Flujos de identidad
Todos los canales terminan en el mismo lugar: un JWT firmado con tu llave privada, que Vatio verifica con tu llave pública y le reenvía a tu API como $auth.token cuando corre una herramienta privada. Lo que cambia por canal es cómo llega ese JWT a Vatio.
| Canal | Cómo llega el JWT | Quién pregunta |
|---|---|---|
| Web | Tu página lo renderiza en el widget | Nadie; tu página lo entrega |
| Tu endpoint de mint lo devuelve para un teléfono | Vatio | |
| Tu endpoint de mint lo devuelve para una cuenta de Instagram | Vatio |
Los diagramas de abajo están en Mermaid para que se lean igual en el navegador, en el gemelo Markdown de esta página y para un agente de código.
Llaves y credenciales
| Credencial | La firma | La verifica | Dura | Se usa en |
|---|---|---|---|---|
JWT de identidad ($auth.token) | Tu identity.pem | Vatio, con el identity.pub de vatio.yml | El exp que elijas | Web, WhatsApp, Instagram |
Vatio-Signature | La llave de mint de Vatio (ES256) | Tu backend, con /.well-known/vatio-mint-key | 60 segundos | WhatsApp, Instagram |
Secreto compartido del mint (X-Api-Key) | Nadie; es un string | Tu backend, en tiempo constante | Hasta que lo rotes | WhatsApp, Instagram |
Token publicable (vatpub_…) | Lo emite Vatio | Vatio, más la lista de orígenes permitidos | Hasta revocarlo | Web |
chat_token | Vatio | Vatio | 12 horas | Web |
$auth.token siempre es el JWT de identidad. El token publicable identifica al workspace, no a la persona, y nunca llega a tu backend.
Web
mermaid
sequenceDiagram
autonumber
participant B as Tu backend
participant W as Widget / SDK
participant V as Vatio
participant A as Tu API
B->>W: página con data-token=vatpub_… y data-visitor-token=JWT
W->>V: POST /api/public/v1/:ws/chats (Bearer vatpub_, visitor_token)
V->>V: origen permitido, rate limit, verifica el JWT con identity.pub
V->>V: guarda el JWT, escribe nombre/email/teléfono en el contacto
V-->>W: chat_token (12 h)
W->>V: mensajes (Bearer chat_token)
V->>V: herramienta privada: vuelve a verificar el JWT guardado (exp)
V->>A: Authorization: Bearer $auth.token
A->>A: verifica con tu llave- Si el visitante inicia sesión a mitad de la conversación, la página llama a
VatioWidget.identify(jwt)y el SDK lo envía a/api/public/v1/:ws/chats/:id/identify. - Un JWT con otro
subrespondeidentity_changed, y el SDK abre una conversación nueva. Una persona nunca ve la de otra. - Sin JWT el chat es anónimo. Las herramientas privadas responden que no pudieron confirmar quién es.
- La web nunca hace mint. Mira En la web.
WhatsApp
mermaid
sequenceDiagram
autonumber
participant C as Contacto de WhatsApp
participant V as Vatio
participant B as Tu backend (endpoint de mint)
participant A as Tu API
C->>V: mensaje (Meta entrega el wa_id)
Note over V: si hay un JWT guardado que sigue siendo válido, se reutiliza
V->>V: body {"channel":"whatsapp","phone_number":"+569…"}
V->>V: firma Vatio-Signature (ES256, exp 60 s, body_sha256)
V->>B: POST auth.mint.url (X-Api-Key, Vatio-Signature)
B->>B: secreto compartido, luego la firma (iss, aud = slug, hash del body)
B->>B: busca el número, exacto como llegó
alt lo conoce
B-->>V: 200 {"token": JWT firmado con identity.pem}
V->>V: verifica con identity.pub y lo guarda en el chat
V->>A: herramienta privada: Authorization: Bearer $auth.token
else no lo conoce, o falló una validación
B-->>V: 404 {}
Note over V: el chat sigue anónimo
end- El mint corre al empezar el chat y cada vez que una herramienta privada corre sin un JWT que siga siendo válido, así que el siguiente ocurre después del
exp. phone_numbersale del número que entregó Meta, nunca de un claim del token escrito en el contacto.- Un usuario que oculta su número detrás de un nombre de usuario de WhatsApp no trae teléfono, y no se envía ningún request.
Instagram
mermaid
sequenceDiagram
autonumber
participant C as Contacto de Instagram
participant M as Meta Graph API
participant V as Vatio
participant B as Tu backend (endpoint de mint)
participant A as Tu API
C->>V: DM (Meta entrega el IGSID)
Note over V: si hay un JWT guardado que sigue siendo válido, se reutiliza
V->>M: usuario actual de este IGSID
M-->>V: usuario (o sin respuesta)
V->>V: body {"channel":"instagram","instagram_id":"1784…","username":"ana.perez"}
V->>V: firma Vatio-Signature (ES256, exp 60 s, body_sha256)
V->>B: POST auth.mint.url (X-Api-Key, Vatio-Signature)
B->>B: secreto compartido, luego la firma (iss, aud = slug, hash del body)
B->>B: busca por instagram_id, o por un usuario verificado
alt lo conoce
B-->>V: 200 {"token": JWT firmado con identity.pem}
V->>V: verifica con identity.pub y lo guarda en el chat
V->>A: herramienta privada: Authorization: Bearer $auth.token
else no lo conoce, o falló una validación
B-->>V: 404 {}
Note over V: el chat sigue anónimo
endinstagram_ides el IGSID: estable, y único para esta persona en tu cuenta. Es el campo para comparar una vez que lo vinculaste.usernamese le pide a Meta en cada mint y se omite cuando Meta no responde. Los nombres de usuario de Instagram se pueden cambiar y reutilizar, así que compara contra uno solo si verificaste que es de ese usuario.- El request llega al mismo endpoint que WhatsApp. Distingue por
channel.
Qué leer después
- Sesiones y canales: la forma del request y la respuesta, y qué verificar en el request de mint.
- Herramientas privadas:
access: privatey los placeholders$auth.*. vatio-identity: la gema de Ruby que firma el JWT y sirve el endpoint de mint.
