OAuth PKCE sessionStorage Perdu lors de la Redirection
Problème
Le flux OAuth PKCE échoue à l'étape d'échange de code car le vérificateur de code PKCE stocké dans sessionStorage est manquant après la redirection en provenance du serveur d'autorisation externe. Le message d'erreur dit généralement « Session not found » ou « No code verifier found » sans indication que le backend de stockage est en cause.
Contexte / Conditions de Déclenchement
- L'SPA initie le flux OAuth PKCE, stockant code_verifier dans
sessionStorage - L'utilisateur est redirigé vers le serveur d'auth externe (p. ex.,
login.example.com) - Le serveur d'auth redirige vers l'URL de callback de l'SPA avec
?code=...&state=... - L'SPA tente d'échanger le code mais ne trouve pas le vérificateur PKCE
- Le message d'erreur parle de « session not found » ou « missing verifier », PAS de stockage
- Fonctionne bien en développement local (same-origin), échoue en production (cross-origin)
Cause Racine
sessionStorage est limité par onglet ET par origine, avec une fragilité supplémentaire :
- Si le serveur d'auth ouvre un nouvel onglet ou popup, le nouvel onglet a un sessionStorage vide
- Certains navigateurs (notamment Safari avec ITP) peuvent effacer sessionStorage pendant des chaînes de navigation cross-origin
- Si le serveur d'auth fait plusieurs redirections (chaînes 302), certains navigateurs traitent le retour comme un nouveau contexte de navigation
- Les navigateurs mobiles sont particulièrement agressifs pour effacer sessionStorage
Solution
Passer de sessionStorage à localStorage pour le stockage du vérificateur de code PKCE :
// AVANT (fragile)
const client = createOAuthClient({
storage: sessionStorage,
});
// APRÈS (fiable)
const client = createOAuthClient({
storage: localStorage,
});
La préoccupation de sécurité avec localStorage (le vérificateur persiste plus longtemps) est atténuée car :
- Le vérificateur PKCE ne s'utilise qu'une seule fois ; le serveur d'auth le rejette après le premier échange
- La plupart des SDK OAuth nettoient le vérificateur après un
exchangeCode()réussi getAuthorizationUrl()écrase tout vérificateur obsolète au démarrage d'un nouveau flux
Vérification
- Démarrer le flux OAuth sur l'SPA
- Compléter l'auth sur le serveur externe
- Le callback devrait échanger le code avec succès sans erreurs « session not found »
- Vérifier
localStorage— la clédivine_pkce(ou équivalente) devrait être nettoyée après un échange réussi
Exemple
D'après l'intégration du SDK @divinevideo/login :
function createClient() {
return createDivineClient({
serverUrl: 'https://login.divine.video',
clientId: 'divine-web',
redirectUri: buildCallbackUrl(),
// localStorage survit aux redirections cross-origin plus fiablement que sessionStorage
storage: localStorage,
});
}
Notes
- Si le SDK OAuth n'accepte pas de paramètre
storage, vous devrez peut-être stocker/récupérer manuellement le vérificateur dans localStorage et le passer àexchangeCode(verifier) - Déplacez également toute donnée de chemin de retour ou d'état de sessionStorage vers localStorage si elle doit survivre à la redirection
- Dans les environnements de test (jsdom/vitest),
localStoragepeut ne pas être complètement implémenté ; fournissez un stub Storage en mémoire dans la configuration de test - Le README du SDK recommande souvent localStorage — consultez la documentation avant de choisir sessionStorage par défaut pour des raisons de « sécurité »