# US-MGN001-002: Logout y Cierre de Sesion ## Identificacion | Campo | Valor | |-------|-------| | **ID** | US-MGN001-002 | | **Modulo** | MGN-001 Auth | | **Sprint** | Sprint 1 | | **Prioridad** | P0 - Critica | | **Story Points** | 5 | | **Estado** | Ready | | **Autor** | System | | **Fecha** | 2025-12-05 | --- ## Historia de Usuario **Como** usuario autenticado del sistema ERP **Quiero** poder cerrar mi sesion de forma segura **Para** proteger mi cuenta cuando dejo de usar el sistema o en dispositivos compartidos --- ## Descripcion El usuario necesita poder cerrar su sesion actual, revocando los tokens de acceso para que no puedan ser reutilizados. Tambien debe poder cerrar todas sus sesiones activas en caso de sospecha de compromiso de cuenta. ### Contexto - Seguridad en dispositivos compartidos - Cumplimiento de politicas corporativas - Proteccion contra robo de tokens --- ## Criterios de Aceptacion ### Escenario 1: Logout exitoso ```gherkin Given un usuario autenticado con sesion activa And tiene un access token valido And tiene un refresh token en cookie When el usuario hace POST /api/v1/auth/logout Then el sistema responde con status 200 And el mensaje es "Sesion cerrada exitosamente" And el refresh token es revocado en BD And el access token es agregado a la blacklist And la cookie refresh_token es eliminada And se registra el logout en session_history ``` ### Escenario 2: Logout de todas las sesiones ```gherkin Given un usuario autenticado And tiene 3 sesiones activas en diferentes dispositivos When el usuario hace POST /api/v1/auth/logout-all Then el sistema responde con status 200 And el mensaje es "Todas las sesiones han sido cerradas" And el response incluye "sessionsRevoked": 3 And TODOS los refresh tokens del usuario son revocados And se registra el logout_all en session_history ``` ### Escenario 3: Logout sin autenticacion ```gherkin Given un usuario sin token de acceso When intenta hacer logout Then el sistema responde con status 401 And el mensaje es "Token requerido" ``` ### Escenario 4: Logout con token expirado ```gherkin Given un usuario con access token expirado And tiene refresh token valido en cookie When intenta hacer logout Then el sistema permite el logout usando solo el refresh token And responde con status 200 ``` ### Escenario 5: Verificacion post-logout ```gherkin Given un usuario que acaba de hacer logout When intenta acceder a un endpoint protegido With el access token anterior Then el sistema responde con status 401 And el mensaje es "Token revocado" ``` --- ## Mockup / Wireframe ``` +------------------------------------------------------------------+ | [Logo] [Usuario ▼] | +------------------------------------------------------------------+ ┌─────────────────┐ │ Mi Perfil │ │ Configuracion │ │ ─────────────── │ │ Cerrar Sesion │ ← Click │ Cerrar Todas │ └─────────────────┘ ┌──────────────────────────────────────────────────────────────────┐ │ CONFIRMACION DE LOGOUT │ ├──────────────────────────────────────────────────────────────────┤ │ │ │ ¿Estas seguro que deseas cerrar sesion? │ │ │ │ [ Cancelar ] [ Cerrar Sesion ] │ │ │ └──────────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────────┐ │ CERRAR TODAS LAS SESIONES │ ├──────────────────────────────────────────────────────────────────┤ │ │ │ ⚠️ Esta accion cerrara tu sesion en todos los dispositivos. │ │ │ │ Sesiones activas: 3 │ │ - Chrome (Windows) - Hace 2 horas │ │ - Firefox (Mac) - Hace 1 dia │ │ - Safari (iPhone) - Ahora │ │ │ │ [ Cancelar ] [ Cerrar Todas ] │ │ │ └──────────────────────────────────────────────────────────────────┘ ``` --- ## Notas Tecnicas ### API ```typescript // Logout individual POST /api/v1/auth/logout Authorization: Bearer eyJhbGciOiJSUzI1NiIs... Cookie: refresh_token=eyJhbGciOiJSUzI1NiIs... // Response 200 { "message": "Sesion cerrada exitosamente" } // Set-Cookie: refresh_token=; Max-Age=0; HttpOnly; Secure; SameSite=Strict // Logout all POST /api/v1/auth/logout-all Authorization: Bearer eyJhbGciOiJSUzI1NiIs... // Response 200 { "message": "Todas las sesiones han sido cerradas", "sessionsRevoked": 3 } ``` ### Flujo de Logout ``` ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Frontend │ │ Backend │ │ Redis │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ │ POST /logout │ │ │───────────────────>│ │ │ │ │ │ │ Revoke refresh │ │ │ token in DB │ │ │ │ │ │ Blacklist access │ │ │───────────────────>│ │ │ │ │ │ Delete cookie │ │ │ │ │ 200 OK │ │ │<───────────────────│ │ │ │ │ │ Clear local state │ │ │ Redirect to login │ │ │ │ │ ``` ### Seguridad - Blacklist en Redis con TTL - Logout idempotente (no falla si ya esta logged out) - Rate limiting: 10 requests/minuto --- ## Definicion de Done - [ ] Endpoint POST /api/v1/auth/logout implementado - [ ] Endpoint POST /api/v1/auth/logout-all implementado - [ ] Refresh token revocado en BD - [ ] Access token blacklisteado en Redis - [ ] Cookie eliminada correctamente - [ ] Registro en session_history - [ ] Frontend limpia estado local - [ ] Frontend redirige a login - [ ] Tests unitarios (>80% coverage) - [ ] Tests e2e pasando - [ ] Code review aprobado --- ## Dependencias ### Requiere | Item | Descripcion | |------|-------------| | US-MGN001-001 | Login (sesion activa) | | BlacklistService | Para invalidar tokens | | Redis | Para almacenar blacklist | ### Bloquea | Item | Descripcion | |------|-------------| | - | No bloquea otras historias | --- ## Estimacion | Tarea | Horas | |-------|-------| | Backend: logout() | 2h | | Backend: logoutAll() | 2h | | Backend: Tests | 2h | | Frontend: Logout button | 1h | | Frontend: Confirmation modal | 2h | | Frontend: Tests | 1h | | **Total** | **10h** | --- ## Referencias - [RF-AUTH-004](../../01-requerimientos/RF-auth/RF-AUTH-004.md) - Requerimiento funcional - [ET-auth-backend](../../02-modelado/especificaciones-tecnicas/ET-auth-backend.md) - Spec tecnica --- ## Historial | Version | Fecha | Autor | Cambios | |---------|-------|-------|---------| | 1.0 | 2025-12-05 | System | Creacion inicial |