# Identity flows

A known visitor is a JWT signed with **your** private key, verified by Vatio
with your public key, and forwarded to your API as `$auth.token` when a private
tool runs. It reaches Vatio on the web, where your page renders it onto the
widget, and on WhatsApp and Instagram, where the contact brings it back from
your sign-in page ([On WhatsApp and Instagram](https://vatio.ai/docs/authentication/sessions#on-whatsapp)).

The diagram below is [Mermaid](https://mermaid.js.org) so that they read the
same in a browser, in the [Markdown twin](https://vatio.ai/docs/authentication/flows.md) of this
page and to a coding agent.

## Keys and credentials

| Credential | Signed by | Verified by | Lives | Used on |
|---|---|---|---|---|
| Identity JWT (`$auth.token`) | Your `identity.pem` | Vatio, with the `identity.pub` in `vatio.yml` | The `exp` you choose | Web |
| Publishable token (`vatpub_…`) | Issued by Vatio | Vatio, plus the token's allowed origins | Until revoked | Web |
| `chat_token` | Vatio | Vatio | 12 hours | Web |

`$auth.token` is always the identity JWT. The publishable token names the
workspace, not the person, and never reaches your backend.

## Web

```mermaid
sequenceDiagram
  autonumber
  participant B as Your backend
  participant W as Widget / SDK
  participant V as Vatio
  participant A as Your API
  B->>W: page with data-token=vatpub_… and data-visitor-token=JWT
  W->>V: POST /api/visitor/v1/:ws/chats (Bearer vatpub_, visitor_token)
  V->>V: origin allowed for the token, rate limit, verify JWT with identity.pub
  V->>V: store the JWT, write name/email/phone_number onto the contact
  V-->>W: chat_token (12 h)
  W->>V: messages (Bearer chat_token)
  V->>V: private tool: verify the stored JWT again (exp)
  V->>A: Authorization: Bearer $auth.token
  A->>A: verify with your key
```

- A visitor who signs in mid-conversation: the page calls
  `VatioWidget.identify(jwt)`, and the SDK posts it to
  `/api/visitor/v1/:ws/chats/:id/identify`.
- A JWT with a different `sub` answers `identity_changed`, and the SDK starts a
  new conversation. One person never sees another's.
- No JWT means an anonymous chat. Private tools answer that they could not
  confirm who the visitor is.
- Vatio never mints a token: your backend signs it. See [On the web](https://vatio.ai/docs/authentication/sessions#on-the-web).

## Where to go next

- [Sessions and channels](https://vatio.ai/docs/authentication/sessions): rendering the token, and
  signing in mid-conversation.
- [Private tools](https://vatio.ai/docs/authentication/tools): `access: private` and the `$auth.*`
  placeholders.
- [`vatio-sdk`](https://vatio.ai/docs/sdk/ruby):
  the Ruby gem that signs and verifies the JWT.
