Skip to content

Commit bbcc105

Browse files
Add browser compatibility guidelines and review instructions for msal-browser (#8525)
This pull request introduces comprehensive documentation and review process improvements focused on browser compatibility, privacy risks, and the handling of browser Web APIs in the `msal-browser` library. The changes add a detailed compatibility map, new review instructions, and update existing documentation to ensure that all browser API usage is tracked, reviewed, and communicated clearly to both developers and reviewers. **Key changes include:** ### Browser Compatibility Documentation and Review Process * Added a new, detailed browser compatibility review instruction file (`.github/instructions/browser_compat.instructions.md`) that provides a checklist for reviewing changes to browser Web API usage, including privacy risks, fallback requirements, and cross-browser restrictions. * Introduced a comprehensive "Browser Compatibility Map" (`lib/msal-browser/docs/browser-compat-map.md`) documenting all browser APIs used by MSAL, their restrictions across browsers and privacy modes, and upcoming changes in browser beta channels. This serves as a central reference for reviewers and is to be updated with every new or changed API dependency. ### Integration with Review Workflows * Updated the doc review instructions to require updating the compatibility map whenever browser Web API usage is introduced, removed, or changed, ensuring documentation stays current with code changes. * Enhanced the agent guidelines (`AGENTS.md`) to reference the new compatibility map and review checklist, clarifying when and how browser compatibility should be checked during PR review. ### Security and Privacy Best Practices * Strengthened the security guidance in the redirect bridge documentation to explicitly prohibit hosting the bridge or its assets on third-party CDNs or origins, require `Cache-Control: no-store`, and explain privacy risks in Safari Private Browsing and similar modes. These changes together ensure that MSAL's browser compatibility and privacy risks are systematically tracked, reviewed, and documented, reducing the likelihood of subtle breakages or security regressions across browsers and privacy modes. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent d7a7eb5 commit bbcc105

4 files changed

Lines changed: 151 additions & 0 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
description: "Use when reviewing or modifying msal-browser source code that introduces, changes, or removes browser Web API usage."
3+
applyTo: "**/lib/msal-browser/src/**"
4+
---
5+
6+
# Browser Compatibility Review
7+
8+
When a change to `lib/msal-browser/src/` introduces, modifies, or removes a browser Web API call, review the [Browser Compatibility Map](../../lib/msal-browser/docs/browser-compat-map.md) for MSAL-specific restrictions and flow dependencies.
9+
10+
## Review steps
11+
12+
1. **Cross-reference the compatibility map** — check which auth flows depend on the affected API, known restrictions, and whether a fallback exists.
13+
2. **New API not in the map** — verify support on MDN/Can I Use (Chrome, Edge, Firefox, Safari desktop+iOS, Chrome Android). Check Private Browsing behavior and storage-partitioning impact. Request the map be updated.
14+
3. **Validate fallback paths** — confirm `try/catch` or feature-detection guards exist for APIs with known restrictions. If no fallback exists on a critical path, flag for discussion.
15+
4. **Check CSP/COOP/framing** — iframe changes need `frame-src`/sandbox review; popup changes need COOP consideration; `fetch()`/form-submit changes need `connect-src`/`form-action` review.
16+
5. **Check beta channel risks** — see the "Upcoming Changes" section of the map for pending browser changes affecting the touched API.
17+
18+
## What to flag
19+
20+
- **Must fix**: API unavailable in a supported browser/mode with no fallback or `try/catch`
21+
- **Discuss**: Critical-path API with known restrictions in beta channels
22+
- **Informational**: Well-supported new API that should be added to the compatibility map

.github/instructions/doc_review.instructions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Each library has its own `docs/` directory. When reviewing changes, look for the
3333

3434
- Changes affected by browser security policies (COOP, COEP, storage partitioning, iframe sandboxing) → update `lib/msal-browser/docs/redirect-bridge.md`, `lib/msal-browser/docs/iframe-usage.md`
3535
- Changes to cross-origin or cross-window communication → update relevant flow docs and known limitations
36+
- Browser API changes: If the change introduces, removes, or modifies usage of a browser Web API (`sessionStorage`, `localStorage`, `IndexedDB`, `BroadcastChannel`, `crypto.subtle`, `window.open`, hidden iframes, `fetch`, `document.cookie`, form submission, etc.), update `lib/msal-browser/docs/browser-compat-map.md` with the new or changed API entry, known restrictions, and fallback behavior
3637

3738
### Migration impact
3839

AGENTS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,9 @@ When a commit deletes, renames, or moves files and directories (especially sampl
5050
- Anchor references (`#heading-name`) if headings were changed
5151

5252
Update or remove stale links introduced or exposed by the current change before merging. For a full repo-wide audit, use the `/doc-audit` prompt (`.github/prompts/doc-audit.prompt.md`). Follow guidelines listed at `.github/instructions/doc_links.instructions.md`.
53+
54+
### Browser Compatibility
55+
56+
Changes to `lib/msal-browser/src/` that introduce, modify, or remove browser Web API usage should be checked against the [Browser Compatibility Map](lib/msal-browser/docs/browser-compat-map.md). The compatibility map catalogs every browser API that MSAL depends on, known restrictions across browsers and privacy modes (Safari Private Browsing, Chrome storage partitioning, Firefox ETP), and upcoming browser changes in beta channels.
57+
58+
The `.github/instructions/browser_compat.instructions.md` instruction is automatically loaded for changes under `lib/msal-browser/src/` and provides a review checklist for identifying compatibility risks.
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# Browser Compatibility Map for MSAL Browser
2+
3+
This document catalogs browser Web APIs that MSAL Browser depends on, their role in authentication flows, MSAL's fallback behavior, and known MSAL-specific restrictions. For general browser support data, refer to [MDN Web Docs](https://developer.mozilla.org/).
4+
5+
> **Maintenance:** Update this file when a new browser API dependency is introduced or a browser change is discovered that affects MSAL flows.
6+
7+
## API Dependencies
8+
9+
### Storage
10+
11+
| API | MSAL Usage | Fallback |
12+
|-----|-----------|----------|
13+
| `sessionStorage` | Interaction status, PKCE verifier, redirect origin URL, redirect bridge response cache | `MemoryStorage` (response lost on navigation) |
14+
| `localStorage` | Persistent token cache (when `cacheLocation: "localStorage"`) | None if configured; not used by default |
15+
| `IndexedDB` | PoP token RSA keypairs | In-memory (keys lost on reload) |
16+
| `document.cookie` | Encryption key for localStorage cache | None — cache cannot be decrypted without it |
17+
18+
**MSAL-specific restrictions:**
19+
- Safari PB: `sessionStorage.setItem()` immediately before `location.replace()` may lose data — affects redirect bridge (`handleRedirectPromise` returns `null`)
20+
- Safari ITP: 7-day cap on script-writable `localStorage`/cookies — tokens evicted without user interaction
21+
- Firefox PB: `indexedDB.open()` throws `SecurityError` — PoP falls back to memory
22+
- Chrome 115+ / Safari 16.1+: storage partitioned in cross-origin iframes — affects NAA and embedded apps
23+
24+
### Crypto
25+
26+
All `crypto.subtle` methods require HTTPS (secure context). On HTTP origins, `crypto.subtle` is `undefined`.
27+
28+
| API | MSAL Usage | Fallback |
29+
|-----|-----------|----------|
30+
| `crypto.subtle.digest()` | PKCE `code_challenge` (SHA-256) | None — PKCE is mandatory |
31+
| `crypto.getRandomValues()` | PKCE verifier, state, nonce, correlation IDs | None |
32+
| `crypto.subtle.generateKey()` | PoP RSA keypairs, EAR AES keys | None for PoP/EAR |
33+
| `crypto.subtle.importKey()` | PoP signing, EAR decryption, localStorage encryption (HKDF → AES-GCM) | None |
34+
| `crypto.subtle.sign()` | PoP token signing | None |
35+
| `crypto.subtle.decrypt()` | EAR response decryption, localStorage decryption | None |
36+
| `crypto.subtle.deriveKey()` | HKDF key derivation for localStorage encryption | None |
37+
38+
**MSAL-specific restriction:** `deriveKey()` with HKDF as base key requires Firefox 119+.
39+
40+
### Messaging
41+
42+
| API | MSAL Usage | Fallback |
43+
|-----|-----------|----------|
44+
| `BroadcastChannel` | Redirect bridge (popup/iframe → main frame), cross-tab cache sync | None for redirect bridge |
45+
| `postMessage` + `MessageChannel` | WAM browser extension communication | None for WAM path |
46+
47+
**MSAL-specific restrictions:**
48+
- Chrome 115+ / Firefox TCP: `BroadcastChannel` partitioned by top-level site — breaks cross-origin iframe ↔ popup communication
49+
- Safari PB: cross-tab channels do not persist
50+
51+
### Navigation & Window
52+
53+
| API | MSAL Usage | Fallback |
54+
|-----|-----------|----------|
55+
| `window.location.assign()` / `.replace()` | Navigate to IdP | None |
56+
| `window.location.hash` / `.search` | Extract auth response from redirect URL | None |
57+
| `window.history.replaceState()` | Clean auth params from URL | Graceful no-op (URL stays dirty) |
58+
| `pageshow` event | Detect bfcache restoration to clear stale interaction state | Graceful — may cause `interaction_in_progress` error |
59+
| `window.open()` | Popup auth flows | None for popup |
60+
| Hidden iframe | Silent token renewal (`ssoSilent`, `acquireTokenSilent` fallback) | None for silent renewal |
61+
| `window.close()` | Close popup after auth | Graceful — popup stays open |
62+
63+
**MSAL-specific restrictions:**
64+
- `window.open()` must be in a user-gesture call stack or browsers block it
65+
- COOP `same-origin` on AAD severs `window.opener` in popups — redirect bridge mitigates
66+
- Silent iframe requires IdP to allow framing and 3P cookies to be available; breaks under Safari ITP, Firefox TCP, and Chrome with 3P cookies disabled
67+
- Office.js sets `history.replaceState` to `null` — MSAL guards with `typeof` check
68+
69+
### Network & DOM
70+
71+
| API | MSAL Usage | Fallback |
72+
|-----|-----------|----------|
73+
| `fetch()` | All HTTP requests (token endpoint, discovery, custom auth) | None |
74+
| `TextEncoder` / `TextDecoder` | String ↔ binary for crypto | None |
75+
| `atob()` / `btoa()` | Base64 for JWK and token parsing | None |
76+
| Hidden form + `form.submit()` | POST-based `/authorize` (EAR, redirect POST, silent iframe POST) | None for POST flows |
77+
| `<link rel="preconnect">` | Early DNS/TLS to authority domain | Graceful — just slower |
78+
79+
**MSAL-specific restrictions:**
80+
- CSP `connect-src` must allow authority/token endpoint domains
81+
- CSP `form-action` must allow authority domain for POST flows
82+
- CSP `frame-src` must allow authority domain for silent iframe
83+
84+
## Privacy Restrictions Affecting MSAL
85+
86+
| Restriction | Affected Browsers | Impact on MSAL |
87+
|-------------|-------------------|----------------|
88+
| 3P cookie blocking | Safari (ITP), Firefox (TCP), Chrome (user setting/Incognito) | Silent iframe renewal fails |
89+
| Storage partitioning in iframes | Chrome 115+, Safari 16.1+, Firefox TCP | `BroadcastChannel`/storage isolated — breaks embedded app scenarios |
90+
| Script-writable storage 7-day cap | Safari ITP | `localStorage` tokens evicted; cookie-based encryption key lost |
91+
| Private Browsing ephemeral storage | Safari, Firefox, Chrome | Tokens lost on tab close; IndexedDB blocked in Firefox PB |
92+
| Tracker domain blocking (Safari 17+ PB) | Safari | CDN-hosted redirect bridge scripts may fail to load |
93+
94+
## Upcoming Changes
95+
96+
| Change | Status | MSAL Impact |
97+
|--------|--------|-------------|
98+
| Chrome Storage Access API | Shipping | Potential fallback for 3P-cookie-blocked iframe renewal |
99+
| Safari tracking domain list expansion | Ongoing | More CDN domains may be blocked in PB |
100+
| Firefox `BroadcastChannel` partitioned under TCP | Active (Firefox 102+) | Breaks cross-origin iframe ↔ popup channel |
101+
| Platform authentication proposal | Early proposal | May enable native broker without extension |
102+
103+
## API-to-Flow Matrix
104+
105+
| API | `loginRedirect` | `loginPopup` | `ssoSilent` | `acquireTokenSilent` | NAA | WAM |
106+
|-----|:-:|:-:|:-:|:-:|:-:|:-:|
107+
| `sessionStorage` || | | | | |
108+
| `localStorage` ||||| | |
109+
| `IndexedDB` ||||| | |
110+
| `BroadcastChannel` | ¹ ||| ✅² | | |
111+
| `window.open()` | || | | | |
112+
| Hidden iframe | | || ✅² | | |
113+
| `crypto.subtle` ||||| | |
114+
| `fetch()` ||||| ||
115+
| `postMessage` | | | | |||
116+
| Form submit (POST) |||| | | |
117+
| Cookies ||| ³ | ³ | | |
118+
119+
- ✅ = required | ○ = optional/configurable
120+
- ¹ redirect bridge popup/iframe only (not direct redirect)
121+
- ² when refresh token expired and MSAL falls back to hidden iframe
122+
- ³ IdP session cookie required in iframe; MSAL's own cookie for localStorage encryption only

0 commit comments

Comments
 (0)