Skip to content

Auth Flows

Módulos API: auth, users · Páginas web: LoginPage, RegisterPage, OAuthCallback Specs Playwright: apps/e2e/tests/auth/ — 📋 pendientes de crear


US-AUTH-001: Registro con email y contraseña

Section titled “US-AUTH-001: Registro con email y contraseña”

Como visitante no registrado Quiero crear una cuenta con mi email y una contraseña Para acceder a la plataforma y comenzar a aprender

Criterios: AC-AUTH-001 · Casos: TC-AUTH-001 · Prioridad: Alta · ✅ Implementado


US-AUTH-002: Login con email y contraseña

Section titled “US-AUTH-002: Login con email y contraseña”

Como usuario registrado Quiero iniciar sesión con mis credenciales Para acceder a mi cuenta y continuar mi progreso

Criterios: AC-AUTH-002 · Casos: TC-AUTH-003 · Prioridad: Alta · ✅ Implementado


Como visitante con cuenta de Google Quiero iniciar sesión con OAuth de Google Para no gestionar una contraseña separada

Criterios: AC-AUTH-003 · Casos: TC-AUTH-005 · Prioridad: Alta · ✅ Implementado


Como visitante con cuenta de LinkedIn Quiero iniciar sesión con OAuth de LinkedIn Para acceder usando mi identidad profesional

Criterios: AC-AUTH-004 · Casos: TC-AUTH-006 · Prioridad: Media · ✅ Implementado


Como usuario registrado que olvidó su contraseña Quiero recibir un enlace de restablecimiento en mi email Para recuperar acceso sin intervención de soporte

Criterios: AC-AUTH-005 · Casos: TC-AUTH-007 · Prioridad: Alta · ✅ Implementado


Como usuario autenticado Quiero cerrar mi sesión en el dispositivo actual Para proteger mi cuenta en dispositivos compartidos

Criterios: AC-AUTH-006 · Casos: TC-AUTH-009 · Prioridad: Media · ✅ Implementado


Como usuario autenticado que cierra el navegador Quiero que mi sesión persista al volver a abrir la aplicación Para no autenticarme en cada visita

Criterios: AC-AUTH-007 · Casos: TC-AUTH-007 · Prioridad: Media · ✅ Implementado


US-AUTH-008: Redirección al acceder a ruta protegida sin sesión

Section titled “US-AUTH-008: Redirección al acceder a ruta protegida sin sesión”

Como visitante no autenticado Quiero ser redirigido al login al intentar acceder a rutas protegidas Para ser guiado hacia la autenticación en lugar de ver un error

Criterios: AC-AUTH-008 · Casos: TC-AUTH-010 · Prioridad: Alta · ✅ Implementado


AC-AUTH-001: Registro con email y contraseña

Section titled “AC-AUTH-001: Registro con email y contraseña”

US: US-AUTH-001

AC-AUTH-001.1 — Registro exitoso

Dado que soy un visitante no registrado
Cuando introduzco un email único válido y una contraseña que cumple los requisitos
Y envío el formulario de registro
Entonces se crea mi cuenta con rol FREE
Y soy redirigido al dashboard de estudiante
Y recibo un email de bienvenida

AC-AUTH-001.2 — Email ya registrado

Dado que ya existe una cuenta con el email "test@example.com"
Cuando intento registrarme con ese mismo email
Entonces veo un error indicando que el email ya está registrado
Y no se crea ninguna cuenta nueva
Y la API responde con status 409

AC-AUTH-001.3 — Contraseña inválida

Dado que estoy en el formulario de registro
Cuando introduzco una contraseña que no cumple los requisitos mínimos
Entonces veo el mensaje de validación con los requisitos
Y el formulario no se envía

AC-AUTH-002: Login con email y contraseña

Section titled “AC-AUTH-002: Login con email y contraseña”

US: US-AUTH-002

AC-AUTH-002.1 — Login exitoso

Dado que tengo una cuenta registrada con email y contraseña
Cuando introduzco mis credenciales correctas
Entonces inicio sesión y soy redirigido al dashboard
Y el token JWT queda almacenado en el cliente

AC-AUTH-002.2 — Credenciales incorrectas (anti-enumeración)

Dado que introduzco una contraseña incorrecta para un email existente
Entonces recibo el mensaje "Credenciales incorrectas"
Y no se inicia sesión
Y el mensaje es idéntico al que se muestra para email inexistente

US: US-AUTH-003

