Modo iframe (Frame Bridge)
El CRM puede incrustarse en otra aplicación mediante un iframe y autenticarse por postMessage (SSO), sin pasar por la pantalla de login. La detección y el puente están en dos servicios de core/services/ui.
Detección
IframeDetectionService.isIframe() devuelve window.self !== window.top, calculado una sola vez al instanciarse.
Protocolo postMessage
FrameBridgeService.init() (llamado desde el constructor de AuthEffects) solo actúa en iframe: registra el listener message y envía { type: 'CRM_READY' } al padre con window.parent.postMessage(..., '*').
Mensajes entrantes (padre → CRM):
type | Contenido | Efecto |
|---|---|---|
CRM_AUTH | token (token SSO del tenant) y data (externalId, email?, username?, firstname?, lastName?, userType?, roleId?) | Despacha frameAuthenticateRequest → POST /auth/frame-login |
CRM_NAVIGATE | to (ruta) | Navega solo si ya hay sesión (_authenticated), y responde CRM_NAVIGATED |
Si environment.allowedParentOrigins tiene elementos, los mensajes cuyo event.origin no esté incluido se ignoran. Si el arreglo está vacío no se filtra el origen.
Mensajes salientes (CRM → padre), tipo FrameOutgoingEventType: CRM_AUTHENTICATED, CRM_READY, CRM_CHAT_OPENED, CRM_MESSAGE_SENT, CRM_CHAT_CLOSED, CRM_AUTH_EXPIRED, CRM_NAVIGATED. En el código revisado solo se emiten CRM_READY, CRM_AUTHENTICATED, CRM_NAVIGATED y CRM_AUTH_EXPIRED.
Flujo
- El iframe carga;
AuthGuarddeja pasar la ruta aunque no haya sesión (isIframe()), yAuthTokenInterceptorno redirige a login. - El CRM emite
CRM_READY; el padre respondeCRM_AUTH. frameLogin$obtiene el token (/auth/frame-login, con headerskip), cargaget-me, guarda la sesión, navega a/whaticket/chaty emiteCRM_AUTHENTICATED.- Si el login falla o una petición devuelve 401, se navega a
/auth/reconnect; el botón de esa pantalla emiteCRM_AUTH_EXPIREDpara que el padre reenvíeCRM_AUTH.