[debt] Autenticación y guards por rol en el API #5

Open
opened 2026-10-02 17:35:58 +00:00 by Carlos · 0 comments
Member

Qué es la deuda

El API no tiene ningún guard. POST /auth/login solo devuelve el usuario, que el front guarda en sessionStorage (apps/web/src/app/_core/hooks/use-session-user.ts). El rol se revisa únicamente en el cliente (user.role === "admin" en page.tsx, pos-shell.tsx, user-login-screen.tsx).

Además, el usuario que ejecuta cada acción viaja en el body (userId, openedById, closedById) y el servidor lo acepta tal cual.

Qué estamos pagando hoy

  • Cualquiera con acceso a la red puede llamar GET /api/users, DELETE /api/payments/:id, etc., sin iniciar sesión.
  • Un cajero puede hacer operaciones de administrador llamando al API directamente.
  • Los registros de quién abrió o cerró una caja o un día no son confiables.

Confirmado en caja negra (2026-10-02)

Contra localhost:3000, sin ninguna sesión ni token, respondieron 200 con datos: GET /api/users (incluye email), /api/payments, /api/cash-movements, /api/cash-register-sessions, /api/operating-days, /api/shop-carts, /api/customers, /api/suppliers, /api/products. El login no devuelve cookie ni token (Set-Cookie/Authorization ausentes): la "sesión" vive solo en sessionStorage del cliente. Ver también #26 (crear admin sin sesión) y la falta de rate limiting en /api/auth/login (no se probó a fondo).

Arreglo propuesto

  • Emitir una sesión (cookie httpOnly) o JWT en el login.
  • AuthGuard global y RolesGuard con decorador @Roles(UserRole.admin).
  • Tomar el usuario actual del token en el servidor en vez del body.
  • GET /users para el selector de login devuelve solo id y name.

Criterios de aceptación:

  • Ningún endpoint (salvo login y health) responde sin autenticación
  • Los endpoints de admin rechazan a cajeros
  • El servidor determina el usuario que ejecuta la acción

Techo de esta ronda

Autenticación por sesión o JWT y dos roles (admin, cashier). Fuera: permisos finos por sucursal, recuperación de contraseña y bloqueo por intentos fallidos.

Superficie

API (apps/api)

Módulos

Auth / sesión / roles, API / backend, Web / frontend, Usuarios

Esfuerzo

L — partir; este issue solo cubre el primer corte

Riesgo de no tocarlo

Alto (seguridad, datos, o bloquea el próximo corte)

### Qué es la deuda El API no tiene ningún guard. `POST /auth/login` solo devuelve el usuario, que el front guarda en `sessionStorage` (`apps/web/src/app/_core/hooks/use-session-user.ts`). El rol se revisa únicamente en el cliente (`user.role === "admin"` en `page.tsx`, `pos-shell.tsx`, `user-login-screen.tsx`). Además, el usuario que ejecuta cada acción viaja en el body (`userId`, `openedById`, `closedById`) y el servidor lo acepta tal cual. ### Qué estamos pagando hoy - Cualquiera con acceso a la red puede llamar `GET /api/users`, `DELETE /api/payments/:id`, etc., sin iniciar sesión. - Un cajero puede hacer operaciones de administrador llamando al API directamente. - Los registros de quién abrió o cerró una caja o un día no son confiables. ### Confirmado en caja negra (2026-10-02) Contra `localhost:3000`, sin ninguna sesión ni token, respondieron `200` con datos: `GET /api/users` (incluye email), `/api/payments`, `/api/cash-movements`, `/api/cash-register-sessions`, `/api/operating-days`, `/api/shop-carts`, `/api/customers`, `/api/suppliers`, `/api/products`. El login no devuelve cookie ni token (`Set-Cookie`/`Authorization` ausentes): la "sesión" vive solo en `sessionStorage` del cliente. Ver también #26 (crear admin sin sesión) y la falta de rate limiting en `/api/auth/login` (no se probó a fondo). ### Arreglo propuesto - Emitir una sesión (cookie httpOnly) o JWT en el login. - `AuthGuard` global y `RolesGuard` con decorador `@Roles(UserRole.admin)`. - Tomar el usuario actual del token en el servidor en vez del body. - `GET /users` para el selector de login devuelve solo `id` y `name`. Criterios de aceptación: - [ ] Ningún endpoint (salvo login y health) responde sin autenticación - [ ] Los endpoints de admin rechazan a cajeros - [ ] El servidor determina el usuario que ejecuta la acción ### Techo de esta ronda Autenticación por sesión o JWT y dos roles (`admin`, `cashier`). Fuera: permisos finos por sucursal, recuperación de contraseña y bloqueo por intentos fallidos. ### Superficie API (apps/api) ### Módulos Auth / sesión / roles, API / backend, Web / frontend, Usuarios ### Esfuerzo L — partir; este issue solo cubre el primer corte ### Riesgo de no tocarlo Alto (seguridad, datos, o bloquea el próximo corte)
Carlos changed title from Autenticación y guards por rol en el API to [debt] Autenticación y guards por rol en el API 2026-10-02 17:42:58 +00:00
Carlos self-assigned this 2026-10-02 20:07:25 +00:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RynextTechnologies/PDV#5