👩‍🔧
Optimism
  • Optimism
  • Setup
  • Quick Start
  • Typical Usage
  • Authentication
  • Reference
  • Advanced Usage
Powered by GitBook
On this page
  • Encrypted Session Cookies
  • User-based Authentication
  • Devise-based Authentication

Was this helpful?

Authentication

Practice safe optimism

If you're just trying to bootstrap a proof-of-concept application on your local workstation, you don't technically have to worry about giving ActionCable the ability to distinguish between multiple concurrent users. However, the moment you deploy to a host with more than one person accessing your app, you'll find that you're sharing a session and seeing other people's updates. That isn't what most developers have in mind.

Encrypted Session Cookies

You can use your default Rails encrypted cookie-based sessions to isolate your users into their own sessions. This works great even if your application doesn't have a login system.

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :set_action_cable_identifier

  private

  def set_action_cable_identifier
    cookies.encrypted[:session_id] = session.id.to_s
  end
end
app/channels/application_cable/connection.rb
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :session_id

    def connect
      self.session_id = cookies.encrypted[:session_id]
    end
  end
end

We need to instruct ActionCable to stream updates on a per-session basis:

app/channels/optimism_channel.rb
class OptimismChannel < ApplicationCable::Channel
  def subscribed
    stream_for session_id
  end
end

Finally, we need to give Optimism the ability to broadcast updates to the correct channel subscription. We will override Optimism's default "OptimismChannel" with a lambda that returns the subscription identifier. You might already have other values in your initializer, or it might not yet exist at all:

config/initializers/optimism.rb
Optimism.configure do |config|
  config.channel_proc = ->(context) { OptimismChannel.broadcasting_for(context.session.id) }
end

User-based Authentication

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :set_action_cable_identifier

  private

  def set_action_cable_identifier
    cookies.encrypted[:user_id] = current_user&.id
  end
end
app/channels/application_cable/connection.rb
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      user_id = cookies.encrypted[:user_id]
      return reject_unauthorized_connection if user_id.nil?
      user = User.find_by(id: user_id)
      return reject_unauthorized_connection if user.nil?
      self.current_user = user
    end
  end
end

We need to instruct ActionCable to stream updates on a per-session basis:

app/channels/optimism_channel.rb
class OptimismChannel < ApplicationCable::Channel
  def subscribed
    stream_for current_user
  end
end

Finally, we need to give Optimism the ability to broadcast updates to the correct channel subscription. We will override Optimism's default "OptimismChannel" with a lambda that returns the subscription identifier. You might already have other values in your initializer, or it might not yet exist at all:

config/initializers/optimism.rb
Optimism.configure do |config|
  config.channel_proc = ->(context) { OptimismChannel.broadcasting_for(context.current_user) }
end

Devise-based Authentication

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

    protected

    def find_verified_user
      if current_user = env["warden"].user
        current_user
      else
        reject_unauthorized_connection
      end
    end
  end
end
PreviousTypical UsageNextReference

Last updated 4 years ago

Was this helpful?

Many Rails apps use the current_user convention or more recently, the object to provide a global user context. This gives access to the user scope from almost all parts of your application.

If you're using the versatile authentication library, your configuration is identical to the User-Based Authentication above, except for how ActionCable looks up a user:

Current
Devise