0014. Impersonation: explicit, short, actor-preserving support grants#
Status: Accepted
Context#
Support staff need to see what a customer sees without learning or changing the customer's credentials, and without disguising who acted (§16.1). IMP-001..IMP-024 list non-negotiable controls.
Decision#
- Disabled by default at three levels: deployment configuration
(
impersonation.enabled: false), realm policy (impersonation.enabled), and at least one API resource must opt in (impersonation_enabledwithverification_mode: strict_onlineand a recordedcontract_version). Otherwise requests fail withfeature_disabled. - Flow:
POST /impersonation-requests(admin audience, MFA withinsecurity.admin_mfa_max_age, permissionsupport.impersonation.startin the target organization, reason of at leastimpersonation.min_reason_lengthcharacters, ticket when required) → optional independent approval (second_operator,organization_ownerorcustomer; writes always need one) →POST /impersonation-requests/{id}/issueby the same operator, which re-checks everything and commits grant, audit and outbox before returning an opaquepa_it_token (0010). - Targets excluded: self, protected users, holders of privileged realm roles,
organization administrators (
org.roles.assign,org.ownership.transferororg.members.write), non-members, suspended users, opted-out customers or organizations. - Scope: the resource's
impersonation_policy.allowed_scopes(andwrite_scopesonly inallowlisted_writemode). The operator's own permissions are never added. - Lifetime: at most 5 minutes (
impersonation.max_ttl, realmimpersonation.max_ttl_seconds, and the realm token-lifetime limitstokens.impersonation_access_token_ttl_secondsandtokens.access_token_ttl_seconds; the smallest applies); no refresh; exchange refused. - Handoff:
POST /impersonation-grants/{id}/handoffscreates a single-use code (pa_hc_, at most 30 s) bound to a confidential destination client, redeemed by that client's backend atPOST /impersonation-handoffs/redeem. - Revocation: by the actor, the target (
/me/impersonation-grants/{id}/revokeor opting out), or a holder ofsupport.impersonation.revoke. Introspection also stops succeeding when the actor or target is no longer active, the target's membership or the organization is no longer active, the actor's session ends, or the actor losessupport.impersonation.start. - Downstream contract: resources use
verifier.SupportGuard, which introspects every request, requires the actor claim, denies protected operations, allows writes only for allowlisted operations inallowlisted_writemode, and writes an audit record before access. - One classification rule (IMP-011, IMP-013; 2026-10 update): the SDKs'
SupportGuardand the decision API classify operations the same way, pinned by the shared tabletests/fixtures/sdk-contracts/support-operations/cases.jsonthat the SDKs and the server's tests run. An operation is protected when the segments of a protected entry occur as a contiguous run in its name (split on.,:and/, simple plurals tolerated), and it is a write when any segment is a write verb, whatever its suffix. The decision API allows anallowlisted_writesupport token a write only when the resource lists the action inimpersonation_policy.write_actions(SUPPORT_ACCESS_WRITE_NOT_ALLOWLISTEDotherwise), the server-side counterpart of the guard'sWriteOperations(resource-servers.md).
Alternatives considered#
- Logging in as the customer (shared session or password reset): violates IMP-006 and IMP-012.
- JWT support tokens: cannot meet strict-online revocation (IMP-010).
Consequences#
Detailed threats and residual gaps are in
docs/threat-models/impersonation.md. Notable
gaps: the IdP does not intersect the support scope with the target's current
permissions at issuance (resources must call the decision API or check their own
data), and a resource that does not use SupportGuard (or an equivalent) is not
prevented from accepting the token beyond what introspection reports. At
acceptance, turning the feature off did not end live grants and denied requests
were not persisted; since the 2026-10 update every introspection re-checks the
deployment, realm, resource, organization and customer switches, and denials are
audited after the failed transaction rolls back.
Migration implications#
The introspection fields act, support_mode, impersonation_grant_id and
token_kind: impersonation_access are part of the resource contract.
impersonation_policy.write_actions is a new, optional resource member (also
in the configuration document); a resource registered before it allows no
support writes through the decision API until it is set. An action with a
write-verb segment is a write even when it ends in a read suffix (for example
orders.cancel.view).
Related requirement IDs#
IMP-001..IMP-024, MFA-003, INT-010, TEST-040..TEST-047, TEST-071, §16