How We Impersonate Users To Fix Problems Faster

Building tools to debug user issues usually gets less focus than product features in most organizations. Product features are exciting things you can sell. Debugging tools are hidden things no one ever hears about.

But a powerful debugging tool has an impact. A startup is a multi-year long process, and if one thing is sure, you will always get support issues. A great tool can make tracking down user issues a quick and pleasant process, rather than a drugery you will dread after just a few weeks or months. Hating the support process leads to long delays, bad attitudes and a poor customer experience. If you can find a way to make resolving issues not a torment, you’ve set your team up for success.

At Eager, one of the most powerful things we did to facilitate user support was give ourselves the ability to “impersonate” our users.

User Search UI

When we get a support ticket, we can temporarily assume the identity of the user in question, to see the site through their eyes.

Impersonated Sites

The impersonation process only requires a minor tweak to our app’s flow. When we choose to impersonate a user, a local storage key is set:

localStorage.IMPERSONATE_USER_ID = "b23jfFd9aA1"

When it comes time to load the user record of the currently active user, we take that setting into account:

if localStorage.IMPERSONATE_USER_ID
  user = User.get(id: localStorage.IMPERSONATE_USER_ID)
else
  user = User.current()

As all of the app, site, and other assorted information we load feeds from that user, no other changes are required.

Sudo

It goes without saying that we don’t allow any user to impersonate. Like many other organizations, we have a handful of “admin” users who have special priviledges enforced at the API level, including the ability to load other user’s information.

One thing we learned through experiences on past projects however is the danger of having your day-to-day user account have superpowers most users don’t have. It’s easy to miss an authentication bug which would stimy your users, but your special account can sail through.

With Eager, we decided to adopt a concept common to unix-based operating systems, sudo[1]. Admin users see a special button in the corner of the app which sets another local storage-based flag:

Sudo Button

When sudo is set, API requests include a special header which informs the API that the user would like to use their admin permissions with this request. In Angular, that is as simple as:

.factory 'SudoRequestInterceptor', (Sudo) ->
  {
    request: (config) ->
      if Sudo.isEnabled()
        config.headers['X-As-Admin'] = 'true'

      config
  }

.config ($httpProvider) ->
  $httpProvider.interceptors.push('SudoRequestInterceptor')

The API, in turn, validates that the user is truely an admin, and then grants them their elevated permissions.

Logging

One important note about this method is we are never “logging in” as our users, even when impersonating a user, you are using your actual credentials. This allows us to maintain a valid audit trail which shows who truely made which changes. For more information about that, see our post on Postgres Audit Logging.

Integrations

The impersonation process got even easier when we integrated it with our support tool. We use Groove, but many different tools allow you to add a bit of your user data to their interface:

Groove Screenshot

Another opportunity afforded by an integration with your support tool is the ability to only grant impersonate priviledges in limited situations. For example, you could allow a support rep to impersonate a user only while they have an open ticket for that user.

Notes
  1. ^ The unix sudo tool allows you to impersonate any user, making it an analog for this whole post. In this context though, we’re only refering to it’s most common usage, to impersonate the root user.

Like this post? Share it with your followers.

Sign up to get our next post delivered to your inbox.

Follow us to get our latest updates.