> ## Documentation Index
> Fetch the complete documentation index at: https://internal.softcrum.com/llms.txt
> Use this file to discover all available pages before exploring further.

# identity

> identity es cómo la plataforma sabe quién está preguntando y si puede. Guarda al personal de nuestros clientes, los roles que llevan, las máquinas que actúan por ellos.

> Traducción. Autoritativo: [`../../../modules/identity/prd.md`](/modules/identity/prd).

> `identity` es cómo la plataforma sabe quién está preguntando y si puede. Guarda al personal de
> nuestros clientes, los roles que llevan, las máquinas que actúan por ellos, y el provider OAuth2
> que permite a un tercero integrarse sin tocar jamás una contraseña. Todo endpoint de la suite está
> gateado por algo definido acá.

## Para quién es

| Persona                                             | Contrata este módulo para                                                                                                                               |
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Administrador del tenant**                        | Invitar a su equipo, decidir quién ve qué, y tener certeza de que un asistente de marketing no puede emitir puntos ni leer un documento de identidad.   |
| **Desarrollador** (tenant o integrador)             | Obtener una API key con alcance acotado en un minuto, o construir una integración que pida permiso al tenant vía OAuth2 en vez de pedirle credenciales. |
| **Operador de Softcrum**                            | Ayudar a un tenant atascado sin convertirse en un superusuario sin rendición de cuentas.                                                                |
| **Revisor de seguridad** (del tenant, o un auditor) | Responder "quién pudo haber hecho esto, y quién lo hizo" desde un rastro y no desde promesas.                                                           |

## El problema hoy

El control de acceso es la parte de una plataforma B2B por la que los clientes no preguntan hasta
que falla, y entonces es lo único por lo que preguntan. Tres fallas concretas, porque el diseño
existe para evitarlas.

**Roles que en realidad son un interruptor.** Muchas plataformas entregan "admin" y "member" y ahí
paran. Apenas un tenant tiene una agencia, un call center y un equipo de finanzas tocando la misma
cuenta, ese modelo los obliga a otorgar de más. Nuestro modelo de permisos es por acción desde el
inicio (DEC-D5), así que "puede leer contactos pero no sus documentos" es expresable y no una
aspiración.

**Integraciones que piden una contraseña.** Sin un provider OAuth2, un tercero que se integra le
pide al tenant una API key con todo, o peor, credenciales de consola. Ser provider OAuth2 es lo que
hace posible un ecosistema de integraciones sin eso.

**Acceso de soporte que nadie puede auditar.** Los operadores necesitan ver lo que ve el tenant.
Hecho a la ligera, eso es una lectura indetectable de los datos de todos los clientes. Con ventana
de tiempo, razón obligatoria, auditoría y **visibilidad para el tenant**, pasa de ser un pasivo a
ser una señal de confianza.

## Qué hace *(normativo)*

* Guarda **organizaciones y usuarios**, donde el email de un usuario es único **por organización**.
  La misma persona trabajando con dos de nuestros clientes tiene dos cuentas independientes que no
  se pueden correlacionar — aislamiento por sobre conveniencia (`standards/data.md` §2b).
* **Invitaciones** con tokens de un solo uso que expiran, conservadas tras aceptarse como evidencia
  de quién dejó entrar a quién.
* Un **registro global de permisos** `{module}.{resource}.{action}`, generado desde las propias
  declaraciones de ruta para que no pueda separarse de lo que el código verifica.
* **Roles** que agrupan permisos, sembrados como roles de sistema y extensibles por el tenant.
* **Las máquinas llevan roles igual que las personas** (DEC-D5): una API key o un cliente OAuth es un
  sujeto con asignaciones de rol, verificado por el mismo camino de código.
* **Autenticación**: contraseña, magic link y passkey, con social y SSO empresarial en F1b.
* **MFA** con TOTP y códigos de recuperación de un solo uso, hasheados.
* **Sesiones** que un usuario puede inspeccionar y revocar por dispositivo.
* **OAuth2 en ambas direcciones**: como provider, para que una herramienta socia actúe por cuenta del
  tenant y el sitio del tenant ofrezca "Sign in with Softcrum"; y como client, para que el personal
  del tenant entre por su propio proveedor de identidad. El tenant elige; ambas pueden correr a la vez.
* **Impersonación de soporte**, acotada en el tiempo, con razón obligatoria, y visible en el propio
  rastro de auditoría del tenant.

## Lo que NO hace *(normativo)*

* **No es el realm de member.** Los members son contactos autenticados y viven en `core` (ADR-010).
  Un token de un realm nunca satisface al otro.
* **No es una red de identidad pública.** "Sign in with Softcrum" sirve a las superficies propias del
  tenant y a los socios que autorice. Un cliente siempre está acotado a la organización que lo
  otorgó, y el sujeto de un member está acotado a esa organización también.
* **No hay SCIM ni sincronización de directorio en F1.** El aprovisionamiento empresarial es un
  pedido real que llega con clientes empresariales reales; el modelo de membresía está formado para
  agregarlo sin migración.
