Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot call handle_open to handle JWT expiration #174

Closed
fs-ses-junya-wako opened this issue Jul 14, 2022 · 2 comments
Closed

Cannot call handle_open to handle JWT expiration #174

fs-ses-junya-wako opened this issue Jul 14, 2022 · 2 comments

Comments

@fs-ses-junya-wako
Copy link

fs-ses-junya-wako commented Jul 14, 2022

Tell us about your environment

Ruby version:
2.7.2

Rails version:
6.0.3

anycable gem version:
1.2.3

anycable-rails gem version:
1.3.4

grpc gem version:
1.47.0

anycable-go version:
1.2.1

What did you do?

I try to refresh my authentication tokens (JWT) by using following tokenRefresher:

anycable/anycable-client: AnyCable / Action Cable JavaScript client for web, Node.js & React Native

And try to respond token_expired message from server side in case of auth error:

module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = find_verified_user
    end

    private

    def handle_open
      super
    rescue VerificationFailed
      logger.error 'An expired JWT token was rejected'
      close(reason: 'token_expired', reconnect: false) if websocket.alive?
    end
    ...
end

anycable/anycable-rails-jwt: JWT identification helpers for AnyCable

What did you expect to happen?

I expect handle_open method is called when the websocket connection establishes.
and to catch VerificationFailed and respond token_expired message if token auth fails.

What actually happened?

But handle_open method was not called.

I changed my code the following, it is OK to catch VerificationFailed and respond token_expired message.
(but if I use websocket.alive? in connect , undefined method alive?' for #AnyCable::Socket:0x00007fe00fe108b0` occurs.)

    def connect
      self.current_user = find_verified_user
    rescue VerificationFailed
      logger.error 'An expired JWT token was rejected'
      close(reason: 'token_expired', reconnect: false)
    end
@palkan
Copy link
Member

palkan commented Jul 14, 2022

I expect handle_open method is called when the websocket connection establishes.

The #handle_open is only called when you're connecting via Action Cable server.

If you're connecting via anycable-go, you should enable JWT identification (e.g., anycable-go --jwt_id_key=<some key>). In this case no RPC is performed at all, anycable-go authenticate the connection on its end.

If you're not using AnyCable JWT feature, and using a custom token-based auth instead, you should use the #connect method, right. The only change required is to add reject_unauthorized_connection after the #close call:

def connect
  self.current_user = find_verified_user
rescue VerificationFailed
  logger.error 'An expired JWT token was rejected'
  close(reason: 'token_expired', reconnect: false) if anycabled? || websocket.alive?
  reject_unauthorized_connection
end

Note that I added if anycabled? || websocket.alive?. This is to make this code backward-compatible with Action Cable server in case you use it in other environments (and don't want it to raise exception when tryin to close non-alive socket).

@palkan palkan added the awaiting response Awaiting response from the reporter label Jul 14, 2022
@fs-ses-junya-wako
Copy link
Author

If you're connecting via anycable-go, you should enable JWT identification

Oh, I didn't know that.

If you're not using AnyCable JWT feature, and using a custom token-based auth instead, you should use the #connect method, right.

In our case, we're using a custom token-based auth.
It worked perfectly with your code!

I could understand very clearly.
Thanks @palkan !

@palkan palkan removed the awaiting response Awaiting response from the reporter label Jul 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants