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.
Maintenance: Update this file when a new browser API dependency is introduced or a browser change is discovered that affects MSAL flows.
| API | MSAL Usage | Fallback |
|---|---|---|
sessionStorage |
Interaction status, PKCE verifier, redirect origin URL, redirect bridge response cache | MemoryStorage (response lost on navigation) |
localStorage |
Persistent token cache (when cacheLocation: "localStorage") |
None if configured; not used by default |
IndexedDB |
PoP token RSA keypairs and DPoP token-binding keypairs | In-memory (keys lost on reload) |
document.cookie |
Encryption key for localStorage cache | None — cache cannot be decrypted without it |
MSAL-specific restrictions:
- Safari PB:
sessionStorage.setItem()immediately beforelocation.replace()may lose data — affects redirect bridge (handleRedirectPromisereturnsnull) - Safari ITP: 7-day cap on script-writable
localStorage/cookies — tokens evicted without user interaction - Firefox PB:
indexedDB.open()throwsSecurityError— PoP/DPoP key storage falls back to memory - Chrome 115+ / Safari 16.1+: storage partitioned in cross-origin iframes — affects NAA and embedded apps
All crypto.subtle methods require HTTPS (secure context). On HTTP origins, crypto.subtle is undefined.
| API | MSAL Usage | Fallback |
|---|---|---|
crypto.subtle.digest() |
PKCE code_challenge (SHA-256) |
None — PKCE is mandatory |
crypto.getRandomValues() |
PKCE verifier, state, nonce, correlation IDs | None |
crypto.subtle.generateKey() |
PoP RSA keypairs, DPoP ES256/P-256 keypairs, EAR AES keys | None for PoP/DPoP/EAR |
crypto.subtle.importKey() |
PoP signing, DPoP signing, EAR decryption, localStorage encryption (HKDF → AES-GCM) | None |
crypto.subtle.sign() |
PoP token signing, DPoP proof signing | None |
crypto.subtle.decrypt() |
EAR response decryption, localStorage decryption | None |
crypto.subtle.deriveKey() |
HKDF key derivation for localStorage encryption | None |
MSAL-specific restriction: deriveKey() with HKDF as base key requires Firefox 119+.
| API | MSAL Usage | Fallback |
|---|---|---|
BroadcastChannel |
Redirect bridge (popup/iframe → main frame), cross-tab cache sync | None for redirect bridge |
postMessage + MessageChannel |
WAM browser extension communication | None for WAM path |
MSAL-specific restrictions:
- Chrome 115+ / Firefox TCP:
BroadcastChannelpartitioned by top-level site — breaks cross-origin iframe ↔ popup communication - Safari PB: cross-tab channels do not persist
| API | MSAL Usage | Fallback |
|---|---|---|
window.location.assign() / .replace() |
Navigate to IdP | None |
window.location.hash / .search |
Extract auth response from redirect URL | None |
window.history.replaceState() |
Clean auth params from URL | Graceful no-op (URL stays dirty) |
pageshow event |
Detect bfcache restoration to clear stale interaction state | Graceful — may cause interaction_in_progress error |
window.open() |
Popup auth flows | None for popup |
| Hidden iframe | Silent token renewal (ssoSilent, acquireTokenSilent fallback) |
None for silent renewal |
window.close() |
Close popup after auth | Graceful — popup stays open |
MSAL-specific restrictions:
window.open()must be in a user-gesture call stack or browsers block it- COOP
same-originon AAD severswindow.openerin popups — redirect bridge mitigates - 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
- Office.js sets
history.replaceStatetonull— MSAL guards withtypeofcheck
| API | MSAL Usage | Fallback |
|---|---|---|
fetch() |
All HTTP requests (token endpoint, discovery, custom auth) | None |
navigator.onLine |
Distinguish network-offline from transport failures when token POST fails | Assumes online (retries once for non-abort transport failures) |
TextEncoder / TextDecoder |
String ↔ binary for crypto | None |
atob() / btoa() |
Base64 for JWK and token parsing | None |
Hidden form + form.submit() |
POST-based /authorize (EAR, redirect POST, silent iframe POST) |
None for POST flows |
<link rel="preconnect"> |
Early DNS/TLS to authority domain | Graceful — just slower |
MSAL-specific restrictions:
- CSP
connect-srcmust allow authority/token endpoint domains - CSP
form-actionmust allow authority domain for POST flows - CSP
frame-srcmust allow authority domain for silent iframe
| Restriction | Affected Browsers | Impact on MSAL |
|---|---|---|
| 3P cookie blocking | Safari (ITP), Firefox (TCP), Chrome (user setting/Incognito) | Silent iframe renewal fails |
| Storage partitioning in iframes | Chrome 115+, Safari 16.1+, Firefox TCP | BroadcastChannel/storage isolated — breaks embedded app scenarios |
| Script-writable storage 7-day cap | Safari ITP | localStorage tokens evicted; cookie-based encryption key lost |
| Private Browsing ephemeral storage | Safari, Firefox, Chrome | Tokens lost on tab close; IndexedDB blocked in Firefox PB |
| Tracker domain blocking (Safari 17+ PB) | Safari | CDN-hosted redirect bridge scripts may fail to load |
| Change | Status | MSAL Impact |
|---|---|---|
| Chrome Storage Access API | Shipping | Potential fallback for 3P-cookie-blocked iframe renewal |
| Safari tracking domain list expansion | Ongoing | More CDN domains may be blocked in PB |
Firefox BroadcastChannel partitioned under TCP |
Active (Firefox 102+) | Breaks cross-origin iframe ↔ popup channel |
| Platform authentication proposal | Early proposal | May enable native broker without extension |
| API | loginRedirect |
loginPopup |
ssoSilent |
acquireTokenSilent |
NAA | WAM |
|---|---|---|---|---|---|---|
sessionStorage |
✅ | |||||
localStorage |
○ | ○ | ○ | ○ | ||
IndexedDB |
○ | ○ | ○ | ○ | ||
BroadcastChannel |
¹ | ✅ | ✅ | ✅² | ||
window.open() |
✅ | |||||
| Hidden iframe | ✅ | ✅² | ||||
crypto.subtle |
✅ | ✅ | ✅ | ✅ | ||
fetch() |
✅ | ✅ | ✅ | ✅ | ✅ | |
postMessage |
✅ | ✅ | ||||
| Form submit (POST) | ○ | ○ | ○ | |||
| Cookies | ○ | ○ | ³ | ³ |
- ✅ = required | ○ = optional/configurable
- ¹ redirect bridge popup/iframe only (not direct redirect)
- ² when refresh token expired and MSAL falls back to hidden iframe
- ³ IdP session cookie required in iframe; MSAL's own cookie for localStorage encryption only