Verb

Writing

How to tell an embedded AI assistant who is signed in

The short answer

Have your own backend mint a short-lived token naming the user, signed with a key the browser never sees, and give the widget a function that fetches a fresh one rather than a single token. A single token works perfectly until it expires, then the assistant starts telling a signed-in user to sign in. Return null only when nobody is signed in, never when the request failed, and encode the token as base64url without padding.

An AI assistant embedded with a script tag runs on your page but is served from somewhere else. That is what makes it easy to install, and it is also why it cannot see who is signed in. Your session cookie belongs to your origin, and a well-behaved browser will not hand it to anyone else.

So the assistant starts every visitor as anonymous, including somebody who has been signed into your app all morning. For an assistant that only answers questions that is fine. For one that takes actions it is the difference between working and refusing every write.

Let your backend say who it is

Your server already knows who is signed in. It states that in a short-lived token signed with a key only your server and the assistant’s server hold, and the assistant verifies the signature rather than trusting anything the page claims. Nothing exotic: an HMAC over a small JSON body, which every backend language does in its standard library.

const claims = { sub: user.id, exp: Math.floor(Date.now() / 1000) + 900 };
const body = base64url(JSON.stringify(claims));
const sig = hmacSha256(body, SIGNING_KEY); // raw digest, then base64url
return { token: `${body}.${sig}` };

Two details decide whether that works. exp is in seconds, not milliseconds. And both halves are base64url with no padding: - and _ instead of + and /, and no trailing =. Standard base64 produces a token that looks completely correct in a log and fails every signature check.

Give it a function, not a token

This is the mistake that does not look like one for fifteen minutes.

The obvious integration fetches a token at page load and hands it over once. It works. The demo works. Then the token expires, because it is short-lived on purpose, it is a bearer credential for a person, and the assistant has no way to get another. A signed-in user starts being told to sign in.

Hand over a function that fetches a fresh token instead, and let the assistant call it before the current one runs out and once more after an unexpected rejection:

const getSessionToken = () =>
  fetch("/api/assistant-token", { credentials: "same-origin", cache: "no-store" })
    .then((r) => r.json())
    .then(({ token }) => token);

Null means signed out, and only that

That fetch can come back empty for three different reasons: nobody is signed in, the endpoint returned an error, or the request never completed. It is tempting to return null for all three.

Do not. Signed out is a real state with a real consequence: the assistant clears the conversation, so the next person at a shared machine does not see it. If a blipped request also returns null, one dropped connection wipes a real user’s conversation halfway through a task. Keep three outcomes apart: signed in, signed out, and unknown.

Two checks before calling it done

What the token protects is covered in how to let users take actions with AI, and what happens when the identity changes is in the chat widget that shows the last user’s conversation.

Common questions

Why can't the assistant just use my session cookie?

A widget loaded from another origin cannot read your cookies, and it should not be able to. Your backend already knows who is signed in, so it states that in a signed token, and the assistant's server verifies the signature instead of trusting the page.

What goes in the token?

As little as possible: the user's id in your system and an expiry a few minutes out, in seconds rather than milliseconds. It is a bearer credential for a person, so keep it short-lived and let the widget fetch a new one before it runs out.

What should happen for a visitor who is not signed in?

The assistant should carry on anonymously and read-only, enforced on the server. That is a working state, not an error, which is exactly why a failed token request must not be reported as signed out: it would wipe a real user's conversation.

Keep reading

Verb is this, built. An AI assistant you embed in your SaaS with one script tag: it calls your own API as the signed-in user, confirms before it changes anything, and logs every action. Free to build and test.