Skip to main content

15 Disabling ActionCable for Unauthenticated Users

Episode 128 · July 11, 2016

To only have ActionCable's JS connect for logged in users, we can setup our Javascript to know when a user is authenticated or not, and have our websocket try to connect accordingly.

ActionCable Javascript


Transcripts

Disabling ActionCable for Unauthenticated Users

In this episode, I want to talk about disabling ActionCable for users that aren't logged in. In our notifications episode, we talked about sending notifications over websocket, but only if the user is logged in. There's no sense in the browser constantly attempting to connect to the websocket, only to be rejected because the user isn't logged in.

As you can see in the network tab, there are a bunch of status 101 requests, meaning the protocol is switching but the connection dies immediately. This is explained by checking the Rails logs, and we see that An unauthorized connect attempt was rejected". In connection.rb, we reject the connection if the user is not verified.

The issue here is the JavaScript does not know if a user is logged in. This is typical, since the JavaScript should never have any idea of the session, because the session needs to be encrypted. If the session wasn't encrypted, then users could impersonate other users. So on the JavaScript side, we need to figure out how to determine if a user is logged in.

The easiest way to determine this is to include a meta tag within the HTML head. Below is an example using Devise logic and methods:

<% if user_signed_in? %>
  <%= tag :meta, name: "current-user", data: {id: current_user.id} %>
<% end %>

Here we use a tag helper. With this tag in the head, the JavaScript now has the information it needs to determine whether or not to initiate an ActionCable connection. To verify if the meta tag is working, we log in and check the page source.

<meta name="current-user" data-id="1">

The tag documentation can be found here. Note that this helper is used by some of the more common helpers such as image_tag.

Now we need to update our JavaScript to look for the current user. In notifications.js, we can include a conditional using a jQuery wrapped object to check for a current user and place the rest of our subscription code inside.

if ($("meta[name='current-user']").length > 0) {
  // subscription code ommitted
}

We wrap the subscriptions instead of the ActionCable.createConsusumer() code inside cable.js, because ActionCable is smart enough to not attempt connecting if there are no subscriptions. We can verify this by logging out, and then inspecting the network tab inside the browser's developer tools. We now see that our JavaScript works as no websocket connections are being made. Thanks for watching and reading!

Written by Frank Lam

Discussion


Gravatar
Sz M (2,710 XP) on

Hey Chris,
I tried to integrate the meta tag if else statement into the group chat app in the channels/chatrooms.js and got "cannot read property `send_message` of undefined" error. It was surprising since if I checked the val of the meta length it returned 1. It took some time to realize that you have to wrap this code into a `turbolinks:load` event since when the code gets to that point when send_message is invoked the meta tag length value is still 0.

Gravatar
stan X (1,540 XP) on

in js files:

$(document).on("turbolinks:load", function () {
if ($("meta[name='current-user']").length >0) {

[...]

}
});

in coffee files:

$(document).on 'turbolinks:load', ->
**if $("meta[name='current-user']").length >0

[...]

(the ** only indicate mandatory indentation - they need to be removed and replaced by spaces)


Gravatar
stan X (1,540 XP) on

Hi Chris,
How would you add this to your chatrooms.coffee.erb or a last_read.coffee from the chat application? Not sure how to translate it in coffee script.
Stan

Gravatar
Chris Oliver (169,610 XP) on

This tool can translate to and from Coffeescript: http://js2.coffee/ 👍

Gravatar
stan X (1,540 XP) on

yes. was my immediate attempt but...still no success.

Gravatar
Chris Oliver (169,610 XP) on

What are you having trouble with? The if statements around your code should be mostly the same.

Gravatar
stan X (1,540 XP) on

I added
if $("meta[name='current-user']").length >0
above the
App.chatrooms = App.cable.subscriptions.create "ChatroomsChannel"

but this leads to
SyntaxError: [stdin]:1:1: unexpected if

Gravatar
Chris Oliver (169,610 XP) on

Can you share your whole file?

Gravatar
stan X (1,540 XP) on

For readers of these comments, the issue was with the indentation. Beware of coffeescript on that side! Thks Chris again for your help.


Gravatar
Darion Wood (190 XP) on
Does anyone have a working coffee version of the project files t. I'm unable to get "an unauthorized attempt..." to stop even though I've made the changes. When the user isn't on the chatrooms_controller, it shouldn't be searching for that user. Please, assist me -- I've been working on this thing for a few weeks now.
Gravatar
Darion Wood (190 XP) on
I think its finally working. I'm no longer receiving the message while in other controllers.

Login or create an account to join the conversation.