Auth providers

Trust external JWT issuers with auth rules, exchange their tokens in the browser, and mint cloud tokens from a server when needed.

An auth rule tells Assistant Cloud which external JWT issuer may open a signed in browser session. Create rules in Settings › Access, where the page lists each rule's name, issuer, audience, JWKS URL, creation time, and actions. A rule does not copy users from your provider. It verifies the token presented by your app, then records a display name when you choose a Name claim.

How a rule accepts a token

A browser first sends the JWT returned by authToken. The cloud derives the project from the request host, requires an RS256 token with an iss claim and a kid header, then finds an auth rule in that project. A rule matches only when its issuer equals the token issuer and either its audience is null or its audience appears in the token's aud list.

Rule used to match a provider token
token.issuer equals rule.issuer
and (rule.audience is empty or token.audience contains rule.audience)
and token.algorithm is RS256
and token.header has kid

The cloud revalidates the rule's JWKS endpoint as a public HTTPS URL before it fetches the selected key. The fetch times out after one second. Its remote JWKS resolver cache is bounded to 10,000 URLs. It then verifies the signature and claims. sub becomes the user id, and the rule's workspace claim becomes the workspace id. The dashboard currently fixes that claim to User ID, so it remains unset on the rule and the cloud uses sub.

The Name claim is optional. When it is set, the cloud reads that JWT claim, trims it, limits it to 255 characters, and records it as the user's display name. It writes a given project, user, and name combination at most once every five minutes. If you remove a Name claim or delete a rule that had one, stored names are forgotten only after no rule in the project names a claim. Those names appear in the dashboard's user and thread lists; otherwise the dashboard shows the user id.

Configure an auth rule

Settings › Access on the demo project

Choose Add rule in Settings › Access, then save the rule. A signed in member can create, edit, or delete auth rules. The rule form has these controls:

ControlDefaultAcceptsEffect
ProviderNo selectionAuth0, Clerk, Firebase, Supabase, or CustomRequired. An empty selection reads Select a provider; the choice labels the rule and opens provider documentation for the first four choices.
NameEmpty1 to 255 charactersThe rule name shown in the table. An empty name reads Name is required.
IssuerEmptyAn optional 1 to 2,047 character valueMust equal the presented token's iss to match.
AudienceEmptyAn optional 1 to 2,047 character valueMust appear in the token's aud. Leave it empty to match a token regardless of audience.
JWKS endpointEmptyA required public HTTPS URL, 1 to 2,047 charactersSupplies the public keys used to verify a matching token. An empty value reads JWKS endpoint is required; invalid, private, or non HTTPS endpoints are refused.
Workspace ID claimUser IDFixed, disabled controlThe form does not submit a claim name. The cloud uses sub as the workspace id.
Name claimEmptyAn optional 1 to 255 character claim nameNames the JWT claim to record as the display name. Whitespace is trimmed and an empty value is saved as no claim.

There is no per project auth rule count limit. Several rules are useful when separate frontends or identity providers need access to the same project. Each presented token is still accepted only by a rule that matches its issuer and audience.

Exchange provider tokens in the browser

After the cloud accepts a provider JWT, its response includes Authorization: Bearer <internal token>. The internal token is valid for five minutes, has an nbf ten seconds before its issue time, and carries the project, user, and workspace. The SDK keeps it until 30 seconds before expiry and shares one pending call to authToken across concurrent requests. A callback returning null means signed out; the SDK throws Authorization failed before it sends that request.

Keep the AssistantCloud client in useMemo. Recreating it on a render discards the exchanged token cache and can call the provider more often than needed.

From your code

The provider token callback returns the JWT you configured the rule to verify. These provider examples use the same browser client shape.

Create a Clerk JWT template named assistant-ui with { "aud": "assistant-ui" }. Set the rule's issuer, JWKS endpoint, and audience to the template values.

use-cloud.ts
"use client";

import { useMemo } from "react";
import { useAuth } from "@clerk/nextjs";
import { AssistantCloud } from "@assistant-ui/react";

function useCloud() {
  const { getToken } = useAuth();
  return useMemo(
    () => new AssistantCloud({
      baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
      authToken: () => getToken({ template: "assistant-ui" }),
    }),
    [getToken],
  );
}

Mint a token on your server

POST /v1/auth/tokens creates a cloud token for the API key client's Aui-User-Id and Aui-Workspace-Id. It accepts no body, requires an API key on the backend host, and returns { "token": "..." }. The minted token carries sub, workspace_id, project_id, and the project frontend issuer. It is valid for five minutes and is accepted ten seconds before issue time.

Create a cloud token
POST /v1/auth/tokens
Authorization: Bearer sk_aui_proj_abcdef123456_secret
Aui-User-Id: usr_123
Aui-Workspace-Id: org_123_usr_123
app/api/assistant-ui-token/route.ts
import { AssistantCloud } from "assistant-cloud";
import { auth } from "@clerk/nextjs/server";

export const POST = async () => {
  const { userId, orgId } = await auth();
  if (!userId) return new Response("Unauthorized", { status: 401 });

  const cloud = new AssistantCloud({
    apiKey: process.env.ASSISTANT_API_KEY!,
    userId,
    workspaceId: orgId ? `${orgId}_${userId}` : userId,
  });
  const { token } = await cloud.auth.tokens.create();
  return new Response(token);
};
app/chat/page.tsx
const cloud = new AssistantCloud({
  baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
  authToken: async () => {
    const response = await fetch("/api/assistant-ui-token", { method: "POST" });
    return response.ok ? response.text() : null;
  },
});

Provider token errors

StatusError stringCause
401JWT token has expiredThe provider token's exp is past.
401JWT token is not yet validIts nbf is in the future.
403Invalid JWT tokenThe token cannot be decoded.
403JWT token algorithm is not validIt is not RS256.
403JWT payload is missing issIt has no issuer.
403JWT header is missing kidIt cannot select a JWKS key.
403Invalid project IDThe request host cannot identify a project.
403No auth rule matches the JWT iss and aud claimsNo rule matches its issuer and audience.
403JWT payload is missing subIt has no user id.
403JWT sub is not a valid user ID: …sub is not a valid user id.
403JWT <claim> is not a valid workspace ID: …The workspace claim is not valid.
403JWT token is not validSignature or another claim check failed.
403Origin does not match project IDA valid token was sent to the wrong host.

The token minting endpoint additionally answers 403 "This endpoint may only be accessed from the backend" to a non API key credential. Other header and API key failures are listed on Authentication.

Troubleshooting

What you seeWhyWhat to do
No auth rule matches the JWT iss and aud claimsThe issuer differs, or the rule audience is not in the token's audience list.Copy the JWT's iss exactly and set the rule audience to a value the token carries, or leave the rule audience empty.
JWT token algorithm is not validThe provider token is not RS256.Use a provider JWT with an RS256 signature, or mint a cloud token from your server.
JWT header is missing kidThe token cannot select a public key from the JWKS document.Return a provider token with a kid header.
The browser reports Authorization failedauthToken returned null or an empty token.Wait until the provider has a signed in session, then return its token.
The dashboard shows an id instead of a nameNo remaining rule names a Name claim, or that claim was empty.Set a Name claim that resolves to a nonempty value in the provider JWT.
A valid token is refused on one frontend but not anotherThe request reached a host other than the project frontend host.Use the project's frontend baseUrl; do not send browser credentials to the backend host.