Autenticación¶
Dos modos, la misma superficie¶
| Database | Keycloak | |
|---|---|---|
| Dónde viven los usuarios | Un schema auth en tu base de datos |
Keycloak |
| Quién firma los tokens | La propia API (SECRET_KEY, HS256) |
Keycloak, y la API los valida en local |
| Login | Usuario y contraseña | Usuario y contraseña, o por redirección con PKCE (SSO, MFA, login social) |
| Qué hace falta | PostgreSQL y el extra database |
Un Keycloak y el extra rbac |
Los dos exponen las mismas rutas, los mismos modelos y los mismos permisos: un endpoint generado no sabe con cuál está funcionando, y un frontend tampoco.
tai-api auth init # elige el modo y lo configura
tai-api auth status # qué hay configurado
tai-api auth switch # cambia de un modo al otro
auth init escribe la configuración, crea rbac/<realm>.py y regenera la autenticación, el
arranque y los routers. auth switch hace lo mismo con el otro modo, conservando la política de
sesión, y avisa de que el backend nuevo puede no tener los permisos: después, tai-api rbac push
(y, al pasar a Database, tai-sql push -s auth --with-feed).
Las rutas de /auth¶
| Método | Ruta | Qué hace |
|---|---|---|
POST |
/auth/{realm}/login |
Inicia sesión con { "username", "password" } |
POST |
/auth/refresh |
Un access token nuevo |
POST |
/auth/logout |
Cierra la sesión |
GET |
/auth/me |
El usuario autenticado: nombre, email, roles y permisos |
PATCH |
/auth/me |
El usuario edita su perfil: nombre, apellidos y email |
POST |
/auth/me/password |
El usuario cambia su contraseña con { "current_password", "new_password" } y sigue dentro |
GET |
/auth/{realm}/authorize · /callback |
El login por redirección (Keycloak, con la sesión con cookie) |
La contraseña propia se cambia por POST /auth/me/password, y solo por ahí: el PATCH /auth/me
es el perfil, y un password en su cuerpo es un 422 con field: "password". Comprueba antes la
actual —en una tablet que se queda con la sesión abierta, nadie la cambia sin saberla— y responde
como un login con la nueva: cierra las sesiones anteriores y trae los tokens de una sesión nueva
(con la sesión con cookie, el refresh token va en la cookie), así que el usuario no
tiene que volver a entrar. Renueva la caducidad de la contraseña si está activa. Sus errores son
422 VALIDATION_ERROR con su field: current_password si la actual no es la correcta, y
new_password si la nueva tiene menos de 8 caracteres o es igual a la actual. Funciona igual en
los dos modos; en Keycloak, la política de contraseñas del realm puede rechazar además la nueva.
La gestión de usuarios, roles y reglas de RLS de un realm está en /rbac/{realm}: ver
Permisos y roles.
En cada petición¶
| Situación | Código |
|---|---|
| Sin token, token inválido o caducado, sesión cerrada | 401 |
| Token válido sin el permiso que pide el endpoint | 403 |
En un WebSocket el token no va en la cabecera sino en el subprotocolo, y los rechazos son códigos de cierre: ver WebSocket.
Desarrollo sin autorización¶
tai-api dev arranca la API con la autorización apagada (RBAC_ENABLED=false): todo endpoint
responde sin token, con un usuario de desarrollo que lo puede todo, y lo avisa al arrancar.
tai-api dev --auth la arranca como en producción. El punto de entrada de producción,
__main__.py, la enciende siempre.
Además, cada respuesta lo dice: con la autorización apagada lleva la cabecera X-Tai-Auth: off
—también un error—, y con ella encendida no la lleva. La autenticación no se apaga: el login y la
sesión funcionan igual y piden usuarios de verdad. El cliente TypeScript lo expone para que el
frontend pinte un aviso: ver Contra tai-api dev.
| Página | Qué cuenta |
|---|---|
| Database | Los usuarios en tu base de datos |
| Keycloak | Los usuarios en Keycloak |
| La sesión con cookie | El refresh token fuera del alcance del JavaScript |
| Permisos y roles | El fichero rbac/<realm>.py, rbac push y /rbac |
| Filtrado por fila | Que cada usuario vea solo sus filas |
| WebSocket | Rutas en tiempo real con la misma autenticación |