# #217 — Validation locale du jeton draco_session (Fusion ACC-3.2) Statut : ✅ livré le 2026-10-21 (2.72.0) ## Contexte Suite de l'émettrice SSO (#216, ACC-3.1). Ici, ObsiGate joue son rôle de **consommatrice** : `get_current_user` accepte le cookie partagé `draco_session` à défaut de jeton natif valide. C'est la brique qui servira aussi à l'API de l'agent commun (ACC-4) pour authentifier les requêtes SSO. Les validateurs des autres applications sont leurs tickets respectifs (Flowdeck #21, TikTak #213 — TikTak 0.52.0). ## Correspondance sub → compte local ObsiGate est émettrice ET consommatrice : le `sub` du jeton **est** son identifiant d'utilisateur — la résolution est directe, par `id`, dans `draco_session.user_for_draco()` : - signature/expiration/révocation vérifiées par `verify_token` (#216) ; - compte **actif** exigé ; - garde-fou BUG-028 appliqué à l'identique : un jeton draco émis avant le dernier changement de mot de passe (`password_changed_at`) est refusé ; - le dict utilisateur retourné porte `_token_vaults` (droits du compte), `_token_scope = "full"` et `_draco_sub` (traçabilité). ## Branchement Dans `backend/auth/middleware.py`, chaque sortie « non authentifié » du chemin natif (aucun jeton, jeton illisible, jti natif révoqué, compte introuvable/inactif, jeton antérieur au changement de mot de passe) passe par `_draco_fallback()`. Sûreté du repli après déconnexion globale : le logout révoque aussi le `jti` draco et efface le cookie (#216), donc un ancien cookie rejoué est refusé par `verify_token`. ## Limite connue Le repli authentifie les **appels d'API**. Le bootstrap d'une session complète du SPA (jetons natifs émis à partir du seul cookie draco) n'est pas couvert : pour ObsiGate, émettrice, la connexion native EST la connexion SSO — le cas d'usage du repli est la continuité d'API quand le jeton natif a expiré avant le cookie partagé, et les consommateurs machine de l'API. ## Tests `tests/test_draco_session.py` (+4) : `/api/auth/me` avec le seul cookie draco (200, bon utilisateur), jti révoqué refusé, sub inconnu refusé, inactivité sans secret configuré.