[Majeur] Une seule session par utilisateur (un seul refresh token) #101

Closed
opened 2026-10-28 10:31:59 +00:00 by asventi · 0 comments
Owner

Gravité : Majeur
Rapports QA d'origine : AUTH-14, PROFILE-20

Se connecter sur un autre appareil coupe la session précédente ; un logout coupe toutes les sessions.

Détails des rapports

[AUTH-14] Il n'y a qu'une session par utilisateur : se reconnecter ailleurs déconnecte la précédente ; le logout d'un appareil les coupe tous — Gravité : Majeur
  • Où : POST /auth/login, GET /auth/logout, GET /me/tokens
  • Étapes : 1. Login de U depuis le client 1 puis depuis le client 2. 2. Le client 1 appelle GET /auth/refresh.
  • Obtenu : 401 REFRESH_TOKEN_UNKNOWN pour le client 1 (déconnecté à l'expiration de son access token, ≤ 10 min) ; GET /me/tokens ne renvoie jamais plus d'une entrée alors que l'endpoint est décrit "one per device still logged in". Inversement un logout depuis le client 1 supprime aussi la session du client 2 (sB2 : tokens []).
  • Cause probable : LoginUserCommand.cs:30-37 (supprime le refresh existant), LogoutQuery.cs:12 (SingleOrDefault(r.UserId == id)).
[PROFILE-20] Changement de mot de passe : les autres sessions restent valides jusqu'à 10 min (access token), seul le refresh est révoqué ; un seul refresh token par user — Gravité : Mineur
  • Où : PATCH /api/me/password, POST /api/auth/login
  • Étapes : 1. Deux sessions A et B du même user. 2. A change le mot de passe. 3. B : GET /api/me -> 200 (valide encore ~10 min) ; GET /api/auth/refresh -> 401 "Refresh token unknown" (cookies effacés). Ancien mdp -> 406, nouveau -> 200 : OK.
  • Obtenu / limite : après un changement de mot de passe (ex. compte compromis), la session de l'attaquant reste utilisable jusqu'à expiration du JWT. Inversement, se connecter une 2e fois (autre appareil) remplace la ligne RefreshToken : la 1re session ne peut plus se rafraîchir et est déconnectée à l'expiration de son access token (pas de multi-appareils).
  • Cause probable : backend/API/Auth/Login/LoginUserCommand.cs:28-36 (une seule ligne RefreshToken par user), Auth/Token/TokenProvider.cs:34 (JWT 10 min sans révocation).
  • UI : après changement, l'utilisateur est bien déconnecté et redirigé vers /login ; pas de champ "confirmation du nouveau mot de passe" (cas "confirmation différente" non applicable).

Trouvé par une campagne de tests QA automatisés (agents Claude, Playwright) sur l'environnement de dev. Les captures citées sont locales et non jointes.

**Gravité :** Majeur **Rapports QA d'origine :** AUTH-14, PROFILE-20 Se connecter sur un autre appareil coupe la session précédente ; un logout coupe toutes les sessions. ## Détails des rapports <details><summary>[AUTH-14] Il n'y a qu'une session par utilisateur : se reconnecter ailleurs déconnecte la précédente ; le logout d'un appareil les coupe tous — Gravité : Majeur</summary> - Où : `POST /auth/login`, `GET /auth/logout`, `GET /me/tokens` - Étapes : 1. Login de U depuis le client 1 puis depuis le client 2. 2. Le client 1 appelle `GET /auth/refresh`. - Obtenu : 401 `REFRESH_TOKEN_UNKNOWN` pour le client 1 (déconnecté à l'expiration de son access token, ≤ 10 min) ; `GET /me/tokens` ne renvoie jamais plus d'une entrée alors que l'endpoint est décrit "one per device still logged in". Inversement un logout depuis le client 1 supprime aussi la session du client 2 (`sB2` : tokens `[]`). - Cause probable : `LoginUserCommand.cs:30-37` (supprime le refresh existant), `LogoutQuery.cs:12` (`SingleOrDefault(r.UserId == id)`). </details> <details><summary>[PROFILE-20] Changement de mot de passe : les autres sessions restent valides jusqu'à 10 min (access token), seul le refresh est révoqué ; un seul refresh token par user — Gravité : Mineur</summary> - Où : `PATCH /api/me/password`, `POST /api/auth/login` - Étapes : 1. Deux sessions A et B du même user. 2. A change le mot de passe. 3. B : `GET /api/me` -> 200 (valide encore ~10 min) ; `GET /api/auth/refresh` -> 401 "Refresh token unknown" (cookies effacés). Ancien mdp -> 406, nouveau -> 200 : OK. - Obtenu / limite : après un changement de mot de passe (ex. compte compromis), la session de l'attaquant reste utilisable jusqu'à expiration du JWT. Inversement, se connecter une 2e fois (autre appareil) remplace la ligne RefreshToken : la 1re session ne peut plus se rafraîchir et est déconnectée à l'expiration de son access token (pas de multi-appareils). - Cause probable : `backend/API/Auth/Login/LoginUserCommand.cs:28-36` (une seule ligne RefreshToken par user), `Auth/Token/TokenProvider.cs:34` (JWT 10 min sans révocation). - UI : après changement, l'utilisateur est bien déconnecté et redirigé vers /login ; pas de champ "confirmation du nouveau mot de passe" (cas "confirmation différente" non applicable). </details> --- _Trouvé par une campagne de tests QA automatisés (agents Claude, Playwright) sur l'environnement de dev. Les captures citées sont locales et non jointes._
asventi self-assigned this 2026-10-29 16:50:27 +00:00
asventi stopped working 2026-10-29 17:42:06 +00:00
29 minutes 50 seconds
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Total time spent: 29 minutes 50 seconds
asventi
29 minutes 50 seconds
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transcendence/backend#101
No description provided.