How to get current_user in ActionCable rails-5-api app?

Why am I unable to get current_user inside my channel or how can I get current_user ?

What am i using?

  • Rails 5.0.1 --api (I don't have any kind of NOR using coffee)
  • I am using an adaptive application to test this (works fine WITHOUT authorization)
  • I DO NOT use devise for auth (instead I use JWT using Knock , so there are no cookies)

Trying to get current_user inside my ActionCable channel as described in rubydoc.info

The code looks like

 class MessageChannel < ApplicationCable::Channel identified_by :current_user def subscribed stream_from 'message_' + find_current_user_privileges end def unsubscribed # Any cleanup needed when channel is unsubscribed end protected def find_current_user_privileges if current_user.has_role? :admin 'admin' else 'user_' + current_user.id end end end 

And by running it, I get this error:

 [NoMethodError - undefined method `identified_by' for MessageChannel:Class] 

And if I remove identified_by :current_user , I get

 [NameError - undefined local variable or method `current_user' for #<MessageChannel:0x7ace398>] 
+12
authentication ruby-on-rails actioncable
source share
4 answers

If you see the provided document, you will find that identified_by not a method for the Channel instance. This is the method for Actioncable::Connection . From the Rails tutorial for Actioncable, this looks like the Connection class:

 #app/channels/application_cable/connection.rb module ApplicationCable class Connection < ActionCable::Connection::Base identified_by :current_user def connect self.current_user = find_verified_user end private def find_verified_user if current_user = User.find_by(id: cookies.signed[:user_id]) current_user else reject_unauthorized_connection end end end end 

As you can see, current_user is not available here. Instead, you need to create current_user here in the connection.

The websocket server does not have a session, but it can read the same cookies as the main application. Therefore, I think you need to save the cookie after authentication.

+4
source share

Thanks @Sajan for kicking me the right way ...

I created an action-cable-react-jwt repo that exactly does exactly what I asked in the question: Rails, React- Native and JWT .

Since the websocket request mysteriously did not allow sending custom headers, I just did a dirty hack for JWT authentication (adding JWT to an existing header: D)

0
source share

if you use designed gems in rails, please replace this function:

 def find_verified_user # this checks whether a user is authenticated with devise if verified_user = env['warden'].user verified_user else reject_unauthorized_connection end end 

I hope this helps you.

+2
source share

Well, in theory

  • You have access to cookies in the ActiveCable::Connection class.
  • You can set and receive cookies.signed and cookies.encrypted
  • Both the application and the ActionCable use the same configuration, so they use the same "secret_key_base"

So, if you know the name of your session cookie (somehow obvious, let it be called " _session "), you can simply get the data in it:

 cookies.encrypted['_session'] 

So you should be able to do something like:

 user_id = cookies.encrypted['_session']['user_id'] 

It depends on whether you use the cookie store for the session and the exact authentication approach, but in any case the necessary data should be there.

I found this approach more convenient since the session is already managed by the authentication solution you are using, and you probably don't need to worry about things like cookie expiration and duplication of authentication logic.

Here is a more complete example:

 module ApplicationCable class Connection < ActionCable::Connection::Base identified_by :current_user def connect session = cookies.encrypted['_session'] user_id = session['user_id'] if session.present? self.current_user = (user_id.present? && User.find_by(id: user_id)) reject_unauthorized_connection unless current_user end end end 
0
source share

All Articles