# Authentication Authentication in AI Transport operates at three levels: Ably token authentication for channel access, HTTP headers for server endpoint authorization, and cancel authorization for controlling who can cancel turns. ## Authentication flow 1. Your auth server authenticates the user. 2. Your auth server issues an Ably-compatible token (JWT format is recommended for most apps). 3. The client SDK fetches tokens with `authCallback` and refreshes them automatically before expiry. 4. The authenticated Pub/Sub client provides channels to AI Transport via `useChannel` or `channels.get`. ## Server setup Create an endpoint that validates user-provided credentials and returns JWTs with the appropriate AI Transport capabilities: ### Javascript ``` // Server-side JWT with AI Transport capabilities import jwt from 'jsonwebtoken'; const [keyName, keySecret] = process.env.ABLY_API_KEY.split(':'); const ablyJwt = jwt.sign( { 'x-ably-capability': JSON.stringify({ // Only allow access to a specific conversation channel 'your-conversation': ['publish', 'subscribe', 'history'], }), 'x-ably-clientId': userId, }, keySecret, { algorithm: 'HS256', keyid: keyName, expiresIn: '1h' } ); ``` ## Client setup ### Javascript ``` import * as Ably from 'ably'; const realtimeClient = new Ably.Realtime({ authCallback: async (tokenParams, callback) => { try { const response = await fetch('/api/ably-token', { credentials: 'include' }); if (!response.ok) throw new Error('Auth failed'); const jwt = await response.text(); callback(null, jwt); } catch (error) { callback(error, null); } }, }); const channel = realtimeClient.channels.get('your-conversation'); ``` ### React ``` 'use client' import { useEffect, useState } from 'react'; import * as Ably from 'ably'; import { AblyProvider, useChannel } from 'ably/react'; import { useClientTransport } from '@ably/ai-transport/react'; // 1. Create an authenticated Ably client and wrap your app export function Providers({ children }) { const [client, setClient] = useState(null); useEffect(() => { const ably = new Ably.Realtime({ authCallback: async (_tokenParams, callback) => { try { const response = await fetch('/api/ably-token', { credentials: 'include' }); callback(null, await response.text()); } catch (err) { callback(err instanceof Error ? err.message : String(err), null); } }, }); setClient(ably); return () => ably.close(); }, []); if (!client) return null; return {children}; } // 2. Inside the provider, get a channel and pass it to the transport function Chat({ conversationId }) { const { channel } = useChannel({ channelName: conversationId }); const transport = useClientTransport({ channel, codec: yourCodec }); // ... } ``` For more details, see [token authentication](https://ably.com/docs/auth/token.md), [capabilities](https://ably.com/docs/auth/capabilities.md), and [identified clients](https://ably.com/docs/auth/identified-clients.md). ## Enable message updates and deletes AI Transport requires the *Message annotations, updates, deletes, and appends* channel rule to be enabled on the channel namespace used for conversations. Without this rule, the transport cannot function correctly. In your app [settings](https://ably.com/accounts/any/apps/any/settings): 1. Click **Add new rule**. 2. Enter the channel name or namespace on which to enable message updates and deletes. 3. Check **Message annotations, updates, deletes, and appends**. 4. Click **Create rule** to save. Create a rule with updates and deletes enabled using the Control API by sending a `POST` request to [`/apps/{app_id}/namespaces`](https://ably.com/docs/api/control-api.md): ### Shell ``` curl -X POST https://control.ably.net/v1/apps/{APP_ID}/namespaces \ -H "Authorization: Bearer {ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "id": "my-namespace", "mutableMessages": true }' ``` Use the [Ably CLI](https://ably.com/docs/platform/tools/cli.md) to create a rule with updates and deletes enabled: ### Shell ``` ably apps rules create \ --name "my-namespace" \ --mutable-messages ``` Run `ably apps rules create --help` for a full list of available options. ## AI Transport capabilities Capabilities are permissions that control what operations a client can perform. When you create a token for an AI Transport user, specify which capabilities they have: | Feature | Required capabilities | |---------|----------------------| | Send user messages to channel | `publish` | | Receive streamed tokens | `subscribe` | | Replay history on reconnect | `subscribe`, `history` | | Cancel a turn | `publish` | | All AI Transport features | `publish`, `subscribe`, `history` | ## Channel-scoped capabilities You can scope capabilities to specific conversation channels, a namespace of channels, or all channels: * `my-conversation` - a specific conversation channel * `conversations:*` - all channels in the `conversations:` namespace * `*` - all channels ## Token lifecycle and permission updates - With `authCallback` or `authUrl`, token refresh is automatic and handled by the SDK. - To change a user's capabilities during an active session, issue a new token from your auth server and re-authenticate: ### Javascript ``` // Re-authenticate to pick up updated capabilities await realtimeClient.auth.authorize(); ``` - To immediately remove access, [revoke issued tokens](https://ably.com/docs/auth/revocation.md). - If your capability JSON is too large for JWT or must remain confidential, use native [Ably Tokens](https://ably.com/docs/auth/token/ably-tokens.md). ## Server endpoint authentication When the client sends user messages, it makes an HTTP POST to the server endpoint. The `ClientTransportOptions` provide two mechanisms for authenticating these requests: **headers**: Static or dynamic HTTP headers sent with every POST. ### Javascript ``` const transport = useClientTransport({ channel, codec: UIMessageCodec, headers: () => ({ 'Authorization': `Bearer ${getAuthToken()}`, }), }) ``` **credentials**: Controls whether cookies are sent with the POST request. This maps directly to the Fetch API `credentials` option. Set to `'include'` if your server uses cookie-based session authentication (for example, NextAuth or `express-session`) and the endpoint is cross-origin. For same-origin requests, the browser sends cookies by default and this option is not needed. ### Javascript ``` const transport = useClientTransport({ channel, codec: UIMessageCodec, credentials: 'include', }) ``` The server endpoint validates these credentials however it normally would: JWT verification, session cookies, or API keys. ## Cancel authorization When a client publishes a cancel signal, the server can authorize or reject it. The `onCancel` hook on `NewTurnOptions` receives a `CancelRequest` with the filter, matched turn IDs, and a map of turn owners: ### Javascript ``` const turn = transport.newTurn({ turnId, clientId, onCancel: async (request) => { // Only allow the turn owner to cancel const owner = request.turnOwners.get(request.filter.turnId) return owner === request.message.clientId }, }) ``` If `onCancel` returns `false`, the cancellation is rejected. If `onCancel` is not provided, all cancel requests are accepted by default. ## What to read next - [Getting started](https://ably.com/docs/ai-transport/getting-started/vercel-ai-sdk.md): Set up authentication in a working app. - [Cancellation](https://ably.com/docs/ai-transport/features/cancellation.md): How cancel signals and authorization work in detail. ## Related Topics - [Sessions and turns](https://ably.com/docs/ai-transport/how-it-works/sessions-and-turns.md): Understand how Ably AI Transport models sessions as durable channels and structures conversations into turns with clear lifecycles. - [Transport](https://ably.com/docs/ai-transport/how-it-works/transport.md): Understand the two-layer transport architecture in Ably AI Transport: a generic core transport and a pluggable codec that bridges your AI framework to Ably. ## Documentation Index To discover additional Ably documentation: 1. Fetch [llms.txt](https://ably.com/llms.txt) for the canonical list of available pages. 2. Identify relevant URLs from that index. 3. Fetch target pages as needed. Avoid using assumed or outdated documentation paths.