showcase/shell-docs/src/content/docs/frontends/angular/auth.mdx
CopilotKit authentication covers two boundaries:
Keep model credentials and service-to-service agent tokens on the server. Browser headers prove the end user's session; they are not a safe place for backend secrets.
Set initial headers in provideCopilotKit:
import { ApplicationConfig } from "@angular/core";
import { provideCopilotKit } from "@copilotkit/angular";
export const appConfig: ApplicationConfig = {
providers: [
provideCopilotKit({
runtimeUrl: "/api/copilotkit",
headers: {
Authorization: `Bearer ${readSessionToken()}`,
},
}),
],
};
When sign-in state changes after bootstrap, update the runtime connection
through the CopilotKit service:
import { inject } from "@angular/core";
import { CopilotKit } from "@copilotkit/angular";
const copilotKit = inject(CopilotKit);
copilotKit.updateRuntime({
headers: sessionToken
? { Authorization: `Bearer ${sessionToken}` }
: {},
});
The runnable Angular Showcase uses the same header shape:
<AngularSnippet region="runtime-auth-headers" />Use the runtime adapter's request hook to reject missing, expired, or unauthorized sessions before CopilotKit discovers or runs an agent:
const handler = createCopilotExpressHandler({
runtime,
basePath: "/api/copilotkit",
hooks: {
onRequest: async ({ request }) => {
const token = request.headers
.get("authorization")
?.replace(/^Bearer\s+/i, "");
const session = token ? await verifySession(token) : null;
if (!session) {
throw new Response("Unauthorized", { status: 401 });
}
},
},
});
Apply authorization as well as authentication. A valid user token does not automatically grant access to every agent, tenant, or thread.
Copilot Runtime forwards authorization and eligible x-* headers to a
self-hosted agent, subject to its denylist. Prefer a small allowlist when your
agent needs only specific context:
const runtime = new CopilotRuntime({
agents: { default: myAgent },
forwardHeaders: {
allow: ["authorization", "x-tenant-id"],
},
});
Server-configured agent headers win over forwarded browser headers. Use that separation for service credentials, and never allow a browser-supplied header to override a backend token.
/info, run, connect, stop, thread, and memory requests—not just
chat sends.updateRuntime({ headers: {} }).