Account switching
When one person controls multiple email-based accounts (e.g. a personal account and a company-email account from corporate onboarding), they can link them and switch without signing in again. Base path: /api/auth/linked-identities.
Linking (proof of ownership on both sides)
Section titled “Linking (proof of ownership on both sides)”| Method · Route | Purpose | Source |
|---|---|---|
POST /initiate | Signed-in user A requests to link email B; emails B a single-use confirm link (15-min, rate-limited). | LinkedIdentityEndpoints.cs:36 |
GET /confirm?token= | B clicks the emailed link → creates the sealed LinkedIdentity (A↔B). Token-authenticated, no session. | :89 |
GET / | List the current user’s active links (for the account-switcher dropdown). | :131 |
POST /{id}/revoke | Unlink — append-only (Status=Revoked, soft-delete; never hard-deleted). | :162 |
Switching (account-takeover-critical)
Section titled “Switching (account-takeover-critical)”POST /switch (:185) re-issues the session as the linked identity and swaps the cookie — gated by a fresh passkey step-up of the current session owner:
- A link must already exist between caller and target, else 404
not_linked. - A passkey assertion is required (403
step_up_requiredif absent). - The assertion must verify and belong to the caller’s own User (
assertion.UserId == uid), so a stolen cookie + an attacker’s own passkey cannot pivot (403step_up_failed). - On success,
SwitchIdentityCommandissues the target session andCookieAuthWriterreplaces the cookie.
Linking requires explicit proof of ownership of both accounts — accounts are never linked automatically.