devise_masquerade adds a login-as button to Rails and Devise
Extension for devise, enable login as functionality. Add link to the masquerade_path(resource) and use it.
At a glance
- What is it?
- This Ruby gem lets an administrator sign in as an existing user without asking for their password, using a short-lived token in the URL and a before_action that swaps the session over. It also gives you the way back to your own account, and it makes authorization your job rather than the gem's.
- Who is it for?
- Adopt devise_masquerade when you run a multi user Rails application on Devise and support staff need to reproduce a user's problem by signing in as them, and you are prepared to add the authorization check yourself. Do not adopt it if your application is not on Devise, since the whole extension hangs off the Devise model macro, or if you cannot restrict who may generate a masquerade token, since the gem deliberately leaves that to your own controller.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 37 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Why a login-as button exists at all
The gem describes itself as a utility library for enabling login as button functionality for admin, and the README explains the case in a sentence: if you have a multi user application and sometimes want to test functionality using the login of an existing user without requesting the password, you define a login as button with a url helper and use it.
That is a narrow and completely legitimate need. Support staff are asked to reproduce a bug that only appears for one account, and asking a customer for their password is both poor practice and a security problem. Being able to open the application as that user, see their state, and then get back to your own session solves it.
The implementation choice is what makes this gem interesting. Instead of storing a persistent impersonation flag on the user record, the gem generates a temporary token, puts it in the URL as a query parameter, and swaps the session over when that URL is visited. The README is explicit about the shape of it: `masquerade_path` creates a specific `/masquerade` path with the query params `masquerade`, which carries the key, and `masqueraded_resource_class`, which tells the gem which model to look up and sign in as.
So the mechanism is a capability token in a link, and the security of the whole thing rests on two things: the token expiring, and the endpoint being authorized.
The project is a Ruby gem, MIT licensed, with the tags v2.1.3 from 2023-11-02, v2.1.0 from 2022-12-16 and v2.0.2 from 2022-10-25. The last push was on 2026-09-16, so the repository is being worked on even though the packaged release is from 2023.
Installing it and putting the link in a view
Installation is a Gemfile line and a bundle:
gem 'devise_masquerade' $ bundleThen the view side is one helper:
= link_to "Login As", masquerade_path(user)The resource passed to the helper does not have to be a user. The README says that instead of user you can use your resource name admin, student or another names, which is the point of the class configuration later on: the gem can masquerade as a User while the person doing it is an AdminUser, or the other way round, and the names are yours to choose.
The model needs one line changed, adding the `:masqueradable` parameter to the existing comma separated values in the devise method:
devise :invitable, :confirmable, :database_authenticatable, :registerable, :masqueradableThat macro is what makes the model eligible for being masqueraded as, and it is why this only works with Devise models.
In the controller you then add a filter. The README gives two options:
before_action :masquerade_user!or
before_action :masquerade!The difference is scope. `masquerade_user!` is the specific one, and the README describes the pair as a custom way to sign in by using the masquerade token. `masquerade!` is the generic way, in case you want to support multiple models on masquerade, which is what the class configuration enables.
The interesting subtlety here is that the filter is optional. The README says that if you add it you get the custom sign in path, otherwise you can still use only `masquerade_path` in your view to generate the temporary token and the link to make Login As. So the gem works with the link alone, and the before_action is what lets you control where the user lands after the swap.
There is also a way back, which is the piece that makes the feature usable in a support console. The helpers are `user_masquerade?`, which tells you whether the current user was masqueraded and by whom, and `back_masquerade_path(current_user)`, which produces the link to return to the account that started the masquerade.
Authorization is your job, and the gem gives you the hook
The gem does not decide who may masquerade as whom, and the README is direct about it: it shows you a custom controller so you can add CanCan for authorization, and the point of the section is that you have to write that check.
The CanCan version overrides a protected method in a controller that inherits from the gem's controller:
class Admin::MasqueradesController < Devise::MasqueradesController
def show
super
end
protected
def masquerade_authorize!
authorize(User, :masquerade?) unless params[:action] == 'back'
end
# or you can define:
# def masquerade_authorized?
# <has access to something?> (true/false)
# end
endThere are two ways in. You can implement `masquerade_authorize!`, which is called and is expected to raise if the action is not permitted, or you can define `masquerade_authorized?` and return a boolean. The README leaves the body of the boolean version as a placeholder with a question in it, which tells you that it is entirely your decision what the condition means.
The Pundit version is the same shape:
class Admin::MasqueradesController < Devise::MasqueradesController
protected
def masquerade_authorize!
authorize(User, :masquerade?) unless params[:action] == 'back'
end
endand the view then checks the policy before rendering the link:
<% if policy(@user).masquerade? %>
<%= link_to "Login as", masquerade_path(@user) %>
<% end %>Note the `unless params[:action] == 'back'` guard in both examples. The back path must remain reachable, otherwise the person who started the masquerade cannot return to their own account, which would leave them stuck inside someone else's session. That is a small detail in the example and a real trap in the implementation.
There is a third piece: if you use a custom controller, the Devise routes have to point at it, and the README reminds you not to forget this:
devise_for :users, controllers: { masquerades: "admin/masquerades" }Without that line in `routes.rb`, the authorization code you just wrote is never called, because the gem's own controller is serving the request.
Where the user lands, and how the finder is overridden
Two smaller extension points decide the user experience, and both are one method override.
The first is the redirect after the masquerade starts:
class Admin::MasqueradesController < Devise::MasqueradesController
protected
def after_masquerade_path_for(resource)
"/custom_url"
end
endand the second is the redirect after the masquerade is finished:
class Admin::MasqueradesController < Devise::MasqueradesController
protected
def after_back_masquerade_path_for(resource)
"/custom_url"
end
endBoth take the resource, so a single controller can route different kinds of masqueraded account to different places if you override them with that in mind.
The third extension point is the finder, which is the one that decides how the resource is located from the identifier in the URL:
class Admin::MasqueradesController < Devise::MasqueradesController
protected
def find_masqueradable_resource
masqueraded_resource_class.friendly.find(params[:id])
end
endThe README gives the FriendlyId case as the example, and the point generalises: if your application identifies users by a slug rather than a numeric id, the default lookup by id will not find them, and you override the finder to use whatever your identifier scheme is.
This is worth pausing on, because it is the kind of detail that turns a working feature into a broken one at the worst time. The default finder assumes the primary key, and a Rails application that uses friendly ids, UUIDs or a composite key will silently fail to resolve the target.
So the three overrides, `after_masquerade_path_for`, `after_back_masquerade_path_for` and `find_masqueradable_resource`, are the practical checklist for this gem: where to land, where to land afterwards, and how to find the user.
The configuration knobs and what they control
The README lists the options you can redefine, and they are worth reading as a set because they describe the security properties of the feature.
Devise.masquerade_param = 'masquerade'
Devise.masquerade_expires_in = 10.seconds
Devise.masquerade_key_size = 16 # size of the generate by SecureRandom.urlsafe_base64
Devise.masquerade_bypass_warden_callback = false
Devise.masquerade_routes_back = false # if true, route back to the page the user was on via redirect_back
Devise.masquerading_resource_class = AdminUser
# optional: Devise.masquerading_resource_class_name = 'AdminUser'
# optional, default: masquerading_resource_class.model_name.param_key
Devise.masquerading_resource_name = :admin_user
Devise.masqueraded_resource_class = User
# optional: Devise.masqueraded_resource_class_name = 'User'
# optional, default: masqueraded_resource_class.model_name.param_key
Devise.masqueraded_resource_name = :user
# optional, default: masquerade_storage_method = :session
# values: :session, :cache
Devise.masquerade_storage_method = :sessionThe expiry is the first thing to look at. `masquerade_expires_in` defaults to 10 seconds, which is short enough that a link left in a browser history or a chat message is dead by the time it is followed, and long enough that a support agent can click it. That is a sensible default, and changing it is a security decision rather than a convenience one.
The key size is 16, and the comment says it is the size of the generation by SecureRandom.urlsafe_base64, so the token is a URL-safe random string of that length. The parameter name is configurable, which lets you pick a name that your application does not otherwise use.
`masquerade_bypass_warden_callback` defaults to false, and it controls whether the Warden authentication callbacks are bypassed during the swap. Leaving it false keeps Devise's own callbacks in play, which is what you want if your application has after_sign_in hooks that should also run for a masqueraded session.
`masquerade_routes_back` is false by default, and the comment explains that if true it routes back to the page the user was on via redirect_back. The class names come in pairs, a class and a name, where the name defaults to the class's model name param key, and the masquerading and masqueraded sides are configured separately. So the gem distinguishes the account doing the masquerading from the account being masqueraded, which is what lets an admin sign in as a student while remaining an admin in the audit trail.
The last option, `masquerade_storage_method`, defaults to `:session` and can be `:session` or `:cache`, and it decides where the state of the masquerade is kept.
The demo, the tests and one development gotcha
The repository ships a demo application inside the test directory, and the README gives the commands:
cd spec/dummy
rake db:setup
rails serverThen you check http://localhost:3000/ and log in with [email protected] and the password `password`. That is a standard Rails engine layout, where the dummy application is the harness the specs run against.
The test suite has its own entry point. The Makefile is short and shows the whole structure:
rspec:
bundle exec rspec
.PHONY: rspec
cucumber:
bundle exec cucumber
.PHONY: cucumber
test: setup rspec cucumberSo `make test` depends on `setup`, which prepares the dummy app's test database, and then runs both rspec and cucumber. Running both frameworks is a choice worth noting: rspec for the unit and request specs in `spec/`, and cucumber for the feature specs in `features/`, with a `Guardfile` at the root for the file watcher workflow. The release target is `bundle exec rake release`, which is the standard Bundler gem release task.
The troubleshooting section at the end of the README contains the single most useful piece of advice in the document, and it is about development mode rather than about the feature. If you are in development and masquerade attempts result in a Receiving You are already signed in flash error message, with Filter chain halted as :require_no_authentication rendered or redirected in the logfile, and if `user_masquerade?` always returns false, then the chances are that you need to enable caching:
rails dev:cacheThe README says it is a one-time operation, and that you can re-run it to disable caching in development. This is the kind of bug that costs an afternoon if you have not seen it before, because the symptoms point at the authorization logic rather than at a missing cache. The cause is that Devise's own authentication machinery behaves differently in development without the cache, so the session state that the masquerade relies on is not there.
The project also keeps a `.ruby-version`, a `.rvmrc` and a `.tool-versions` file, so the Ruby version is pinned three ways for as many version managers as people use.
Editorial conclusion
Adopt devise_masquerade when you run a multi user Rails application on Devise and support staff need to reproduce a user's problem by signing in as them, and you are prepared to add the authorization check yourself. Do not adopt it if your application is not on Devise, since the whole extension hangs off the Devise model macro, or if you cannot restrict who may generate a masquerade token, since the gem deliberately leaves that to your own controller. Verify first that you have overridden `masquerade_authorize!` or the `masquerade_authorized?` hook, that the `masquerade_expires_in` window is short enough for your use, that `Devise.masquerade_storage_method` matches whether your app has a cache configured, and that the version you take is v2.1.3, the most recent tag from 2023-11-02, given that the last push was on 2026-09-16.
Frequently asked questions
What does the devise_masquerade gem do?
It is a utility library for enabling a login as button for administrators. You generate a link with the `masquerade_path` helper, which carries a temporary token and the resource class as query parameters, and a before_action in your controller signs you in as that user without their password.
How do I install devise_masquerade and use it?
Add `gem 'devise_masquerade'` to your Gemfile and run bundle. In the model add the `:masqueradable` parameter to your devise declaration, in the view use `link_to "Login As", masquerade_path(user)`, and in the controller add `before_action :masquerade_user!` or the generic `before_action :masquerade!`.
How do I control who is allowed to masquerade?
The gem leaves that to you. Subclass `Devise::MasqueradesController` and implement `masquerade_authorize!`, for example with `authorize(User, :masquerade?) unless params[:action] == 'back'` for CanCan or Pundit, or define `masquerade_authorized?` returning a boolean. Then point the Devise routes at your controller with `devise_for :users, controllers: { masquerades: "admin/masquerades" }`.
What are the main configuration options?
Among them `Devise.masquerade_expires_in`, which defaults to 10 seconds, `Devise.masquerade_key_size`, which defaults to 16 for a SecureRandom.urlsafe_base64 token, `Devise.masquerade_storage_method`, which is `:session` by default and can be `:cache`, and `Devise.masquerade_routes_back`, which if true returns the user to the page they were on via redirect_back.
Why does masquerading fail with an already signed in error in development?
The README's troubleshooting section points at Devise's caching in development mode. If attempts produce a You are already signed in flash error, a require_no_authentication filter chain halt in the log, and a user_masquerade? method that always returns false, the fix is to run `rails dev:cache`, which is a one-time operation.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/oivoodoo-devise-masquerade)Was this useful?