Cómo el navegador no tiene tokens, qué protege la cookie de sesión, cómo se autoriza cada ruta y qué se registra en la auditoría.
Implementado en parte. El diseño es
dec-0118. Qué piezas están verificadas se lee en el gate detrack/identity/sec. El modelo de tokens para clientes nativos es todavía un ADR propuesto, fuera de esta página.
El único origen de control plane que ve el navegador es la web (TanStack Start). Sus funciones de
servidor y un proxy de /auth/* hacia identity-svc son la única superficie: los demás
servicios no se exponen al navegador.
localStorage, sessionStorage, IndexedDB, en
memoria JS ni en cookies legibles por JS. Su única credencial es una cookie de sesión HttpOnly.identity-svc (con la revocación en cuenta) y obtiene un JWT
de acceso de vida corta que nunca sale del servidor. Con él llama a los servicios en nombre
del usuario.El flujo de entrada es OIDC con PKCE contra un proveedor estándar (Pocket ID de referencia).
GET /auth/oidc/start es anónimo y no escribe nada en el servidor: el login pendiente (el
state, el nonce, el verificador de código y el destino) viaja sellado con AES-256-GCM en una
cookie de corta vida, y sólo el callback escribe una marca de uso único. Así el endpoint anónimo
no consume un recurso del servidor que un grupo de clientes pudiera agotar.
| Cookie | Atributos | Contenido |
|---|---|---|
__Host-styx_sess | HttpOnly; Secure; SameSite=Strict; Path=/, sin Domain | Credencial opaca con secreto de 256 bits; en el servidor sólo se guarda su hash |
__Host-styx_login | HttpOnly; Secure; SameSite=Lax, vida del login pendiente | El login pendiente sellado (el callback llega como navegación entre sitios) |
Secure es obligatorio también en desarrollo (con TLS interno): no se admite HTTP en local.
Clear-Site-Data.Los clientes nativos usan un refresh opaco rotatorio en el almacén seguro de la plataforma y no cookies, así que no tienen CSRF.
Toda petición que cambia estado y lleva la cookie debe pasar las dos:
SameSite=Strict y comprobación en servidor de Sec-Fetch-Site: same-origin (o, si falta, Origin idéntico al origen de la web).X-Styx-CSRF con un HMAC de la sesión, que el SSR entrega
a la página; no sirve sin la cookie y no se puede fabricar desde otro sitio.Las funciones de servidor GET no cambian estado. Especificado, pendiente: todavía no hay un
test que falle si una ruta GET declara efectos; lo que existe hoy es el tope de cuerpo por método
de apps/web/src/server/request-guard.ts.
public en una lista explícita, authenticated,
role:… o resource:tipo:acción). Una ruta sin policy deniega. En cada servicio, un test recorre
las rutas y falla si falta alguna o si una public no está en la lista versionada.track/identity/sec, hoy partial): las
funciones de servidor de la web se crearán sólo con un envoltorio, y un guard de lint prohibirá
crearlas de otra forma. Hoy no existen ni el envoltorio ni el guard: los módulos de
apps/web/src/server/*.ts llaman a createServerFn directamente.owner, admin, member y restricted. Un rol es un conjunto de permisos, no
un if en un handler.Authorized que sólo
el motor de políticas fabrica, así que no puede consultar con un id crudo. Un recurso de otro
actor responde 404, no 403, para no confirmar su existencia.own, shared y any. restricted sólo tiene lo propio y no lee la
biblioteca hasta que un propietario le conceda bibliotecas.@styx/authz) decide para HTTP y para el bus.strict-dynamic, Trusted Types y
cabeceras de aislamiento (apps/web/src/server/security-headers.ts). Especificado, pendiente
de SW13: SRI en los scripts y hojas de estilo todavía no está implementado. El contenido
remoto (metadatos, subtítulos, plugins) es no confiable hasta llegar al DOM.application/problem+json (RFC 9457), sin eco de la entrada, sin pila y sin
mensajes de librerías en producción; llevan un instance que enlaza con la traza.Los servicios emiten eventos evt.security.* firmados por spire: inicio y fallo de sesión, cierre,
rotación, reutilización detectada, revocación, denegación de policy, CSRF rechazado, límite de
tasa, emisión y rechazo de SCT, cambios de rol y de fuentes con secretos. Se guardan de forma
sólo-añadir en un esquema propio y se exportan como logs OTel con atributos security.*. Las
agregaciones por «IP» usan la misma unidad de cliente que el rate-limit (IPv4 completa, IPv6 por
/64).
Un rol de Postgres por servicio (sin privilegios de superusuario, con un rol de migraciones
separado), ACL de Valkey por servicio y secretos en ficheros montados de sólo lectura, no en
variables de entorno. Las claves de firma se publican con kid y rotan con solape.