docs: add inline OIDC sequence diagram to ADR-0009
Render the OAuth 2.0 Authorization Code + PKCE flow as a Mermaid sequence diagram at the top of the Decision Outcome section. Five participants (user, SPA, BFF, Entra, Redis), thirteen autonumbered steps covering the authorize redirect, the user-side authentication (with the Conditional Access MFA enforcement annotated), the callback, the state verification, the token exchange, the id_token validation pipeline (signature, iss against the tenant allowlist, aud, exp/nbf, amr sanity-check, audience-claim mapping), the encrypted session write to Redis, and the cookie set. Inline rather than in docs/architecture.md per the convention stated at the top of architecture.md: cross-cutting diagrams live in the architecture file, single-decision diagrams live inside the ADR they visualise. ADR-0009 IS the auth flow decision; the sequence diagram belongs here. Cross-references the related ADRs (0010 sessions, 0011 MFA, 0008 audience model) so the diagram reads as the integration point of the security stack rather than as an isolated picture.
This commit is contained in:
@@ -60,6 +60,37 @@ The SPA must never hold tokens — that is the BFF security pattern, recommended
|
||||
|
||||
## Decision Outcome
|
||||
|
||||
The end-to-end flow at a glance:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
actor U as User (browser)
|
||||
participant SPA as portal-shell
|
||||
participant BFF as portal-bff
|
||||
participant E as Microsoft Entra ID
|
||||
participant R as Redis (session store)
|
||||
|
||||
U->>SPA: clicks "Sign in"
|
||||
SPA->>BFF: GET /auth/login?returnTo=…
|
||||
BFF->>BFF: generate state + nonce<br/>+ code_verifier + code_challenge
|
||||
BFF-->>U: 302 → Entra /authorize<br/>(client_id, code_challenge, state, nonce, scope)
|
||||
U->>E: authenticate<br/>(Conditional Access enforces MFA)
|
||||
E-->>U: 302 → BFF /auth/callback?code&state
|
||||
U->>BFF: GET /auth/callback?code&state
|
||||
|
||||
BFF->>BFF: verify state matches<br/>(CSRF defence on the OIDC roundtrip)
|
||||
BFF->>E: POST /token<br/>(code + code_verifier + client_secret/cert)
|
||||
E-->>BFF: id_token + access_token + refresh_token
|
||||
|
||||
BFF->>BFF: validate id_token<br/>(sig, iss in allowlist, aud, exp/nbf)<br/>+ sanity-check amr (ADR-0011)<br/>+ map audience claim → Audience enum
|
||||
BFF->>R: SET session:{opaque_id}<br/>payload incl. tokens encrypted AES-256-GCM (ADR-0010)
|
||||
BFF-->>U: 302 → returnTo<br/>+ Set-Cookie __Host-portal_session<br/>+ Set-Cookie __Host-portal_csrf
|
||||
U->>SPA: render destination (cookies attached on subsequent calls)
|
||||
```
|
||||
|
||||
The numbered steps line up with the prose below: library / flow / tokens / token validation / refresh / cookies / CSRF / routes / auth layer.
|
||||
|
||||
**Library.** `@azure/msal-node`, instance of `ConfidentialClientApplication`, configured with the multi-tenant authority and the tenant allowlist from ADR-0008. PKCE is used despite the confidential-client setup, per IETF current BCP.
|
||||
|
||||
**Flow.** OAuth 2.0 Authorization Code Flow with PKCE, executed entirely on the BFF. The SPA never sees `code`, `code_verifier`, or any token.
|
||||
|
||||
Reference in New Issue
Block a user