* **No hay permisos por registro.** Los permisos son por acción, no por fila. "Puede editar esta
  campaña pero no aquella" queda fuera deliberadamente: es donde los modelos de autorización dejan
  de ser razonables, para nosotros y para quien los configura.
* **Sin contraseña para members.** Es una decisión de `core` (FS-CORE-0009) y se mantiene: sin
  contraseña de member no hay contraseña de member que se filtre.

## Éxito

| Medida                                                            | Objetivo                                               | Para                  |
| ----------------------------------------------------------------- | ------------------------------------------------------ | --------------------- |
| Tiempo desde el registro hasta un compañero invitado trabajando   | menos de 5 minutos, sin ayuda                          | G1-Engage             |
| Endpoints con exactamente un permiso declarado                    | 100%, impuesto por CI                                  | G1-Engage             |
| Divergencia del registro de permisos entre código y base de datos | cero, impuesto por CI                                  | G1-Engage             |
| Auth p95 (sign-in, token exchange, validación de key)             | \<300 ms                                               | certificación, pre-G1 |
| Sesiones de impersonación sin razón registrada                    | cero, por construcción                                 | siempre               |
| Adopción de MFA entre administradores del tenant                  | obligatorio, no medido — es requisito para roles admin | G1-Engage             |

## Modelo comercial

`identity` no se vende ni se mide. Dos capacidades se gatean por plan en vez de cobrarse: **SSO
empresarial**, que es la feature estándar de tier enterprise en toda la industria, y los **roles
personalizados por el tenant**, donde los planes menores reciben los roles de sistema sembrados.

Los asientos no son una dimensión de facturación. La suite cobra contactos accionables y volumen
(ADR-014, ADR-016), y sumar un cargo por asiento castigaría a un tenant por involucrar a más de su
propio equipo — lo contrario de lo que impulsa la adopción.

## Fases

| Fase    | Contenido                                                                                                                                        | Objetivo              |
| ------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------- |
| **F1a** | Organizaciones, usuarios, membresías e invitaciones · registro de permisos y RBAC · contraseña, magic link y passkey · sesiones · MFA · API keys | G1-Engage, 2026-11-01 |
| **F1b** | Provider OAuth2 con consentimiento · login social · SSO empresarial · impersonación de soporte                                                   | post-G1               |
| **F2**  | Aprovisionamiento SCIM · delegación fina · política de seguridad por organización (duración de sesión, exigencia de MFA, allowlist de IP)        | 2027                  |

## Cumplimiento y riesgo

Para los datos de este módulo Softcrum es **responsable**, no encargado — son nuestros propios
usuarios, no los clientes de nuestros clientes (DEC-J1). Por eso es un schema aparte de `core`
(ADR-022), y significa que nuestra propia política de privacidad rige acá mientras el DPA rige allá.

Tres riesgos dan forma al diseño:

* **Escalamiento de privilegios entre realms.** Mitigado estructuralmente: realms separados,
  audiencias de token separadas, un cliente OAuth que declara un realm y nunca puede alcanzar el
  otro, y un test que afirma que un token de member es rechazado por todo endpoint de consola.
* **Fuga de identidad entre tenants.** El mismo email en dos organizaciones nunca debe ser
  correlacionable. Mitigado por unicidad por tenant, claims `sub` por organización, y respuestas de
  invitación cuya redacción y tiempo no revelan que una dirección se conoce en otra parte.
* **Una API key filtrada.** Mitigada por hasheo en reposo, un prefijo visible que permite
  identificar una key filtrada sin revelarla, `last_used_at` para detección, y rotación sin caída.
* **Un operador leyendo datos de clientes sin ser detectado.** Mitigado haciendo imposible la
  impersonación sin razón y ventana de tiempo, y exponiéndola en el propio rastro del tenant — que
  es quien tiene el incentivo de notarla.

## Dependencias

Better Auth para ambos realms (ADR-010) — el único vendor de este módulo, y aquel cuyo costo de
reemplazo pesa explícitamente la sección de alternativas del ADR-022. Upstash para rate limiting y
verificación de replay. Resend para magic links e invitaciones. `core.audit_log` para el rastro.

## Preguntas abiertas

| # | Pregunta                                                                                                                 | Decide | Para                         |
| - | ------------------------------------------------------------------------------------------------------------------------ | ------ | ---------------------------- |
| 1 | ¿MFA obligatorio para todo usuario, o solo para roles con permisos sensibles?                                            | Daniel | antes de aprobar FS-IDN-0005 |
| 2 | Duración de sesión de consola por defecto — ¿12 horas, o 30 días deslizantes con re-prompt de MFA en acciones sensibles? | Daniel | antes de aprobar FS-IDN-0004 |
| 3 | ¿Entregamos passkeys en F1a, o basta contraseña más magic link para partir?                                              | Daniel | antes de aprobar FS-IDN-0003 |

## Changelog

| Versión | Fecha      | Cambio           | Por qué | Autor                  |
| ------- | ---------- | ---------------- | ------- | ---------------------- |
| 0.1.0   | 2026-08-17 | Borrador inicial | —       | daniel + claude-opus-5 |
