Skip to content

Unclear how to set up authentication with @cloudflare/ai-chat #847

@MonsterDeveloper

Description

@MonsterDeveloper

I'm using Cloudflare Agents with useAgentChat from @cloudflare/ai-chat/react. It's not clear how to properly authenticate the agent.

Issue 1: useAgentChat—2 methods to change headers

const { messages, sendMessage, status, regenerate, stop, error } =
    useAgentChat({
      agent,
      // should we set the via `headers`
      headers: {
        Authorization: `Bearer ${token}`,
      },
      // or
      prepareSendMessagesRequest: () => ({
        headers: {
          Authorization: `Bearer ${token}`,
        },
      }),
    })

However, using prepareSendMessagesRequest is not even possible with the code from the README of ai-chat, because this method doesn't add headers, it just overwrites the whole request and therefore messages don't get sent. There's no way of just customizing the headers without overwriting the body.

Issue 2: Where to check the token on the server?

Assuming we set following hook options:

 const { messages, sendMessage, status, regenerate, stop, error } =
    useAgentChat({
      agent,
      headers: {
        Authorization: `Bearer ${token}`,
      },
    })

In the backend, the token can be checked at 3 multiple locations:

export default {
  async fetch(request: Request, env: Env, _ctx: ExecutionContext) {
    // (1) should we check request.headers here?

    return (
      // Route the request to our agent or return 404 if not found
      (await routeAgentRequest(request, env, {
        onBeforeConnect: (request) => {
          // (2) or maybe here?
        },
        onBeforeRequest: (request) => {
          // (3) or here?
        },
      })) || new Response("Not found", { status: 404 })
    )
  },
} satisfies ExportedHandler<Env>

According to my tests, when just using headers option in the hook (because prepareSendMessagesRequest is unusable), the Authorization header is present in only (3):

Location Authorization header
In worker fetch body
onBeforeConnect
onBeforeRequest

Issue 3: How to pass the token to the Agent's DO?

I need the token to fetch user-specific data before making an LLM request. I couldn't find a way to pass the token from the Worker fetch to the Agent DO itself:

export class QAgent extends AIChatAgent<Env> {
  async onChatMessage(
    onFinish: StreamTextOnFinishCallback<ToolSet>,
    _options?: { abortSignal?: AbortSignal },
  ) {
    // How to access the token here? Or just pass arbitrary data?

    const stream = createUIMessageStream({
      execute: async ({ writer }) => {
        // Clean up incomplete tool calls to prevent API errors
        const cleanedMessages = cleanupMessages(this.messages)

        const agentStream = (await createAgentUIStream({
          agent: qAgent,
          uiMessages: cleanedMessages,
          options: {
            writer,
          },
          // Type boundary: streamText expects specific tool types, but base class uses ToolSet
          // biome-ignore lint/suspicious/noExplicitAny: This is safe because our tools satisfy ToolSet interface (verified by 'satisfies' in tools.ts)
          onFinish: onFinish as unknown as UIMessageStreamOnFinishCallback<any>,
        })) as AsyncIterableStream<InferUIMessageChunk<QAgentUIMessage>>

        writer.merge(agentStream)
      },
    })

    return createUIMessageStreamResponse({ stream })
  }
}


export default {
  async fetch(request: Request, env: Env, _ctx: ExecutionContext) {
    return (
      (await routeAgentRequest(request, env, {
        // how to pass the data from here?
      })) || new Response("Not found", { status: 404 })
    )
  },
} satisfies ExportedHandler<Env>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions