Skip to main content

Start Support Access Session

API Endpoint: POST /admin/support-access/requests Priority: P1 User Story: As an admin, I want to start a support access (act-as) session to troubleshoot.

Overview

Initiate a time-limited impersonation session allowing support staff to access the system as a target user with a delegated JWT token for troubleshooting purposes.

Scenarios

Scenario 1: Create support session with default TTL

Given:

  • Support staff is authenticated with scope support:access:create
  • Target user user_12345 exists in law firm firm_abc
  • No active support session exists for this user

When:

  • Support staff POSTs to /admin/support-access/requests with payload:
    {
    "lawFirmId": "firm_abc",
    "targetUserId": "user_12345",
    "reason": "User cannot upload documents - investigating permissions"
    }

Then:

  • Response status is 201 Created

  • Response body contains:

    FieldValueDescription
    session.idGenerated UUIDUnique session identifier
    session.lawFirmId"firm_abc"Law firm context
    session.targetUserId"user_12345"User being impersonated
    session.actorAdminUserIdSupport staff IDWho initiated session
    session.reason"User cannot upload..."Troubleshooting reason
    session.status"active"Session state
    session.startedAtCurrent timestampWhen session began
    session.expiresAtNow + 30 minutesSession expiration
    session.ttlMinutes30Time to live
    delegatedTokenJWT stringToken for impersonation
    uiSwitchUrlURL stringFrontend redirect URL
  • Delegated JWT token contains claims:

    ClaimValuePurpose
    sub"user_12345"Target user ID (primary subject)
    act.actorUserIdSupport staff IDActor performing actions
    ctx.lawFirmId"firm_abc"Firm context
    act_astrueIndicates impersonation mode
    expNow + 30 minToken expiration timestamp
    iatNowToken issued at
    scopeTarget user's scopesFull permissions (if not narrowed)

Scenario 2: Create session with custom TTL

Given:

  • Support staff is authenticated with scope support:access:create
  • Target user exists

When:

  • Support staff POSTs with custom TTL:
    {
    "lawFirmId": "firm_abc",
    "targetUserId": "user_12345",
    "reason": "Quick permission check",
    "ttlMinutes": 15
    }

Then:

  • Response status is 201 Created
  • Session expiresAt is 15 minutes from startedAt
  • Delegated token exp claim matches session expiry

Scenario 3: Create session with narrowed scopes

Given:

  • Support staff is authenticated with scope support:access:create
  • Target user has scopes: ["cases:read", "cases:write", "documents:read", "documents:write"]

When:

  • Support staff POSTs with scope limitation:
    {
    "lawFirmId": "firm_abc",
    "targetUserId": "user_12345",
    "reason": "Check document read permissions only",
    "scopes": ["cases:read", "documents:read"]
    }

Then:

  • Response status is 201 Created
  • Delegated token scope claim is ["cases:read", "documents:read"]
  • Support staff cannot perform write operations
  • Session is more restricted than target user's full permissions

Scenario 4: Invalid TTL rejection

Given:

  • Support staff is authenticated with scope support:access:create

When:

  • Support staff POSTs with TTL below minimum:
    {
    "lawFirmId": "firm_abc",
    "targetUserId": "user_12345",
    "reason": "Test",
    "ttlMinutes": 3
    }

Then:

  • Response status is 400 Bad Request
  • Response body contains:
    {
    "error": "VALIDATION_ERROR",
    "message": "ttlMinutes must be between 5 and 120",
    "field": "ttlMinutes",
    "received": 3,
    "constraints": {"min": 5, "max": 120}
    }

Scenario 5: Target user not found

Given:

  • Support staff is authenticated with scope support:access:create
  • No user with ID user_nonexistent

When:

  • Support staff POSTs with nonexistent user:
    {
    "lawFirmId": "firm_abc",
    "targetUserId": "user_nonexistent",
    "reason": "Test"
    }

Then:

  • Response status is 404 Not Found
  • Response body contains:
    {
    "error": "USER_NOT_FOUND",
    "message": "User 'user_nonexistent' not found in law firm 'firm_abc'"
    }

Scenario 6: Missing required reason

Given:

  • Support staff is authenticated with scope support:access:create

When:

  • Support staff POSTs without reason:
    {
    "lawFirmId": "firm_abc",
    "targetUserId": "user_12345"
    }

Then:

  • Response status is 400 Bad Request
  • Response contains validation error for missing reason field

Request Specification

Request Body

FieldTypeRequiredConstraintsDefaultDescription
lawFirmIdstringYesMust exist-Target law firm
targetUserIdstringYesMust exist in firm-User to impersonate
reasonstringYesMin 5 chars, max 500-Justification for access
ttlMinutesintegerNo5-12030Session duration in minutes
scopesstring[]NoValid scope stringsTarget user's scopesScope limitation

Validation Rules

RuleDescription
Required fieldslawFirmId, targetUserId, reason must be provided
TTL range5 ≤ ttlMinutes ≤ 120
Reason length5 ≤ length(reason) ≤ 500
Scopes subsetIf provided, scopes must be subset of target user's scopes
Firm membershipTarget user must be member of specified law firm

Response Specification

Success Response (201 Created)

{
"session": {
"id": "session_abc123",
"lawFirmId": "firm_abc",
"targetUserId": "user_12345",
"actorAdminUserId": "admin_789",
"reason": "User cannot upload documents - investigating permissions",
"status": "active",
"startedAt": "2025-10-18T14:30:00Z",
"expiresAt": "2025-10-18T15:00:00Z",
"ttlMinutes": 30,
"scopesNarrowed": false,
"scopes": null
},
"delegatedToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"uiSwitchUrl": "https://app.example.com/switch-user?token=..."
}

Delegated Token Claims

{
"sub": "user_12345",
"iss": "https://api.example.com",
"aud": "law-firm-app",
"exp": 1729264200,
"iat": 1729262400,
"act": {
"actorUserId": "admin_789"
},
"ctx": {
"lawFirmId": "firm_abc"
},
"act_as": true,
"scope": "cases:read cases:write documents:read documents:write"
}

Error Responses

StatusError CodeDescription
400VALIDATION_ERRORInvalid input (TTL, reason, scopes)
401UNAUTHORIZEDMissing or invalid auth token
403FORBIDDENMissing support:access:create scope
404LAW_FIRM_NOT_FOUNDLaw firm does not exist
404USER_NOT_FOUNDTarget user not found in firm
409ACTIVE_SESSION_EXISTSUser already has active support session

Requirements Mapping

  • FR-001: Accept POST with lawFirmId, targetUserId, reason, ttlMinutes, scopes
  • FR-002: Validate all required fields present
  • FR-003: Validate TTL between 5-120 minutes
  • FR-004: Default TTL to 30 minutes
  • FR-005: Validate reason minimum 5 characters
  • FR-006: Create support session record
  • FR-007: Generate delegated JWT token
  • FR-008: Include sub claim (target user)
  • FR-009: Include act claim (actor metadata)
  • FR-010: Include ctx claim (firm context)
  • FR-011: Include act_as flag
  • FR-012: Set exp claim matching session expiry
  • FR-013: Limit scopes when requested
  • FR-014: Return session details and token
  • FR-015: Generate UI switch URL for frontend
  • FR-016: Prevent multiple active sessions per user
  • FR-017: Audit log session creation