Files
fm_be/docs/frontend-sso-exchange-flow.md
2026-07-16 22:16:45 +07:00

122 lines
3.8 KiB
Markdown

# Frontend Flow: Microsoft `ssoSilent` + Backend `/auth/exchange`
This document describes the recommended frontend authentication flow when using:
- Microsoft Entra `ssoSilent` on the frontend
- Backend session tokens (`access` + `refresh`) issued by `/api/v1/auth/exchange`
## Goal
Use Microsoft silent SSO to re-establish identity, then exchange that identity for backend session cookies/tokens used by API requests.
## Prerequisites
- Frontend already integrated with MSAL and can call `ssoSilent`.
- Backend has `POST /api/v1/auth/exchange`.
- User account is already linked/recognized by backend SSO mapping.
- Backend uses cookie-based auth session (`access` + `refresh` cookies).
## High-Level Sequence
1. Frontend attempts to call backend API with current backend access session.
2. If backend responds `401`, frontend calls `POST /api/v1/auth/refresh` once.
3. If refresh fails (`401`), frontend tries Microsoft `ssoSilent`.
4. If `ssoSilent` succeeds, frontend calls `POST /api/v1/auth/exchange`.
5. Backend issues fresh auth cookies. Frontend retries the original API request.
6. If `ssoSilent` fails with `interaction_required`, frontend logs out local app session and redirects user to interactive login.
## Detailed Frontend Logic
## 1) App startup / route guard
1. Try calling a lightweight authenticated endpoint (for example `/api/v1/auth/me`).
2. If response is `200`, continue app normally.
3. If response is `401`, run the recovery flow below.
## 2) Recovery flow for backend `401`
1. Call `POST /api/v1/auth/refresh` once.
2. If refresh is successful (`200`), retry the original request and continue.
3. If refresh fails (`401`), call Microsoft `ssoSilent`.
## 3) On successful `ssoSilent`
The frontend receives a Microsoft auth result (example fields):
- `accessToken`
- `idToken`
- `idTokenClaims`
Send them to backend exchange endpoint:
```http
POST /api/v1/auth/exchange
Content-Type: application/json
```
```json
{
"data": {
"type": "auth_exchange",
"attributes": {
"access_token": "<ms_access_token>",
"id_token": "<ms_id_token>",
"id_token_claims": {
"sub": "...",
"preferred_username": "user@company.com",
"name": "User Name",
"tid": "...",
"oid": "...",
"exp": 1715603600
}
}
}
}
```
Expected behavior:
- `200`: backend sets fresh session cookies -> frontend retries previous API call.
- `401`: identity not linked / invalid token -> treat as not authenticated and move to login.
## 4) On failed `ssoSilent`
If frontend receives:
- `errorCode = "interaction_required"` (or equivalent no-session/no-cookie condition)
Then:
1. Clear local app auth state (user store, cached flags, pending retries).
2. Redirect to interactive login page/flow.
Do not loop `ssoSilent` repeatedly.
## Retry Rules (Important)
- Only attempt each step once per failure chain:
- one `/auth/refresh`
- one `ssoSilent`
- one `/auth/exchange`
- Use a request queue/lock to prevent multiple parallel refresh/exchange attempts.
- If exchange fails, stop retries and force user to login interactively.
## Suggested Error Handling Matrix
- Backend API `401`:
- action: `/auth/refresh`
- `/auth/refresh` `401`:
- action: `ssoSilent`
- `ssoSilent` success:
- action: `/auth/exchange`
- `ssoSilent` `interaction_required`:
- action: clear session + redirect login
- `/auth/exchange` `401`:
- action: clear session + redirect login
## Security Notes
- Do not store backend refresh tokens in JavaScript storage.
- Prefer `HttpOnly`, `Secure`, `SameSite` cookies from backend.
- Avoid logging raw Microsoft tokens in browser console or monitoring payloads.
## Optional UX Improvement
When redirecting to login after `interaction_required`, preserve the intended route:
- Save current path (`returnTo`) and restore it after successful login.