Skip to content
Chatvia Docs

Workspace

Protected agents

Get in touch: Ahmad Mayahi, creator of Chatvia, Spectra and Shakomako

A protected agent only talks to signed-in chatters. Your backend mints a short-lived JWT signed with the agent's signing secret. Chatvia trusts the signature.

If your team hasn't read Identity verification yet, start there. This page is the embed-specific recipe.

Marking an agent as protected

Open the agent's Security → Identity page. Under Access control, turn Make agent public off. New agents start protected. The flag belongs to the agent, so it applies to all three surfaces at once: Hosted Chat, Chat Widget and Command Bar.

The same page shows the agent's Signing secret. Copy it to your backend. Each agent has its own secret.

A protected agent without a token shows:

  • Hosted Chat: the sign-in page.
  • Chat Widget: a locked chat window with the notice "This chat requires sign-in." The composer is turned off.
  • Command Bar: the same locked screen.

Mint the token on your backend

js
import jwt from 'jsonwebtoken'

const SIGNING_SECRET = process.env.CHATVIA_SIGNING_SECRET

export function signChatviaToken(chatterId, agentId, ttlSeconds = 3600) {
  return jwt.sign(
    { sub: chatterId, aud: agentId },
    SIGNING_SECRET,
    { algorithm: 'HS256', expiresIn: ttlSeconds },
  )
}
  • sub: the Chatvia ID of the chatter or teammate (a UUID), not an ID from your own system. The account must have access to this agent.
  • aud: the agent ID (same as data-agent-id).
  • exp: Unix expiry. Max 24 hours from now.

No JWT library? Chatvia also accepts a short HMAC token: cvh1.<sub>.<exp>.<sig>, where <sig> is the lowercase hex HMAC-SHA256 of <sub>.<exp>, made with the signing secret.

Hand the token to the embed

Widget: data-auth

Render the token into the script tag from your team's server-side template:

html
<script id="chatbot-embed-script"
    src="https://chat.example.com/shakomako/embed.js"
    data-agent-id="YOUR_AGENT_ID"
    data-auth="<%= chatviaToken %>"
    defer></script>

https://chat.example.com stands for your install's own address (APP_URL). For a protected agent, the snippets on the Deploy page already carry a data-auth="YOUR_SIGNED_TOKEN" placeholder.

On load, the widget swaps the token once for its own session token. To sign a chatter in again, mint a new token and render the page again.

Hosted Chat: ?token=

Redirect signed-in chatters from your app:

js
res.redirect(`https://chat.example.com/chat/YOUR_AGENT_ID?token=${chatviaToken}`)

Chatvia validates the token, signs the chatter in to the chat, and strips ?token= from the URL. From then on the chatter is an ordinary signed-in chat user.

Refresh strategy

Tokens live up to 24 hours. Don't try to mint longer ones. Chatvia rejects them.

Options for keeping a long chatter session alive:

  1. Re-mint per page load. Cheapest, fits server-rendered apps.
  2. Mint a fresh token when the chatter comes back. SPA apps: when your own session renews, mint a new JWT on your backend and load the widget with it on the next page load.
  3. Let it expire. If your team's sessions are short anyway (online banking, sensitive tools), letting the chat session end with the JWT is fine.

What rejection looks like

A bad token (expired, wrong audience, wrong signature) resolves to "not signed in." The agent then behaves as if the request were unauthenticated, per surface:

  • Hosted Chat: the sign-in page.
  • Chat Widget: the locked window with "This chat requires sign-in."
  • Command Bar: the same locked screen.

Chatvia never returns a partial response with a half-authenticated identity. It's signed in or not, with nothing in between.

Auditing access

A signed-in chat belongs to the chatter's Chatvia account, so each chatter only sees their own conversations. The agent's Chatters page lists the chatters who have access to the agent. A token only works while its chatter still has access: once the chatter loses access or is deactivated, their tokens stop working at once.

Common mistakes

  • Wrong audience. aud must be the agent's external ID, not its name or chat address.
  • Wrong subject. sub must be the Chatvia ID of the workspace owner, a teammate, or a chatter who has been granted access to this agent. Just any string isn't enough.
  • Token in URL hash. Don't put the token in #fragment. It ends up in browser history and can leak. Use ?token= (consumed and stripped) or data-auth (never in the URL).
  • Signing on the client. Never ship the signing secret to the browser. If it's bundled in JS, anyone can mint sign-ins as anyone.

Search guides, settings and commands.