vault backup: 2026-04-30 16:05:42
This commit is contained in:
parent
59e4539c70
commit
c4227c42bb
2 changed files with 107 additions and 0 deletions
|
|
@ -239,3 +239,6 @@ tags: [daily]
|
|||
- 16:01 | `aimpress`
|
||||
- **Asked:** Configure magnet link support and disable uploads in qBittorrent | Set up qBittorrent for magnet links with download-only mode, connected Radarr/Sonarr to Jellyfin with auto-scan on completion | qbittorrent.conf, jellyfin_scan.sh
|
||||
- **Done:** Asked: Configure qBittorrent magnet link support with download-only and check speed limits
|
||||
- 16:04 (2min) | `video-accessibility`
|
||||
- **Asked:** Check SSO configuration in the project to verify if it's correctly set up for Azure Single Page Application flow.
|
||||
- **Done:** Analyzed SSO architecture and confirmed the implementation correctly uses browser-based token exchange with PKCE flow, backend verification via Microsoft JWKS, and httpOnly cookie response.
|
||||
|
|
|
|||
104
wiki/tech-patterns/azure-sso-pkce-browser-token-exchange.md
Normal file
104
wiki/tech-patterns/azure-sso-pkce-browser-token-exchange.md
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
---
|
||||
tags: [tech-patterns, auto-generated]
|
||||
source: video-accessibility
|
||||
created: 2026-04-30
|
||||
---
|
||||
|
||||
# Azure SSO with MSAL: Browser-Based Token Exchange Pattern
|
||||
|
||||
## When to use
|
||||
When implementing Single Page Application (SPA) authentication with Azure AD where the frontend handles OAuth token acquisition via PKCE flow, and the backend validates tokens without requiring client secrets. This pattern is appropriate when you need to avoid exposing credentials on the backend and want to leverage browser-native security features.
|
||||
|
||||
## Prerequisites
|
||||
- Azure AD tenant with app registration configured as Single Page Application
|
||||
- MSAL.js library (v2.0+) installed in frontend
|
||||
- Backend HTTP endpoint for token validation (e.g., `POST /auth/microsoft`)
|
||||
- Backend access to Microsoft's public JWKS endpoint
|
||||
- Understanding of OAuth 2.0 PKCE flow
|
||||
|
||||
## Steps
|
||||
1. Configure Azure AD app registration:
|
||||
- Set app type to "Single Page Application"
|
||||
- Add frontend URL to "Redirect URIs" (e.g., `http://localhost:3000`)
|
||||
- Enable implicit grant flow for ID tokens (not required, PKCE preferred)
|
||||
- Note the Client ID and Tenant ID
|
||||
|
||||
2. Configure MSAL in frontend (e.g., `src/msal-config.ts`):
|
||||
```javascript
|
||||
const msalConfig = {
|
||||
auth: {
|
||||
clientId: process.env.REACT_APP_AZURE_CLIENT_ID,
|
||||
authority: `https://login.microsoftonline.com/${process.env.REACT_APP_AZURE_TENANT_ID}`,
|
||||
redirectUri: window.location.origin
|
||||
},
|
||||
cache: { cacheLocation: "sessionStorage" },
|
||||
system: { loggerOptions: { loggerCallback: console.log } }
|
||||
};
|
||||
```
|
||||
|
||||
3. Trigger login popup in browser:
|
||||
```javascript
|
||||
const loginPopup = async () => {
|
||||
const response = await publicClientApplication.loginPopup({
|
||||
scopes: ["openid", "profile"]
|
||||
});
|
||||
return response.idToken; // This is the ID token from Azure
|
||||
};
|
||||
```
|
||||
|
||||
4. Send ID token to backend for validation:
|
||||
```javascript
|
||||
const response = await fetch('/auth/microsoft', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id_token: response.idToken }),
|
||||
credentials: 'include' // For httpOnly cookie
|
||||
});
|
||||
```
|
||||
|
||||
5. Backend validates token signature against Microsoft's public JWKS:
|
||||
```
|
||||
GET https://login.microsoftonline.com/{tenant-id}/discovery/v2.0/keys
|
||||
```
|
||||
Verify:
|
||||
- Token signature matches public key from JWKS
|
||||
- `aud` (audience) claim matches your Client ID
|
||||
- `iss` (issuer) matches your tenant
|
||||
- Token not expired
|
||||
|
||||
6. Backend issues its own JWT (httpOnly, Secure, SameSite flags):
|
||||
```
|
||||
Set-Cookie: jwt=...; HttpOnly; Secure; SameSite=Strict; Path=/
|
||||
```
|
||||
|
||||
## Key Configuration
|
||||
**Frontend `.env`:**
|
||||
```
|
||||
REACT_APP_AZURE_CLIENT_ID=your-client-id
|
||||
REACT_APP_AZURE_TENANT_ID=your-tenant-id
|
||||
```
|
||||
|
||||
**Backend token validation pseudocode:**
|
||||
```
|
||||
POST /auth/microsoft
|
||||
body: { id_token }
|
||||
|
||||
1. Decode JWT header (no verification yet)
|
||||
2. Fetch JWKS from Microsoft
|
||||
3. Find public key matching kid from JWT header
|
||||
4. Verify signature with that public key
|
||||
5. Verify claims: aud, iss, exp, iat
|
||||
6. Create session / issue httpOnly JWT
|
||||
7. Return 200 with Set-Cookie header
|
||||
```
|
||||
|
||||
## Gotchas
|
||||
- **Do NOT make backend-to-backend calls to Microsoft token endpoint** – the browser already obtained the token via PKCE. A second call is redundant and suggests a configuration error (likely Azure app registered as "Web app" instead of "Single Page Application").
|
||||
- **PKCE is handled automatically by MSAL.js** – no manual code_verifier/code_challenge needed in frontend.
|
||||
- **Public JWKS endpoint requires no authentication** – you fetch it directly from Microsoft, no client secret needed for validation.
|
||||
- **Token validation MUST happen on backend** – never trust token validation from frontend; always verify signature server-side.
|
||||
- **Redirect URI must exactly match Azure registration** – including protocol, domain, port, and path.
|
||||
- **httpOnly cookies prevent XSS token theft** – never store tokens in localStorage if possible.
|
||||
|
||||
## Source
|
||||
Project: video-accessibility
|
||||
Loading…
Add table
Reference in a new issue