From 4b8d0789b1723c8eb7ca0f5b702898fff121264a Mon Sep 17 00:00:00 2001 From: Julien Gautier Date: Thu, 30 Apr 2026 21:02:08 +0200 Subject: [PATCH] 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. --- .../0009-auth-flow-oidc-pkce-msal-node.md | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/decisions/0009-auth-flow-oidc-pkce-msal-node.md b/docs/decisions/0009-auth-flow-oidc-pkce-msal-node.md index d0b2fb6..147fbe1 100644 --- a/docs/decisions/0009-auth-flow-oidc-pkce-msal-node.md +++ b/docs/decisions/0009-auth-flow-oidc-pkce-msal-node.md @@ -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
+ code_verifier + code_challenge + BFF-->>U: 302 → Entra /authorize
(client_id, code_challenge, state, nonce, scope) + U->>E: authenticate
(Conditional Access enforces MFA) + E-->>U: 302 → BFF /auth/callback?code&state + U->>BFF: GET /auth/callback?code&state + + BFF->>BFF: verify state matches
(CSRF defence on the OIDC roundtrip) + BFF->>E: POST /token
(code + code_verifier + client_secret/cert) + E-->>BFF: id_token + access_token + refresh_token + + BFF->>BFF: validate id_token
(sig, iss in allowlist, aud, exp/nbf)
+ sanity-check amr (ADR-0011)
+ map audience claim → Audience enum + BFF->>R: SET session:{opaque_id}
payload incl. tokens encrypted AES-256-GCM (ADR-0010) + BFF-->>U: 302 → returnTo
+ Set-Cookie __Host-portal_session
+ 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.