# Correspondance draco par utilisateur (HUB-16, 0.46.0) Kanbante participe au SSO de la suite dracodev : ObsiGate émet le cookie `draco_session` (JWS HS256, claims `sub`, `name`, `iat`, `exp`, `jti`), Kanbante le valide localement (`app/draco.py`) et le pont `GET /auth/draco` le convertit en session Kanbante native. Depuis la 0.46.0, un jeton draco valide désigne **le compte Kanbante de cette identité** — et aucun autre. L'ancienne hypothèse mono-utilisateur (« un jeton valide = l'opérateur ») a disparu. C'est ce qui fait tenir le critère de la suite : « un compte créé fonctionne dans toutes les applications ». ## Où vit la correspondance Dans le modèle existant des comptes : la colonne **`users.draco_sub`** (texte, `UNIQUE`, présente depuis la 0.24.0) porte le `sub` draco lié à chaque compte Kanbante. `models.get_user_by_draco(sub)` est la résolution canonique ; la règle de décision complète vit dans `app.accounts.resolve_draco_user()`, seul point d'entrée du pont et du contrôle draco de `/api/search`. La correspondance est donc biunivoque : un `sub` ↔ un compte, garanti par la contrainte d'unicité. ## Résolution d'une connexion draco (`/auth/draco`) Dans l'ordre : 1. **Session native déjà ouverte** : si le navigateur porte à la fois une session Kanbante et un cookie draco dont le `sub` n'est lié à aucun compte, le `sub` est lié au compte de la session (première visite doublement connectée — mécanisme historique, inchangé, aussi appliqué à la connexion native dans `login_submit`). 2. **Correspondance existante** : la session du compte lié est ouverte. Un compte **désactivé** n'ouvre aucune session et n'est jamais contourné (voir § Désactivation). 3. **Compte d'amorçage** : s'il n'existe qu'**un seul compte** et que c'est un **admin actif sans liaison**, le premier `sub` valide s'y lie et sa session est ouverte. C'est le cas du compte créé à l'installation depuis l'environnement (`KANBANTE_AUTH_USER` / `KANBANTE_AUTH_PASSWORD`, Bruno) : sa correspondance s'établit au premier passage, sans le verrouiller dehors. Ses autres accès restent inchangés dans tous les cas : connexion native avec le mot de passe du compte, et repli d'urgence par les identifiants d'environnement (formulaire et Basic), qui ne dépendent pas de draco. 4. **Création JIT** : sinon, un compte Kanbante est créé pour cette identité (détail ci-dessous) et sa session est ouverte. Un `sub` inconnu n'ouvre **jamais** la session de l'opérateur d'environnement ni celle d'un compte existant non lié — y compris si le nom affiché draco ressemble au nom d'un compte local : le JIT crée toujours un compte **nouveau** (nom suffixé `-2`, `-3`… en cas de collision), jamais une adoption. ## Création JIT (juste-à-temps) À la première connexion draco d'une identité sans correspondance : - **nom d'utilisateur** : nom affiché des claims slugifié (`Alice Exemple` → `alice-exemple`), libre ou suffixé ; repli `draco-` si le nom est inexploitable ; - **nom d'affichage** : le `name` des claims ; - **rôle** : `member` (utilisateur standard) — jamais admin ; - **mot de passe local** : secret aléatoire, haché (PBKDF2 comme tous les comptes), **jamais divulgué** — l'accès normal passe par draco. Un administrateur peut ensuite poser un mot de passe local depuis `/admin` (bouton « Réinitialiser ») si un accès local est voulu ; - **espace** : le compte rejoint l'espace Principal comme membre, comme tout utilisateur créé par l'administration ; - le geste est journalisé (`draco.jit` dans le journal d'administration). ## Liaison par l'administrateur (comptes préexistants) Pour associer un compte Kanbante existant à une identité draco sans attendre un premier passage : 1. Se connecter à Kanbante avec un compte **admin**. 2. Ouvrir **Administration** (`/admin`), section **Utilisateurs**. 3. Dans la colonne **Draco (sub)** du compte visé, saisir le `sub` draco de l'identité (l'identifiant du compte de suite chez l'émettrice, ObsiGate) et cliquer **Lier**. 4. La liaison est immédiate et journalisée (`draco.link.admin`). Le bouton **Délier** de la même colonne la retire (`draco.unlink.admin`). Gardes : un `sub` déjà lié à un autre compte est refusé avec un message d'erreur (délier l'autre compte d'abord). L'administrateur peut lier **son propre** compte — c'est la voie manuelle pour le compte d'amorçage si le premier passage ne l'a pas lié. Chaque utilisateur peut aussi voir sa propre liaison dans **Mon profil → Liaison draco (SSO)** et la délier lui-même. > Le registre matriciel des rôles par application côté Hub > (carte HUB-19) lira cette correspondance ; la présente carte ne > livre que le côté Kanbante, qui est la source de vérité locale. ## Surfaces voisines - **`GET /api/search`** (« Rechercher partout ») : le cookie draco n'y est plus accepté « en tant qu'opérateur ». Il faut que le `sub` désigne un compte (correspondance existante ou compte d'amorçage lié au passage). Aucune création JIT sur cette surface : la création a lieu à la première vraie connexion, par le pont. Les autres modes d'accès à `/api/search` (session, Basic, jeton `kbt_`) sont inchangés. - **Désactivation** : désactiver un compte dans `/admin` coupe tous ses accès — session native, pont draco (la correspondance résout à « refusé ») et jetons `kbt_`. Réactiver le compte rétablit la correspondance telle quelle. ## Non-régressions garanties - **Jetons personnels `kbt_`** : création, usage sur `/mcp` et `/api/`, révocation — inchangés ; un jeton n'ouvre toujours pas l'interface web. - **Sessions propres Kanbante** et **connexion native** (formulaire, mot de passe de la base) : inchangées, y compris la liaison automatique à la première visite doublement connectée. - **Authentification Basic** (identifiants d'environnement, pour les scripts) : inchangée. - **Pont inerte sans `DRACO_SESSION_SECRET`** : sans secret configuré, `/auth/draco` renvoie au login, comme avant. - La réconciliation Kanbante/Gitea par étiquettes (adoption d'une colonne seulement si exactement une étiquette `kanban:*` est reconnue) n'est pas touchée par cette carte.