Auth passthrough móvil → Agentforce chat — User Verification en MIAW con JWT firmado
The Challenge
El cliente ya hizo login en la app móvil (auth propia, no SF). Al abrir el chat de Agentforce embebido, la conversación arranca anónima y el agente no sabe quién escribe. Queremos que sepa desde el turno 0, sin re-autenticar.
In short
- La solución correcta es User Verification de Messaging for In-App and Web (MIAW) — el nombre viejo era 'Authenticated Conversations'; si buscas por ese término te vas a perder los docs actuales.
- El customer firma un JWT (RS256 o RS512, asimétrico — HMAC no está soportado) en su backend con su private key; la public key vive en Salesforce dentro del Auth Method del deployment.
- El SDK móvil (iOS/Android) entrega el JWT vía un delegate/provider al que MIAW le pide el token cuando lo necesita. El SDK web usa 'setIdentityToken' (no 'setAuthorizationToken' — ese es el nombre viejo).
- MIAW valida la firma, resuelve el subject contra un Contact/PersonAccount/User de Salesforce y liga la Messaging Session a ese registro. Agentforce recibe el contexto y puede saludar por nombre desde el turno 0.
- Regla fuerte de MIAW: un deployment atiende usuarios verified O unverified; no se mezclan. Decidí eso desde el diseño.
Symptom
El cliente hace login en la app móvil del negocio (auth propia, no Salesforce). Abre el componente de chat con Agentforce embebido vía MIAW. La conversación arranca anónima: el agente no sabe quién es, saluda genérico ('Hola, ¿en qué te ayudo?') y — peor — le pide datos que la app ya conoce (nombre, DNI, número de póliza).
Root cause
MIAW, por default, trata cada conversación nueva como anónima. El SDK móvil y el SDK web no comparten cookies ni tokens con la capa de auth del negocio. Salesforce no tiene forma de saber que el usuario ya se autenticó afuera a menos que el customer se lo demuestre — con una firma criptográfica, no con un simple dato.
Impact
Fricción alta: doble autenticación percibida, saludo despersonalizado, agente que pide datos redundantes, más turnos hasta la resolución. En verticales regulados (banca, salud, telco) incluso obliga a validaciones extra por cumplimiento — cuando la app ya lo hizo mejor upstream.
Secuencia completa
- 1
App móvil (login)
El usuario abre la app del customer y se autentica con las credenciales del negocio (típ. OAuth contra el IdP corporativo). Recibe la sesión propia del customer.
Esta capa es 100% del customer. Salesforce no participa.
- 2
App móvil (usuario tap 'Chat')
La app va a pedir un JWT específico para MIAW a su propio backend. La sesión que ya tiene el usuario autoriza esa petición.
El JWT NO es la sesión de la app: es un token corto (típ. 5–15 min) emitido específicamente para el chat.
- 3
Backend del customer (endpoint minter)
Recibe la petición autenticada, arma los claims del JWT (iss, sub=customerId, aud, iat, exp), lo firma con la private key RS256/RS512 y lo devuelve.
El sub debe matchear con el campo configurado en el Auth Method (típ. External Id de Contact o Email).
- 4
SDK móvil (delegate/provider)
El SDK dispara el hook userVerificationChallenge (Android) / userVerificationChallengeWithReason (iOS) cuando necesita el JWT. La app responde con el token recién obtenido del backend.
El SDK NO llama al backend por vos: solo te avisa 'necesito un token'. La lógica de traerlo es tuya.
- 5
MIAW runtime (Salesforce)
Recibe el JWT vía el SDK. Valida firma con la public key del Auth Method, valida exp/iat, y resuelve el subject contra el campo configurado.
Si falla cualquier paso, la sesión no arranca y el SDK dispara un error que la app debe manejar.
- 6
MIAW → MessagingSession
Crea (o reutiliza) la MessagingSession y la liga al Contact/PersonAccount/User resuelto. A partir de acá la conversación NO es anónima.
- 7
Agentforce Service Agent
Recibe el primer turno del usuario con el contexto de sesión ya poblado. Puede acceder al Contact desde las variables de contexto del topic y usarlas en el saludo y en cualquier acción downstream.
El path exacto de la variable de contexto (algo como $Context.MessagingSession.MessagingEndUser.Contact) debe validarse abriendo el .agent en Studio del org destino — puede variar por release.
- 8
SDK móvil (token expiration)
Cuando el JWT está por expirar, MIAW dispara el evento onEmbeddedMessagingIdentityTokenExpired (web) o vuelve a invocar el delegate/provider (móvil). La app pide un nuevo JWT al backend y lo entrega dentro de la ventana permitida.
En web la ventana para responder es 30 segundos: si no llega token fresco, la sesión termina.
App móvil del customer
│
│ 1. Login (IdP corporativo)
▼
Auth propia del negocio ────────────────────┐
│
│ 2. Usuario abre chat │
▼ │
Backend del customer (Token Minter) │
│ │
│ 3. Firma JWT (RS256, private key) │
▼ │
Retorna JWT ────────────────────────────────►│
│
│ 4. SDK dispara challenge │
▼ ▼
MIAW SDK (iOS/Android/Web) Cert & Key Mgmt
setIdentityToken / delegate (public key)
│ │
│ 5. JWT viaja al runtime │
▼ │
MIAW Runtime en Salesforce ◄────────────────┘
│ 6. Valida firma con public key
│ 7. Resuelve sub → Contact/PersonAccount
▼
MessagingSession vinculada al Contact
│
▼
Agentforce Service Agent
"Hola Jonathan, ¿en qué te ayudo?"Legend
- Token Minter — Endpoint interno del customer que emite JWTs firmados. Autorizado por la sesión que la app ya tiene. La private key nunca sale de este componente.
- Cert & Key Mgmt — Setup > Security > Certificate and Key Management (o directamente en el Auth Method). Almacena la public key que Salesforce usa para validar el JWT.
- MIAW Runtime — El servicio de Salesforce que recibe el JWT, valida firma/expiración, resuelve el subject y liga la MessagingSession al registro correspondiente.
