4.5 KiB
4.5 KiB
Smoke Test — UDT-002: Logout + Refresh Token
Branch: feature/UDT-002
Fecha: 2026-04-14
Prerequisito: backend corriendo en http://localhost:5212, BD SIGCM2 con migración V002 aplicada.
Escenario 1 — Login y persistencia de tokens
- Abrir la app en
http://localhost:5173 - Ingresar con credenciales válidas (admin / password)
- Verificar que el login redirige al home
- Abrir DevTools → Application → Local Storage →
auth-storage - Confirmar que el objeto contiene:
accessToken,refreshToken,expiresAt,user - Verificar que
expiresAtes aproximadamenteDate.now() + 3600000(1 hora)
Escenario 2 — Refresh transparente en 401
Opción A (esperar expiración natural — requiere token con TTL corto):
- Modificar
Jwt:AccessTokenMinutesa1enappsettings.Development.jsony reiniciar el backend - Hacer login
- Esperar 1 minuto para que el access token expire
- Realizar cualquier request autenticado (ej: navegar a una sección que llame a la API)
- Verificar que el request se completa sin error visible para el usuario
- Verificar en DevTools → Network que hubo una llamada a
POST /api/v1/auth/refreshseguida del request original reenviado con un nuevo Bearer
Opción B (manipulación manual del token):
- Después del login, abrir DevTools → Application → Local Storage →
auth-storage - Editar el JSON y reemplazar
accessTokencon un valor inválido (ej:"expired") - Realizar cualquier request autenticado
- El interceptor de axiosClient recibe 401, llama a
/refreshcon elrefreshTokenreal - El request original se reintenta automáticamente con el nuevo
accessToken - El usuario no ve ningún error
Escenario 3 — Refresh de 3 requests paralelos (singleton promise)
- Con el access token vencido (opción B del escenario 2)
- Abrir una página que dispare múltiples llamadas API simultáneas
- Verificar en DevTools → Network que hay exactamente 1 llamada a
POST /api/v1/auth/refresh - Verificar que todos los requests subsiguientes retornan con éxito
Escenario 4 — Logout
- Con sesión activa, hacer click en el botón de logout
- Verificar que redirige a
/login - Verificar en DevTools → Network que se llamó a
POST /api/v1/auth/logout - Verificar en Local Storage que
auth-storagetieneuser: null,accessToken: null,refreshToken: null - Intentar navegar a una ruta protegida — debería redirigir a login
Escenario 5 — Reuso de refresh token después del logout (reuse detection)
- Hacer login y copiar el valor de
refreshTokendel Local Storage - Hacer logout
- Intentar llamar manualmente al endpoint de refresh con el token anterior:
curl -X POST http://localhost:5212/api/v1/auth/refresh \ -H "Content-Type: application/json" \ -d '{"accessToken": "<access-anterior>", "refreshToken": "<refresh-anterior>"}' - Verificar que el backend responde
401con{ "error": "invalid_token" } - Verificar en la BD que todos los tokens de la familia fueron revocados:
SELECT * FROM dbo.RefreshToken WHERE RevokedAt IS NOT NULL ORDER BY Id DESC;
Escenario 6 — Refresh token expirado (7 días)
- Modificar
ExpiresAtde un token en la BDSIGCM2_Testa una fecha pasada - Intentar refresh con ese token — debería responder
401 - Verificar que el frontend redirige a
/loginy limpia el Local Storage
Escenario 7 — Refresh con access token de otro usuario (mismatch)
- Crear dos usuarios en la BD (o usar admin + otro)
- Hacer login con usuario A, guardar el
accessToken - Hacer login con usuario B, guardar el
refreshToken - Intentar refresh con accessToken de A + refreshToken de B:
curl -X POST http://localhost:5212/api/v1/auth/refresh \ -H "Content-Type: application/json" \ -d '{"accessToken": "<access-usuario-A>", "refreshToken": "<refresh-usuario-B>"}' - Verificar que el backend responde
401
Notas de verificación
| Check | Comando |
|---|---|
| Tokens en BD | SELECT Id, UsuarioId, FamilyId, IssuedAt, ExpiresAt, RevokedAt FROM dbo.RefreshToken ORDER BY Id DESC |
| Familias revocadas | SELECT FamilyId, COUNT(*) as Total, SUM(CASE WHEN RevokedAt IS NOT NULL THEN 1 ELSE 0 END) as Revoked FROM dbo.RefreshToken GROUP BY FamilyId |
| Usuario activo | SELECT Id, Username, Activo FROM dbo.Usuario |