Close
Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

LABS
Fast user switching with Devise

Ever wondered how to login as another user within Devise?

Recently we had a feature request that would provide Admins with the ability
to sign is as another user. You could imagine live demonstrations or even production
support calls where you would like to be signed in as another user, yet not
have to ask for or decrypt their current password. After stewing for a bit, we found a
pretty nice solution with Devise.

Here’s the Cucumber feature…


  Feature: Sign in as another user
    As an admin
    I want to sign in as another user

    Scenario: Admin can sign in as another user
      Given I am logged in as an admin user
      And a user: "bob" exists with email: "bob@example.com", password: "password", ...
      When I go to the admin users page
      And I follow the "Sign in as" link for user: "bob"
      Then I should see "Welcome Bob"

The trick was to store the admin info within the rack session.

request.env[‘rack.session’][‘devise.remember_admin_user_id’]

We decided on using a Rails 3 concern to keep our actual strategy clean.


require 'devise/strategies/base'

module SignInAs
  module Concerns
    module RememberAdmin
      extend ActiveSupport::Concern

      private

      def remember_admin_id
        request.env['rack.session']['devise.remember_admin_user_id']
      end

      def remember_admin_id=(id)
        request.env['rack.session']['devise.remember_admin_user_id'] = id
      end

      def remember_admin_id?
        request.env['rack.session'] && request.env['rack.session']['devise.remember_admin_user_id'].present?
      end

      def clear_remembered_admin_id
        request.env['rack.session']['devise.remember_admin_user_id'] = nil
      end
    end
  end
end

The above really makes writing the Devise strategy fairly easy.


require 'devise/strategies/base'

module SignInAs
  module Devise
    module Strategies
      class FromAdmin < ::Devise::Strategies::Base
        include SignInAs::Concerns::RememberAdmin

        def valid?
          remember_admin_id?
        end

        def authenticate!
          resource = User.find(remember_admin_id)
          if resource
            clear_remembered_admin_id
            success!(resource)
          else
            pass
          end
        end
      end
    end
  end
end

Warden::Strategies.add(:sign_in_as, SignInAs::Devise::Strategies::FromAdmin)

Then we just wire in our new strategy. Last line above.

Lastly, here’s our sign-in-as controller which sets the Devise session variable.


class SignInAsController < ApplicationController
  include SignInAs::Concerns::RememberAdmin

  layout 'admin/application'

  def create
    if can?(:manage, :users)
      self.remember_admin_id = current_user.id
      sign_in :user, User.find(params[:user_id])
    end

    redirect_to '/admin'
  end

end

That’s it, pretty neat and might make for a nice Gem or Devise addition.

Comments
  1. Mike Perham says:

    Please note that blog posts which are 100% gist show up as blank entries in the RSS feed.

  2. Jack dempsey says:

    Nice post Mike. Based on the title, I thought you might have stumbled upon a middleware I threw together recently: http://github.com/jackdempsey/spy

    There’s an example app up there at spy_example as well. It looks like your code is more structurally laid out–perhaps spy might spur some other creative thoughts along the lines of gemifying it up and including the middleware switcher.

    Anyway, good stuff! Thx for the post.

  3. Mike Barinek says:

    very cool! also, I’m no longer using Gists and have updated the existing posts…

  4. dennis says:

    I am following your tutorial above, but am confused on where to place the individual files you mention above… can you provide a little input as to where those files should go?

  5. Anthony Karapetrides says:

    I cannot get this to work! Can somebody help out?
    I keep getting “Uninitialized constant SignInAs”

    Thank you!

  6. Murali says:

    but am confused on where to place the individual files you mention above… can you provide a little input as to where those files should go?

Post a Comment

Your Information (Name required. Email address will not be displayed with comment.)

* Copy This Password *

* Type Or Paste Password Here *