AC-AUTH-003.1 — Primera vez (auto-registro)

Dado que soy visitante sin cuenta previa
Cuando autorizo el acceso con Google
Entonces se crea una cuenta con mi email de Google y rol FREE
Y soy redirigido al dashboard

AC-AUTH-003.2 — Cuenta existente (vinculación)

Dado que tengo cuenta previa con el mismo email de Google
Cuando autorizo el acceso con Google
Entonces inicio sesión en mi cuenta existente sin crear una nueva

AC-AUTH-003.3 — Usuario cancela el popup

Dado que hago clic en "Continuar con Google"
Cuando cancelo el popup de autorización
Entonces vuelvo al login sin error crítico

US: US-AUTH-004

AC-AUTH-004.1 — Primera vez

Dado que soy visitante sin cuenta previa
Cuando autorizo el acceso con LinkedIn
Entonces se crea una cuenta con mi email de LinkedIn y rol FREE

AC-AUTH-004.2 — Cuenta existente

Dado que tengo cuenta con el mismo email de LinkedIn
Cuando autorizo el acceso
Entonces inicio sesión en mi cuenta existente

US: US-AUTH-005

AC-AUTH-005.1 — Solicitud con email registrado

Dado que tengo cuenta con email y contraseña
Cuando solicito restablecer contraseña con mi email
Entonces recibo el mensaje de confirmación genérico
Y recibo un email con enlace de un solo uso válido 60 minutos

AC-AUTH-005.2 — Email no registrado (anti-enumeración)

Dado que introduzco un email no registrado
Entonces veo el mismo mensaje de confirmación que para email existente
Y no se envía ningún email

AC-AUTH-005.3 — Restablecimiento exitoso con token válido

Dado que tengo un enlace de restablecimiento válido
Cuando introduzco y confirmo una nueva contraseña válida
Entonces mi contraseña se actualiza
Y el enlace queda invalidado (no se puede reusar)
Y soy redirigido al login

AC-AUTH-005.4 — Token expirado

Dado que el enlace ha superado los 60 minutos de validez
Cuando intento acceder a él
Entonces veo el mensaje de enlace expirado
Y se me ofrece solicitar uno nuevo

US: US-AUTH-006

AC-AUTH-006.1 — Logout exitoso

Dado que tengo sesión activa
Cuando hago clic en "Cerrar sesión"
Entonces mi sesión queda invalidada en el cliente
Y soy redirigido a la página pública o al login

AC-AUTH-006.2 — Rutas protegidas bloqueadas tras logout

Dado que acabo de cerrar sesión
Cuando navego a "/dashboard"
Entonces soy redirigido al login
Y no veo ningún dato de la sesión anterior

US: US-AUTH-007

AC-AUTH-007.1 — Sesión persiste tras cerrar el navegador

Dado que tengo sesión activa
Cuando cierro y vuelvo a abrir la pestaña con la misma URL
Entonces sigo autenticado sin necesidad de hacer login

AC-AUTH-007.2 — Sesión expirada redirige al login

Dado que mi token JWT ha expirado
Cuando intento acceder a cualquier ruta protegida
Entonces soy redirigido al login

AC-AUTH-008: Redirección de rutas protegidas

Section titled “AC-AUTH-008: Redirección de rutas protegidas”

US: US-AUTH-008

AC-AUTH-008.1 — Redirección con returnUrl

Dado que soy visitante no autenticado
Cuando accedo directamente a "/dashboard/courses"
Entonces soy redirigido a "/login?returnUrl=/dashboard/courses"
Y tras autenticarme voy a la URL original

AC-AUTH-008.2 — Rutas públicas accesibles sin auth

Dado que soy visitante no autenticado
Cuando accedo a "/", "/login", "/register" o "/verify/{uuid}"
Entonces puedo verlas sin redirección

AC-AUTH-008.3 — Portal de rol incorrecto denegado

Dado que soy usuario con rol FREE
Cuando accedo directamente a "/admin"
Entonces veo pantalla de acceso denegado o soy redirigido
Y no veo ningún dato del panel admin

AC: AC-AUTH-001.1 · Prioridad: Alta · Tipo: E2E · Estado: 📋 Pendiente Spec: apps/e2e/tests/auth/register.spec.ts

Precondiciones: El email de prueba no existe en la BD (usar email único por ejecución: qa-${Date.now()}@nappai.test)

