Identity and session security
Identity replacement changes the provider identity used to sign in while preserving the stable ProAuthUser and outward OpenID Connect subject. Scoped revocation invalidates existing authentication state at the UserStore-user, tenant, or client level.
Why identity replacement is a security workflow
Replacing a provider identity is not ordinary profile editing. A naive update can attach an attacker's external identity to a victim, select the wrong identity from a collection, or leave tokens issued through the former identity active.
ProAuth therefore keeps exactly one active sign-in identity per ProAuthUser, requires proof of both the current and replacement identities, supports independent approval, and performs durable cleanup after the atomic identity switch.
Identity lifecycle
Provider identities use these lifecycle values:
| Status | Meaning |
|---|---|
Legacy | Identity created before explicit lifecycle data was introduced. Migration selects and validates the active candidate. |
Staged | Replacement identity exists but cannot authenticate as the user. |
Active | The only identity permitted to represent the ProAuth user during sign-in. |
Retired | Historical identity retained for audit but no longer accepted. |
Blocked | Identity is explicitly prohibited from authenticating. |
Sign-in must prove the active identity; the presence of another linked identity does not authorize its use.
Replacement workflow
Only one nonterminal replacement operation may exist for a user. A database uniqueness guard enforces this across all nodes.
Request a replacement
POST /api/management/v2/identity-replacements
Content-Type: application/json{
"proAuthUserId": "<user-id>",
"replacementIdpInstanceId": "<idp-instance-id>",
"replacementUniqueUserId": "<provider-unique-id>",
"replacementIssuer": "https://issuer.example.com",
"replacementSubject": "<provider-subject>",
"isUserStoreIdentity": false,
"reason": "Service desk case INC-12345",
"policyFingerprint": "<approved-policy-fingerprint>",
"requiredApprovals": 1,
"lifetimeMinutes": 60
}| Field | Valid values and effect |
|---|---|
ProAuthUserId | Stable subject whose active identity will change. |
ReplacementIdpInstanceId | IDP instance that must prove the replacement identity. |
ReplacementUniqueUserId | Provider-domain unique ID, maximum 100 characters. |
ReplacementIssuer | Exact expected issuer, maximum 1000 characters. |
ReplacementSubject | Exact expected subject, maximum 100 characters. |
IsUserStoreIdentity | Identifies a UserStore-backed replacement. It does not waive proof. |
Reason | Required operational reason or case reference, 1–1000 characters. |
PolicyFingerprint | Required policy provenance, 1–128 characters. |
RequiredApprovals | 0–5; default 1. Use at least one for administrator-initiated replacement. |
LifetimeMinutes | 5–43200; default 60. |
The caller needs ProAuthUser.ReplaceIdentity. Approval needs ProAuthUser.ApproveIdentityReplacement.
Prove both identities
The affected user opens Account Management > Profile and starts proof-only authentication for the current identity and then the replacement identity. Each POST is protected by anti-forgery validation.
Each central ceremony is bound to:
- the
IdentityReplacementpurpose; - exact replacement operation and identity;
- authenticated Account Management user;
- subscription and tenant;
- Account Management client application;
- selected IDP instance;
- authorization-request fingerprint, expiry, and one-time consumption state.
The callback records the proof but does not issue an ordinary application or ProAuth SSO session. An ordinary login ceremony cannot be reused as replacement proof.
Approve, execute, or cancel
GET /api/management/v2/identity-replacements?proAuthUserId=<user-id>&take=100
GET /api/management/v2/identity-replacements/{id}
POST /api/management/v2/identity-replacements/{id}/approvals
POST /api/management/v2/identity-replacements/{id}/execute
POST /api/management/v2/identity-replacements/{id}/cancelThe requesting actor cannot count as an independent approver. Execute succeeds only after both proofs and the required approvals are present and unexpired.
Execution atomically:
- retires the former active identity;
- activates the staged replacement;
- updates the user's explicit active identity reference;
- preserves roles, consents, assignments, and outward subject;
- advances security state and starts durable token cleanup.
The built-in job scheduler checks for due cleanup retries and expired replacement operations every 30 seconds. The operation reports RevocationCompletedOn, retry count, and a privacy-safe error state so operators can distinguish a completed identity switch from pending cleanup.
Irreversible boundary
After execution, do not reactivate the retired row manually. To reverse the business decision, create a new replacement operation and prove both identities again.
Scoped revocation
ProAuth combines eager token cleanup with a durable reauthentication cutoff. The cutoff prevents an older browser session or token-store race from creating fresh access after revocation.
| Scope | Effect | Typical use |
|---|---|---|
| UserStore user | Advances or validates the UserStore authentication-security epoch and revokes all central token state backed by that local user. | Password reset, recovery, contact replacement, credential compromise, suspension. |
| Tenant | Rejects authentication state for one ProAuth user and tenant when its auth_time is on or before the cutoff. | Sign out all applications in the current tenant. |
| Client | Applies the cutoff only to one ProAuth user, tenant, and client, and revokes matching token families. | Sign out of one application. |
Tenant and client cutoffs are monotonic durable records. UserStore epoch validation and cutoff storage fail closed: a storage or locator failure does not turn stale state into valid state.
The authorization server checks these values during SSO reuse and token validation. A user must complete fresh policy-compliant authentication after the relevant cutoff.
Presenting state invalidated by a tenant or client cutoff does not revoke grants in other scopes. Validation failures caused by unavailable storage also reject the request without triggering a user-wide sign-out.
Account Management sessions
Account Management > Sessions lists active stored token families grouped by application for the authenticated tenant. It shows:
- application name and ID;
- first and last issuance times;
- expiry;
- whether renewable state exists;
- token types in the family.
The user can sign out of one application or all applications in the tenant. Token values are never exposed.
The browser endpoints are:
GET /account/security/api/sessions
DELETE /account/security/api/sessions/clients/{clientAppId}
DELETE /account/security/api/sessionsThese endpoints derive the target user and tenant from the authenticated Account Management session. They do not accept a caller-selected subject or tenant.
What “all applications” means
The all-sessions action is tenant-scoped. It does not sign the same ProAuth user out of unrelated tenants. A UserStore-wide compromise response uses the broader UserStore-user revocation path.
Operational guidance
- Require a case reference for administrator-initiated replacement.
- Keep at least one independent approval for privileged or regulated accounts.
- Alert on replacement requests, failed proofs, expired operations, execution, and cleanup retries.
- Investigate any operation where the issuer or subject differs from the approved replacement request.
- Monitor revocation cleanup lag and stale-epoch rejection rates.
- Do not delete retired identity history until its retention obligation has elapsed.
- Test SSO reuse, refresh-token use, and concurrent browser tabs after every revocation scope.
User deletion and legacy API compatibility
Deleting a user through either API version begins the configured deletion quarantine (30 days by default). The account and its synchronized identity become inactive immediately. Quarantine retains the data needed for controlled recovery and eventual erasure; it does not permit authentication.
The v1 DELETE route, request and response formats remain unchanged. Subsequent v1 user reads return 404, and v1 user lists exclude the deleted account, preserving legacy deletion-as-absence behavior. Administrators using v2 can inspect the retained inactive record. Canonical identifiers remain reserved during quarantine. Use the lifecycle and erasure process to restore or permanently erase records; changing an activity flag is not a substitute.
The built-in job scheduler checks due deletions, passkey policies and pending notifications every minute. Setting UserDeletionQuarantineDays to 0 makes a deletion eligible for the next maintenance run; erasure is asynchronous and can take longer when there is a backlog or a processing failure. Legal hold continues to prevent erasure.