Aurabase Logo
aurabasedocs
docs›Guides›User impersonation

User Impersonation

Act on behalf of any user for support and debugging without asking for their password. Bounded to 10 minutes, strictly audited in security logs.

5 min read·Level intermediate·Revised on Oct 26, 2026
#
Overview

What is impersonation?

User impersonation allows an administrator or support engineer to generate a short-lived bearer token that acts as a specific user. This enables reproducing customer bugs, checking RLS policy permissions, or troubleshooting data issues without requesting credentials.

Impersonation in Aurabase guarantees three fundamental security principles:

  1. Short lifespan: Impersonation tokens are valid between 1 and 600 seconds (10 minutes maximum, default 300 seconds). They never include a refresh token.
  2. Explicit actor attribution: The issued access token carries the standard RFC 8693 act claim indicating who initiated the session.
  3. Audit-before-issuance: The action is recorded in auth_audit_log with the actor, reason, duration, and target user before the token is ever generated. If the log insertion fails, no token is issued.
#
Token Claims

RFC 8693 act claim structure

An impersonation token is signed with the project's active ES256 key and conforms to the standard user access token format, with an additional act (actor) object:

Decoded JWT payloadjson
{
  "sub": "b2f4c3a1-7788-4e89-a5c2-98e3b1234567",
  "project_id": "ecd48fb4-4fe6-48d0-a8cd-f0641ceb8b1c",
  "role": "authenticated",
  "email": "user@example.com",
  "act": {
    "sub": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  },
  "exp": 1730000300,
  "iat": 1730000000,
  "iss": "https://auth-lab-n7qn5stb.localhost:8080/v1/auth"
}
  • sub: The identity of the user being impersonated. Postgres RLS (auth.uid()) evaluates to this value.
  • act.sub: The identity of the operator who generated the token (e.g. console user ID or service_role).
#
HTTP API

Admin endpoint

Impersonation requires administrator authorization via a service_role key or an operator with the admin role.

Terminalbash
curl -X POST "$AURABASE_URL/v1/auth/admin/users/$TARGET_USER_ID/impersonate" \
  -H "apikey: $AURABASE_SERVICE_ROLE_KEY" \
  -H "Authorization: Bearer $AURABASE_SERVICE_ROLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Investigating ticket #4812",
    "ttl_seconds": 300,
    "allow_privileged": false
  }'

Request body

FieldTypeRequiredDescription
reasonstringOptional*Justification recorded in security logs. Required for privileged target accounts (admin/owner).
ttl_secondsnumberOptionalToken lifetime in seconds (1 to 600, default 300).
allow_privilegedbooleanOptionalMust be set to true if the target user has an admin or owner role.

Response (200 OK)

json
{
  "data": {
    "access_token": "eyJhbGciOiJFUzI1NiIsImtpZCI6...",
    "token_type": "Bearer",
    "expires_in": 300,
    "act": {
      "sub": "service_role"
    },
    "user": {
      "id": "b2f4c3a1-7788-4e89-a5c2-98e3b1234567",
      "email": "user@example.com",
      "role": "authenticated"
    }
  }
}
#
SDK

TypeScript SDK

Use authAdmin.impersonate() with an Aurabase client configured with the service_role key:

admin-debug.tstypescript
import { createClient } from '@aurabase/aurabase-js'

const aura = createClient(process.env.AURABASE_URL!, process.env.AURABASE_SERVICE_ROLE_KEY!)

// Generate an impersonation token for 5 minutes
const { data, error } = await aura.authAdmin.impersonate('b2f4c3a1-7788-4e89-a5c2-98e3b1234567', {
  reason: 'Reproducing issue reported on dashboard',
  ttlSeconds: 300,
})

if (error) {
  console.error('Failed to impersonate:', error.message)
} else {
  console.log('Impersonation token:', data.access_token)
  console.log('Token expires in:', data.expires_in, 'seconds')

  // Create an ephemeral user client to run queries as this user
  const userClient = createClient(process.env.AURABASE_URL!, process.env.AURABASE_ANON_KEY!, {
    accessToken: data.access_token,
  })

  // Queries will now execute under the target user's RLS context
  const { data: posts } = await userClient.from('posts').select('*')
}
#
Security

Privileged accounts and audit logs

Guarding privileged accounts

Target accounts that possess administrative roles (such as role = 'admin', role = 'owner', or app_metadata.roles containing 'admin') represent high-value targets. To prevent accidental privilege elevation:

  1. You must explicitly pass allow_privileged: true.
  2. A non-empty reason string must be provided.
  3. If either check fails, the backend rejects the request with 403 Forbidden.

Security audit log

Every impersonation event is inserted into the tenant's auth_audit_log table:

  • Action: admin_impersonation
  • User ID: ID of the target user
  • Metadata: JSON object containing { "actor": "...", "reason": "...", "ttl_seconds": 300, "privileged": false }

This trail is visible in Studio › Authentication › Audit logs and can be forwarded to SIEM tools via database drains.

Last updated · Oct 26, 2026