Pasos:

  1. Navegar a /register
  2. Introducir email único válido
  3. Introducir contraseña válida (≥8 chars, 1 mayúscula, 1 número)
  4. Enviar formulario

Resultado esperado: Redirige a /dashboard, API retorna 201, usuario tiene rol FREE

// data-testid a confirmar en el componente:
// 'register-email', 'register-password', 'register-submit', 'register-error'
const email = `qa-test-${Date.now()}@nappai.test`

TC-AUTH-002: Registro rechazado — email duplicado

Section titled “TC-AUTH-002: Registro rechazado — email duplicado”

AC: AC-AUTH-001.2 · Prioridad: Alta · Tipo: API · Estado: 📋 Pendiente Spec: apps/e2e/tests/auth/register.spec.ts

const res = await apiClient.post('/auth/register', {
email: fixtures.free.email,
password: 'ValidPass123!'
})
expect(res.status).toBe(409)

AC: AC-AUTH-002.1 · Prioridad: Alta · Tipo: E2E · Estado: 📋 Pendiente Spec: apps/e2e/tests/auth/login.spec.ts

Precondiciones: fixtures.free existe con credenciales email/password

// data-testid: 'login-email', 'login-password', 'login-submit'

TC-AUTH-004: Login rechazado — credenciales incorrectas

Section titled “TC-AUTH-004: Login rechazado — credenciales incorrectas”

AC: AC-AUTH-002.2 · Prioridad: Alta · Tipo: API · Estado: 📋 Pendiente

const res = await apiClient.post('/auth/login', {
email: fixtures.free.email, password: 'WrongPassword!'
})
expect(res.status).toBe(401)
// Verificar que el mensaje NO revela si el email existe:
expect(res.data.message).not.toMatch(/email|usuario/)

AC: AC-AUTH-003.1 · Prioridad: Alta · Tipo: Manual · Estado: ⚠️ Manual Nota: No automatizable directamente (popup real de Google). Considerar interceptar el callback OAuth.


TC-AUTH-006: Login LinkedIn — primera vez

Section titled “TC-AUTH-006: Login LinkedIn — primera vez”

AC: AC-AUTH-004.1 · Prioridad: Media · Tipo: Manual · Estado: ⚠️ Manual


TC-AUTH-007: Recuperación de contraseña — flujo completo

Section titled “TC-AUTH-007: Recuperación de contraseña — flujo completo”

AC: AC-AUTH-005.1 + AC-AUTH-005.3 · Prioridad: Alta · Tipo: API + Manual · Estado: 📋 Pendiente Spec: apps/e2e/tests/auth/password-reset.spec.ts

// Step 1: solicitar reset
const req = await apiClient.post('/auth/forgot-password', { email: fixtures.free.email })
expect(req.status).toBe(200)
// Step 2: obtener token (via BD de test o email mock)
// Step 3: usar el token
const reset = await apiClient.post('/auth/reset-password', { token, password: 'NewPass123!' })
expect(reset.status).toBe(200)
// Step 4: verificar que el token no se puede reusar
const reuse = await apiClient.post('/auth/reset-password', { token, password: 'AnotherPass123!' })
expect(reuse.status).toBe(400)

TC-AUTH-008: Token de restablecimiento expirado

Section titled “TC-AUTH-008: Token de restablecimiento expirado”

AC: AC-AUTH-005.4 · Prioridad: Media · Tipo: API · Estado: 📋 Pendiente

const res = await apiClient.post('/auth/reset-password', { token: 'expired-token-xxx', password: 'NewPass123!' })
expect(res.status).toBe(400)

AC: AC-AUTH-006.2 · Prioridad: Alta · Tipo: E2E · Estado: 📋 Pendiente Spec: apps/e2e/tests/auth/logout.spec.ts

// data-testid: 'user-menu', 'logout-button'
await loginAs(page, fixtures.free)
await page.getByTestId('user-menu').click()
await page.getByTestId('logout-button').click()
await page.goto('/dashboard')
await expect(page).toHaveURL(/\/login/)

TC-AUTH-010: Redirección al login con returnUrl

Section titled “TC-AUTH-010: Redirección al login con returnUrl”

AC: AC-AUTH-008.1 · Prioridad: Alta · Tipo: E2E · Estado: 📋 Pendiente Spec: apps/e2e/tests/auth/protected-routes.spec.ts

const page = await context.newPage() // sin sesión
await page.goto('/dashboard/courses')
await expect(page).toHaveURL(/\/login/)
await expect(page).toHaveURL(/returnUrl/)