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

# SSO (Single Sign-On)

> Inicio de sesión empresarial vía SAML 2.0 u OpenID Connect, intermediado por Stytch B2B

<Info>
  **Disponible en el plan Corporate.** Esta funcionalidad forma parte de las capacidades empresariales de woku. [Conversa con nuestro equipo comercial](https://woku.app/pricing).
</Info>

Woku soporta **SSO empresarial** (SAML 2.0 + OpenID Connect) para
que los usuarios de una empresa puedan iniciar sesión con el
proveedor de identidad (IdP) que ya usan internamente: Azure AD /
Microsoft Entra, Okta, OneLogin, Google Workspace, ADFS, etc.

El intermediario técnico es **Stytch B2B**: Stytch hospeda las
conexiones SAML/OIDC y nos entrega un token verificable cuando la
autenticación del IdP termina exitosamente.

<Note>
  **Caso de referencia.** **RE/MAX Chile** utiliza SSO con woku integrando su
  Active Directory de **Microsoft Azure AD (Entra ID)**.
</Note>

## Modelo

* **Una empresa Woku ↔ una `Organization` Stytch.** Cada empresa que
  habilita SSO se vincula a una organización en Stytch.
* **Una organización Stytch ↔ una o más conexiones SAML/OIDC.** Las
  conexiones se configuran en el dashboard de Stytch (XML metadata
  del IdP, attribute mapping, certificados, etc.).
* **Lista blanca de dominios.** Cada empresa que habilita SSO
  declara qué dominios de correo pueden usar SSO contra esa
  organización. Esto evita ataques de impersonación cross-tenant.
* **Identidad escopada por organización + miembro Stytch.** Una vez
  que un usuario Woku entra por SSO, lo vinculamos a la tupla
  `(stytchOrganizationId, stytchMemberId)`. Los logins siguientes
  resuelven por esa tupla, no por email, lo que cierra la ventana
  de impersonación incluso si el email cambia o se reutiliza.
* **Opt-in per-empresa.** Por defecto SSO está apagado y los usuarios
  inician sesión con email + contraseña + (opcional) MFA TOTP.

## Activar SSO en tu empresa

Pre-requisitos:

1. Tener una organización Stytch creada (la primera vez la creamos
   nosotros para ti).
2. Tener al menos una conexión SAML u OIDC configurada en esa
   organización contra tu IdP.

Luego, desde Woku:

1. Ve a **Empresa → Seguridad → SSO**.
2. Marca **Habilitado** e ingresa lo que te entrega Stytch:
   * **Stytch Organization ID** (formato `organization-prod-...`).
   * **Stytch Connection ID** (formato `saml-connection-prod-...`
     u `oidc-connection-prod-...`).
3. Agrega al menos un **dominio de correo permitido** (por ejemplo
   `acme.com`). Solo los usuarios cuyo email termine en alguno de
   esos dominios podrán completar el SSO contra esta empresa.
4. Guarda.

> El backend rechaza activar SSO sin Organization ID, Connection ID
> y al menos un dominio permitido (400 `BadRequest`). Esto evita
> dejar la empresa con SSO habilitado pero sin destino ni control
> de quién puede entrar.

### Por qué la lista de dominios

Sin esta lista, un IdP malicioso (o mal configurado) podría afirmar
un correo de otra empresa (`alguien@otra-empresa.com`) y obtener
acceso al tenant equivocado. Con la lista, el backend rechaza con
`403` cualquier aserción SSO cuyo dominio de correo no figure entre
los autorizados de la empresa.

## Cómo es el flujo de login (SP-initiated)

Vista desde el usuario:

1. El usuario abre la página de login del admin y escribe su correo.
   Hace clic en **Continuar**.
2. El admin consulta el **servicio de descubrimiento** para resolver
   qué método mostrar:
   * Si el dominio del correo está en alguna empresa con SSO
     habilitado, aparece el botón **Continuar con SSO**.
   * En caso contrario, aparece el campo **Contraseña**.
3. Si fue SSO: el navegador es redirigido a Stytch, Stytch al IdP, el
   IdP de vuelta a Stytch, y Stytch a nuestro callback. Después de
   intercambiar el token, redirige al admin con los tokens Woku en
   el fragmento de URL y la sesión queda iniciada.

Vista desde el backend:

1. El **descubrimiento** resuelve si el dominio del correo pertenece
   a alguna empresa con SSO activo. La respuesta indica el modo
   (`sso` o `password`) y tiene **forma estable independiente de si el
   usuario existe en Woku**, para no filtrar datos de enumeración.
2. Cuando el usuario aprieta **Continuar con SSO**, el backend valida
   que la empresa tenga SSO habilitado y responde con un **302
   redirect** a la URL pública de Stytch.
3. Stytch redirige al IdP donde el usuario se autentica.
4. El IdP redirige de vuelta a Stytch, que valida la aserción y
   redirige al **callback de Woku**.
5. Woku intercambia el token (`stytch.sso.authenticate`), resuelve
   la empresa por `organization_id`, **verifica que el dominio del
   correo afirmado esté en `ssoEmailDomains`**, busca al usuario
   primero por `(stytchOrganizationId, stytchMemberId)` y, si es la
   primera vez, hace JIT provisioning + registra la identidad.
   Finalmente asegura la membresía `UserCompany`, emite un par de
   tokens Woku (access + refresh) y redirige al admin con los
   tokens en el fragmento de URL.
6. La **página de callback** del admin lee el fragmento, persiste el
   token en el store de autenticación, abre el canal de tiempo real y
   limpia el fragmento del historial antes de redirigir al usuario al
   dashboard.

V1 soporta solo el flujo **SP-initiated** (el usuario empieza
en Woku). IdP-initiated llega en una iteración posterior.

## Just-In-Time provisioning

Cuando un usuario inicia sesión por SSO por primera vez:

1. **Resolución por identidad scopeada.** Primero buscamos un usuario
   Woku que ya tenga registrada la identidad
   `(stytchOrganizationId, stytchMemberId)`. Si existe, lo usamos.
2. **Fallback por email.** Si no había identidad registrada, buscamos
   por email normalizado. Si el usuario existe lo **vinculamos** a la
   nueva identidad para los siguientes logins.
3. **JIT.** Si tampoco existe el email, lo creamos automáticamente con
   un username derivado del email y una contraseña aleatoria (que el
   usuario nunca usa). Marcamos la cuenta como confirmada.
4. **Membresía.** En todos los casos aseguramos que el usuario tenga
   membresía `UserCompany` en la empresa correspondiente. El rol por
   defecto es `member`. Si necesitas que los usuarios SSO entren con
   rol `admin`, contacta a soporte (UI de mapeo de roles está en
   backlog).

Cada login SSO queda registrado en el [registro de
auditoría](/seguridad/audit-log) como `auth.sso.login` con
`actorEmail`, `companyId`, `stytchOrganizationId`, `stytchMemberId`,
`newlyLinked` (`true` cuando recién se registró la identidad) e IP.

## Garantías

* **El secreto de Stytch nunca toca el cliente.** Solo el
  `STYTCH_PUBLIC_TOKEN` (público por diseño) se incluye en la URL
  de start; el `STYTCH_SECRET` vive solo en el backend.
* **Validación server-side.** La sesión Woku se emite únicamente
  después de que Stytch confirma la autenticación. El token de
  Stytch es de un solo uso.
* **Aislamiento per-empresa.** El callback rechaza con `403` si la
  organización Stytch no está vinculada a ninguna empresa Woku.
* **Anti-impersonación cross-tenant.** El callback rechaza con `403`
  si el dominio del correo afirmado por el IdP no figura en
  `ssoEmailDomains`, y la identidad Woku se resuelve por la tupla
  `(stytchOrganizationId, stytchMemberId)` antes que por email.
* **No enumeración.** La respuesta del descubrimiento no depende de
  si el usuario existe en Woku; solo del dominio del correo. Está
  rate-limitada para desincentivar barridos.
* **Auditable.** Todos los pasos quedan registrados.

## Limitaciones conocidas (V1)

* La configuración detallada de SAML/OIDC (XML metadata, attribute
  mapping, certificados) se hace en el **dashboard de Stytch**, no
  en el panel de Woku. Solo los IDs y los dominios viven en Woku.
* Solo SP-initiated. IdP-initiated requiere endpoint adicional;
  llega en la siguiente iteración.
* Sin mapeo de roles automático: todos los usuarios SSO entran como
  `member` por defecto. Los upgrades a `admin`/`owner` se hacen
  manualmente desde **Empresa → Miembros**.
* El add-on de SSO es **opt-in y monetizable**: el modelo comercial
  (precio del add-on) se documenta aparte. Mientras tanto el flag
  `ssoEnabled` se enciende manualmente.

## Pérdida de acceso

Si la conexión SAML/OIDC del IdP se rompe, si el dominio del email
del usuario cambia, o si necesitas agregar/quitar un dominio
permitido sin acceso al panel, contacta a soporte
(`team@woku.app`) para deshabilitar SSO temporalmente o reasignar
la membresía manualmente.
