9

I am using devise for authentication, but when I implemented your method I got "An unauthorized connection attempt was rejected"

After hours of searching I found out that:

cookies.signed['user.id']

returns nil. In the following code block.

def find_verified_user
  if verified_user = User.find_by(id: cookies.signed['user.id'])
    verified_user
  else
    reject_unauthorized_connection
  end
end

I checked and there is definitely a cookie but it does not contain the cookie data set by Devise.

To check if the 'user.id' actually is set I raise it in the view. This, as excepted, return the user id

Signed in as @#{cookies.signed[:username]}.
- raise(cookies.signed['user.id'].inspect)
%br/
%br/
#messages
%br/
%br/
= form_for :message, url: messages_path, remote: true, id: 'messages-form' do |f|
 = f.label :body, 'Enter a message:'
 %br/
 = f.text_field :body
 %br/
 = f.submit 'Send message'

My question/issue:

It seems like the cookie is not available at the actioncable server.
Is there a way to share the cookie set by Devise with the cable server?

https://github.com/stsc3000/actioncable-chat.git

Bas de Ruiter
  • 101
  • 1
  • 7
  • Its the example I used to create the actioncable – Bas de Ruiter Dec 24 '15 at 14:30
  • Might want to look into this: http://www.rubytutorial.io/actioncable-devise-authentication/ – Kkulikovskis Dec 27 '15 at 10:33
  • @Kkulikovskis thanks for the reply! But I already tried that. I am not sure why this isn't working for me. As mentioned, it seems the cookie is not available on the actioncable server. Whereas it is available in the browser of the application. – Bas de Ruiter Jan 04 '16 at 09:32

4 Answers4

5

Check the client-side JavaScript file that connects to your Action Cable server. Some tutorials have you put that in 'app/assets/javascripts/application_cable.coffee' and others in 'app/assets/javascripts/channels/index.coffee' but it looks like this:

#= require cable

@App = {}
App.cable = Cable.createConsumer("ws://cable.example.com:28080")

You need the WebSocket address to point to your Cable server and that address needs to share a cookie namespace with the rest of your app. Most likely yours is pointing at the wrong place, so for example if you're working on this locally you would need to change:

App.cable = Cable.createConsumer("ws://cable.example.com:28080")

to

App.cable = Cable.createConsumer("ws://localhost:28080")

assuming of course that your Cable server is running on port 28080 (specified in the bin/cable executable). Also make sure to clear your browser cache so the updated file is the one being used by the browser.

Pwnrar
  • 1,307
  • 13
  • 13
3

Not sure if you got it running by now, but I had the same issue on Rails 5.0.0.beta3. I did not change to the following line:

App.cable = Cable.createConsumer("ws://localhost:3000")

I kept it as it was before

 @App ||= {}
 App.cable = ActionCable.createConsumer()

But what I did change had to do with the Cookies. No matter what. The cookie for my user_id would not display. So I made a work around. I got the cookie to save the username instead, then I was finally able to see it in the find_verified_user function call.

After the user logs in(Sessions#create), I call a helper function:

sessions_helper.rb
 def set_cookie(user)
    the_username = user.username.to_s
    cookies.permanent.signed[:username] = the_username
  end

The new find_verified_user

  def find_verified_user
    if current_user = User.find_by_username(cookies.signed[:username])
      current_user
    else
      reject_unauthorized_connection
    end
  end

This may or may not be the best solution, but after hours of confusion and frustration this worked for my situation. I hope this can help someone

1

You need to configure in config/initializers/session_store.rb

# using cookie store
if Rails.env.production?
#  to share across subdomains
    Rails.application.config.session_store :cookie_store, 
                      key: '_app_name_session', domain: ".example.com"
else
# to share with any domain
    Rails.application.config.session_store :cookie_store, 
                      key: '_app_name_session', domain: :all, tld_length: 2
end

#for redis store
elsif Rails.env.production?
#  to share across subdomains
    Rails.application.config.session_store :redis_store, {
       servers: [
        { host: YourRedisHost, port: YourRedisPort},
      ],
      key: '_app_name_session',
      expire_after: 1.day,
      domain: '.example.com'
    }

else
# to share with any domain
    Rails.application.config.session_store :redis_store, {
       servers: [
        { host: YourRedisHost, port: YourRedisPort},
      ],
      key: '_app_name_session',
      expire_after: 1.day,
      domain: :all, 
      tld_length: 2
    }
end 
Marcelo Austria
  • 861
  • 8
  • 16
0

the problem I found is: I have 2 different users logged in. One is logged in at 127.0.0.1, and the other is logged in at localhost. so when I access my website using 127.0.0.1:3000, but my cable is configured to run on localhost like this:

  config.action_cable.url = "ws://localhost:3000/cable"

in config/environments/development.rb

the user logged in at 127.0.0.1 makes cable request to "ws://localhost:3000/cable" (as per configuration), but this way the cookie saved for localhost is sent, even though I am making the request from 127.0.0.1, which is different user(or no user at all).

So the bottom root is actually what Pwnrar points above, cable address configuration and the way you access your website.

So to solve the problem, always access your website using the server address configured for your cable, otherwise cookies get mixed in.

Jeni
  • 1,088
  • 12
  • 30