Files
motor-de-encuestas/docs/adr/ADR-004-capa-de-identidad.md

56 lines
3.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-004 — Capa de identidad: respondente anónimo vs staff con SSO
- **Estado:** Aceptado (frontera) · Diferido (integración Keycloak)
- **Fecha:** (completar con fecha de commit)
---
## Contexto
El equipo construye una familia de productos Inquality que se autentican contra un **Keycloak**
propio (proyecto en curso de otro equipo). Surge la pregunta de si esa capa de identidad aplica a
este producto. El producto tiene dos audiencias con necesidades opuestas (respondente anónimo vs
staff interno), por lo que la respuesta no es única.
## Decisión
### Frontera dura (no negociable)
- **El flujo del respondente NUNCA se ata a un IdP.** Las encuestas de v1 son anónimas: el
respondente no se loguea, ni con Keycloak ni con nada. Atarlo a SSO destruiría el anonimato (la
premisa de v1) y agregaría fricción que baja la tasa de respuesta. Lado respondente = `anon` key +
RLS + sin identidad. Para siempre, mientras la encuesta sea anónima.
- **El staff interno SÍ puede usar SSO.** El acceso del equipo a dashboards/administración —a través
de la familia de productos— es donde Keycloak aporta: SSO único, gestión de usuarios centralizada,
offboarding en un solo lugar (control de seguridad real para dato sensible), una sola fuente de
verdad de identidad. Y Keycloak es self-hosteable → alinea con la dirección Dokploy/soberanía.
### Integración técnica (cuando Keycloak madure)
Supabase soporta *third-party auth*: confía en JWT de un emisor externo si son firmados
asimétricamente (RS256/ES256), expuestos vía OIDC Discovery URL, con `kid` en el header. Keycloak
cumple. Dos caminos válidos:
1. Registrar Keycloak como emisor OIDC confiable (más libre en self-host).
2. Patrón universal: verificar el JWT de Keycloak en el edge e intercambiarlo por un JWT firmado por
Supabase. Funciona con cualquier emisor.
RLS lee los claims del token externo con `auth.jwt()` igual que con tokens de Supabase Auth.
### No bloquear v1
Keycloak es un proyecto en curso de otro equipo. **v1 no depende de él.** v1 casi no necesita auth
(encuestas anónimas + dashboard que presenta el staff). Estrategia:
1. Diseñar las policies de RLS para que lean **claims por nombre** (`org_id`, `role`), no helpers
exclusivos de Supabase Auth, para que el emisor sea intercambiable.
2. v1 corre con auth nativa de Supabase para los pocos usuarios internos (o sin login interno si
alcanza).
3. Cuando Keycloak esté listo: emite esos claims, se registra como emisor confiable, y RLS sigue
andando sin reescribir.
## Consecuencias
- (+) Identidad portable: el emisor del token se cambia por config, no por reescritura.
- (+) Encaja con la familia de productos y con la soberanía (Keycloak self-host).
- () Disciplina: nunca basar RLS en `user_metadata` (modificable por el usuario); usar claims
verificados del servidor (Keycloak los da).
- () Cuando se integre, alinear los claims de Keycloak (`org_id`, `role`) con lo que esperan las
policies — tarea de config, no de esquema.
## Relación con otros ADR
Vive sobre el patrón de backend de ADR-002 (Supabase como backend). La regla de keys de `CLAUDE.md`
(rule 9) sigue aplicando: `service_role` nunca al cliente, pase lo que pase con el IdP.