oauth-pkce-sessionstorage-lost-on-redirect

Par divinevideo · divine-mobile

Corrigez les erreurs OAuth PKCE « Session not found » ou « No code verifier » dans les SPAs après redirection depuis un serveur d'authentification externe. À utiliser quand : (1) le callback OAuth échoue avec session/verifier introuvable malgré un démarrage correct du flux, (2) le `code_verifier` PKCE stocké dans `sessionStorage` est manquant après la redirection depuis le serveur d'authentification, (3) l'erreur ne se produit qu'en production ou lors de redirections cross-origin, pas en développement local. Cause racine : le `sessionStorage` est perdu lorsque le navigateur ouvre un nouvel onglet, change de contexte de navigation, ou que certains navigateurs l'effacent lors d'une navigation cross-origin. Correction : utiliser `localStorage` à la place (avec nettoyage après l'échange).

npx skills add https://github.com/divinevideo/divine-mobile --skill oauth-pkce-sessionstorage-lost-on-redirect

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 :

  1. Si le serveur d'auth ouvre un nouvel onglet ou popup, le nouvel onglet a un sessionStorage vide
  2. Certains navigateurs (notamment Safari avec ITP) peuvent effacer sessionStorage pendant des chaînes de navigation cross-origin
  3. Si le serveur d'auth fait plusieurs redirections (chaînes 302), certains navigateurs traitent le retour comme un nouveau contexte de navigation
  4. 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

  1. Démarrer le flux OAuth sur l'SPA
  2. Compléter l'auth sur le serveur externe
  3. Le callback devrait échanger le code avec succès sans erreurs « session not found »
  4. 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), localStorage peut 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é »

Skills similaires