User Impersonation
Admin feature to log in as another user for support and debugging — supports two modes: read-only Impersonation and full-access Masquerade
User Impersonation
User impersonation lets administrators temporarily act as another user — essential for support, debugging, and reproducing user-specific issues without ever asking for credentials.
EduShade ships two distinct modes:
| Mode | What the admin can do | Token view_mode |
|---|---|---|
| Impersonation (read-only) | View the user's dashboard, courses, settings, etc. Write actions are blocked — POST/PUT/DELETE attempts return an error. | impersonation |
| Masquerade (full access) | Act as the user end-to-end: enroll, submit, change settings, post content. Every action is attributed to the user. | masquerade |
Choose Impersonation for safe diagnostic work, and Masquerade only when you need to perform an action as the user (e.g. completing a stuck workflow on their behalf).
Who Can Impersonate?
- Users with the
admin.userspermission, or - Users with the
is_adminflag set totrue
Restrictions:
- You cannot impersonate yourself.
- You can only impersonate users in your same tenant.
- Both modes are audited — every start/stop is published as an audit event.
How to Start Impersonation
- Go to Admin → Users → [select user] → Impersonation tab (
/admin/users/{userID}/edit/impersonation) - You will see two buttons:
- Start Impersonation — read-only mode
- Start Masquerade — full-access mode
- Click the mode you need. Confirm the action.
- You are redirected to the target user's dashboard.
What Happens Behind the Scenes
- Frontend calls
POST /v1/auth/impersonate/{user_id}with{ "view_mode": "impersonation" | "masquerade" }. - Backend issues a new access token for the target user. The JWT contains an extra
impersonated_byclaim with the admin's user ID. - Frontend snapshots your original admin token, refresh token, and user data to
localStorageso they can be restored later. - The view mode is stored in
localStorageunderes_impersonation_view_mode. - An audit event
impersonation_startedis published with: admin ID, target user ID, view_mode, IP, user agent.
While Impersonating
- An
ImpersonationBanneris shown at the top of every page so you cannot forget you are impersonating. - The banner shows: target user name, view mode, and a Stop button.
- In Impersonation mode (read-only): write operations are rejected by the backend; the UI may still render forms but submissions will fail.
- In Masquerade mode: the target user's roles, permissions, and identity apply to every request. Any data you create or modify is attributed to them.
What to Be Careful About
- In Masquerade, profile changes, enrollments, purchases, and submissions are all stored against the user — there is no automatic rollback.
- Avoid Masquerade unless you specifically need to write on the user's behalf.
- For pure investigation, always prefer Impersonation.
How to Stop Impersonation
- Click Stop in the impersonation banner (or the Return to Admin option in the user menu).
- Frontend calls
POST /v1/auth/impersonate/stop. - Your original admin token, refresh token, and user data are restored from
localStorage. - Impersonation
localStoragekeys are cleared. - You are redirected to the page you started from (or the admin dashboard).
- An audit event
impersonation_stoppedis published.
Browser Storage During Impersonation
The frontend uses the following localStorage keys to preserve admin state and track the impersonated session. (Source of truth: src/lib/auth/impersonation/session.ts.)
| Key | Purpose |
|---|---|
es_impersonation_active | Boolean flag — "true" while an impersonation session is active |
es_impersonation_view_mode | Current mode — "impersonation" or "masquerade" |
es_original_admin_token | The admin's original access token (restored on stop) |
es_original_admin_refresh_token | The admin's original refresh token |
es_original_admin_user_data | The admin's user profile snapshot |
es_impersonated_user_id | The target user's ID (decoded from the impersonation JWT) |
es_impersonated_by | Admin user ID (mirror of the JWT impersonated_by claim) |
es_impersonated_user_data | Snapshot of the target user's profile |
es_impersonation_start_page | URL to return to after stopping |
es_restored_admin_user_data | Admin profile data restored after stopping (transient) |
The active access/refresh tokens during impersonation continue to live under the regular
es_auth_access_token/es_auth_refresh_tokenkeys — that's how the rest of the app sees the impersonated session as the "current" session.
Audit Trail
Every impersonation transition is logged for security and compliance:
| Event | Data Logged |
|---|---|
impersonation_started | Admin ID, Target User ID, view_mode, Timestamp, IP, User Agent |
impersonation_stopped | Admin ID, Target User ID, view_mode, Timestamp, IP, User Agent |
These are published to the platform's pub/sub event stream and can be viewed by administrators with audit.view permission.
JWT Claim: impersonated_by
While impersonating (either mode), the JWT issued to the admin contains:
user_id→ the target user's ID (so the rest of the system treats requests as the user)impersonated_by→ the admin's user IDview_mode→"impersonation"or"masquerade"
Backend services use the impersonated_by claim to:
- Allow read-only operations in Impersonation mode and reject writes
- Tag downstream audit/activity events so any side-effects are traceable to the originating admin
Security Considerations
- The original admin session is preserved only in browser storage (not on the server). If
localStorageis cleared mid-session, the admin must log back in manually. - An impersonation token is just a regular access token with extra claims — same expiry, same revocation rules. Logging out the impersonated session also ends the impersonation.
- Always prefer Impersonation (read-only) for diagnostic work to avoid accidental writes on the user's behalf.
Troubleshooting
| Issue | Solution |
|---|---|
| "You don't have permission to impersonate" | You need the admin.users permission or the is_admin flag |
| "Cannot impersonate yourself" | Self-impersonation is not allowed |
| "User not found" | The target user may be soft-deleted, suspended, or in a different tenant |
| Write actions fail unexpectedly | You are in Impersonation (read-only) mode — restart in Masquerade mode if writes are required |
| Can't stop impersonation | Clear all es_impersonation_* and es_original_admin_* keys from localStorage and log in again |
| Lost admin session after impersonation | Browser storage was cleared. Log back in with your admin credentials |
| Actions attributed to the wrong user | In Masquerade, actions are always attributed to the impersonated user — this is by design |

