---
title: How To Masquerade As Another User To See How They Use Your App
teaser:
tags: web,rails
author: Dan Croak
published_on: 2011-09-22
---

Recently, I created [thoughtbot Foursquare
lists](https://foursquare.com/thoughtbot) to help out-of-town
[workshops](http://workshops.thoughtbot.com) students find hotels, coffee
shops, and bars.

In the process, I noticed Foursquare has an "act as" feature:

![foursquare masquerade](http://media.tumblr.com/tumblr_lrfyq8ahRS1qz5x9p.png)

It lets you, well, "act as" another user:

![foursquare masquerade](http://media.tumblr.com/tumblr_lrfyp90Oyo1qz5x9p.png)

It caught my eye because I had recently implemented a similar feature for a
client. I named it with slightly more aplomb: "masquerading."

## Ingredients

* an authentication library
* aplomb

## Recipe

Here's what we wanted:

    Given a user exists with email "bobby@example.com" and name "Bobby Tables"
    And an admin with email "admin@example.com"
    When I sign in as "admin@example.com"
    Then I should see "Bobby Tables"
    When I follow "Masquerade" within the "bobby@example.com" row
    And I should see "Now masquerading as Bobby Tables"
    And I should see "Hi Bobby" within the navigation
    When I follow "Stop Masquerading"
    Then I should be on the admin page

The context is that I'm an admin. A user is **on the phone with me right now**
with support questions. I quickly find their account and see the app through
their eyes.

In `app/views/admin/users/index.html.erb`:

    <% @users.each do |user| %>
        ...
        <%= link_to 'Masquerade', new_user_masquerade_path(user) %>
    <% end %>

In `config/routes.rb`:

    resources :users, only: [:edit, :update] do
      resources :masquerades, only: [:new]
    end

Nothing crazy so far.

In `app/controllers/masquerades_controller.rb`:

    class MasqueradesController < ApplicationController
      before_filter :authorize, :authorize_admin

      def new
        session[:admin_id] = current_user.id
        user = User.find(params[:user_id])
        sign_in(user)
        redirect_to home_path, notice: "Now masquerading as #{user.name}"
      end

      def destroy
        user = User.find(session[:admin_id])
        sign_in :user, user
        session[:admin_id] = nil
        redirect_to admin_users_path, notice: "Stopped masquerading"
      end
    end

The masquerading controller actions are restricted to admins by before filters
provided by the authentication library and the developer.

The `create` action switches the user ids and signs in as the user. Put your
mask on because we're masquerading.

When the customer support session is over, we'll want to return to the admin
views. In `app/views/shared/_navigation.html.erb`:

    <% if masquerading? %>
      <%= link_to "Stop Masquerading", "#" %>
    <% end %>

In `application_controller.rb`:

    def masquerading?
      session[:admin_id].present?
    end
    helper_method :masquerading?

We define that in a controller, then expose it as a helper method to the views,
so that we can alter the `authorize_admin` method that is used as a
`before_filter`:

In `application_controller.rb`:

    def authorize_admin
      current_user.admin? || masquerading?
    end

That way, the `MasqueradesController` stays protected, even when you're signed
in as a non-admin user during a masquerade.

We aren't using this technique on our own products right now. One concern is
that on many apps, the customer's view could reveal sensitive data. Airbrake,
for example, would require at minimum asking the person "may I act as your
account?"

Heroku's ZenDesk support form does something similar: "May we access your
application code? Check here to allow us to clone and/or inspect your code for
debugging purposes."

However, I like the idea of providing better support by viewing the app as our
customers do.
