new·Earn with mozg — 20% of every monthSend somebody here and take a fifth of every plan payment they make, for as long as they keep paying — not a bounty on the first invoice. Your handle is the link, the window is thirty days, and the commission lands on your balance the second they pay. Free to join: if you have signed in, you already have the link. mozg.sh/earnall news →
mozg.beta
Sign in

Better Auth · Plugins · all subjects

agent auth plugin

45 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Agent Auth plugin for AI agent authorization

Better Auth includes an Agent Auth plugin (marked as new) that provides discovery, registration, and capability-based authorization for AI agents.

Install Agent Auth plugin packages

Install the main plugin with: npm install @better-auth/agent-auth. Optional client and CLI packages: npm install @auth/agent @auth/agent-cli.

Agent Auth plugin overview and purpose

The Agent Auth plugin enables a Better Auth server to act as an Agent Auth provider implementing the Agent Auth Protocol. It gives AI agents a standard way to discover your service, register themselves, request approval, and execute scoped capabilities using short-lived signed JWTs. The plugin comes with adapters for OpenAPI and MCP.

Agent Auth plugin features

Features include: OpenAPI adapter to derive capabilities from OpenAPI 3.x specs; MCP adapter to expose agent auth as MCP tools; discovery document at /.well-known/agent-configuration; capability listing, description, and execution with optional per-capability location URLs; delegated and autonomous agent modes; device authorization and CIBA approval flows; short-lived signed JWTs with replay protection; audit and event hooks for approvals, grants, and execution.

Agent Auth plugin basic configuration structure

Add agentAuth() to the plugins array in betterAuth config. Define capabilities with name and description. Provide an onExecute handler function that performs the action for an authenticated agent. Set modes (delegated, autonomous), providerName, and providerDescription.

Expose Agent Auth discovery document

The plugin provides auth.api.getAgentConfiguration() to retrieve the discovery document. Expose it at /.well-known/agent-configuration from your app root, even if your Better Auth base path is /api/auth. The route should return the configuration as JSON.

Agent Auth database migration

Run npx auth migrate or npx auth generate to add the agent, host, grant, and approval tables required by the Agent Auth plugin.

Agent Auth client plugin setup

Add agentAuthClient() plugin to createAuthClient for type-safe access to plugin endpoints from a Better Auth client. Import agentAuthClient from @better-auth/agent-auth/client.

Agent Auth flow overview

The typical Agent Auth flow: (1) Agent discovers provider from /.well-known/agent-configuration, (2) Agent lists capabilities and decides what it needs, (3) Agent registers with server and requests capability grants, (4) User approves request through device authorization or CIBA, (5) Agent signs short-lived JWTs with aud matching the URL and invokes each granted capability at default_location or at capability's own location if set.

Discovery document key fields

Important fields in the discovery document: issuer (provider's base URL matching Better Auth baseURL); endpoints (absolute URLs for each route, e.g., execute points at POST /capability/execute); default_location (full URL of default execute endpoint, always matches endpoints.execute, used by agents as JWT aud when capability has no custom URL and as request URL for those capabilities).

OpenAPI adapter - createFromOpenAPI

The createFromOpenAPI helper reads an OpenAPI 3.x spec and produces: capabilities (one per operationId), input/output JSON Schemas, a proxy onExecute handler, and optionally providerName/providerDescription from info. Every operation with an operationId becomes a capability whose name is that id. Path, query, header parameters plus JSON request body are merged into single input schema; 200/201 response body becomes output.

OpenAPI adapter upstream authentication

Use resolveHeaders in createFromOpenAPI options to inject credentials each request needs (e.g., internal service token or user-scoped access token). The function receives agentSession and returns headers to add to upstream API calls.

OpenAPI adapter default host capabilities

Control which capabilities are auto-granted to new hosts via defaultHostCapabilities: pass true (all), a single HTTP method string, an array of methods, or a callback receiving full runtime context.

OpenAPI adapter approval strength per method

Map HTTP methods to approvalStrength in createFromOpenAPI so mutating operations require stronger user verification (e.g., WebAuthn) while reads use normal session. Example: {GET: 'session', POST: 'webauthn', PUT: 'webauthn', DELETE: 'webauthn'}.

OpenAPI adapter per-capability location

When setting location in createFromOpenAPI, every derived capability gets that URL. Agents call it directly with the agent JWT instead of going through default execute endpoint. Useful when you want agents to hit the real API URL and handle the session in your own middleware rather than proxying through onExecute.

OpenAPI adapter individual helpers

The adapter exports lower-level helpers: fromOpenAPI(spec) returns Capability[] only (no handler, no host caps); createOpenAPIHandler(spec, opts) returns only the onExecute proxy handler so you can pair it with hand-written capabilities or filter the spec yourself.

Capability definition structure

Each capability has: name (identifier), description (human-readable), optional input (JSON Schema defining parameters), optional location (absolute URL agents call instead of default execute URL). When location is set, onExecute is not used for those requests.

Default execute vs custom location routing

No location: Agents POST to default_location (endpoints.execute) with {capability, arguments}. Plugin validates JWT and grant, then runs onExecute. With location: Agents call that URL directly (your REST handler, another service, etc.). onExecute does not run for that call. You must resolve agentSession in your handler using provided helpers and enforce grants/business logic.

Get agent session outside onExecute

For custom location routes or non-execute handlers, agents send Authorization: Bearer header with agent JWT. Use auth.api.getAgentSession({headers}) to run JWT verification in-process and return AgentSession or null. Alternatively use verifyAgentRequest(request, auth) when you have Request + auth. Verification includes signature, aud, replay (jti), expiry, and request-binding claims.

Check capability grants in custom handlers

After retrieving agentSession, inspect agentSession.agent.capabilityGrants (active DB grants intersected with JWT's capabilities claim). For each capability this route implements, ensure there is a matching grant with status='active'. If that grant has constraints, validate the request body the same way POST /capability/execute would—otherwise a client could bypass constraints by calling your custom URL.

Agent session object properties

The AgentSession object contains: agentSession.user (resolved user for the agent, delegated host user or resolveAutonomousUser result); agentSession.agent (id, name, mode, capabilityGrants, host id, metadata); agentSession.host (host record when agent is linked to a host). Types are exported from @better-auth/agent-auth.

JWT audience (aud) validation rules

The JWT aud must match what the server expects: No per-capability location: use default_location, endpoints.execute, issuer, or base URL values the plugin allows. With location: aud should be that same absolute URL. GET /capability/list includes location when set. Invalid location values fail at startup. Single capability in JWT: aud may equal that capability's location when set. Multiple capabilities in JWT: per-capability locations are not accepted as aud; use issuer, base path, or default execute endpoint. Behind reverse proxy, set trustProxy=true for Host/X-Forwarded-Proto alignment.

Filter visible capabilities with resolveCapabilities

Use resolveCapabilities to show different capability sets to different callers, such as plan-gated, user-specific, or organization-specific capabilities.

onExecute handler behavior

onExecute runs for capabilities using the default execute URL (no per-capability location). The plugin verifies the JWT including aud, attaches agentSession, checks the grant, then calls onExecute. Capabilities with custom location never hit this path—you handle them in your own route using session helpers. The handler receives {capability, arguments, agentSession}.

Agent Auth approval methods

The plugin supports two approval methods: device_authorization (browser-based approval with user code) and ciba (backchannel approval flows). Both are enabled by default. Restrict or customize with approvalMethods array and resolveApprovalMethod function.

Device approval UI requirement

The plugin does not render the device approval UI. Your app must provide the page referenced by deviceAuthorizationPage configuration option.

Agent Auth events and auditing

Use onEvent callback to capture important lifecycle events: agent creation and revocation, host creation and enrollment, capability requests and approvals, capability execution. This hook is suitable for writing audit logs or feeding analytics pipelines.

Agent Auth configuration options - providerName

providerName: string, not required. Human-readable provider name returned in discovery metadata.

Agent Auth configuration options - providerDescription

providerDescription: string, not required. Description returned in the discovery document.

Agent Auth configuration options - modes

modes: ('delegated' | 'autonomous')[], not required. Supported agent modes. Defaults to ['delegated', 'autonomous'].

Agent Auth configuration options - capabilities

capabilities: Capability[], not required. Capability definitions (name, description, optional input, optional absolute location—if set, agents call this URL instead of default_location and you use session helpers in your handler).

Agent Auth configuration options - onExecute

onExecute: function, not required. Handler for capabilities invoked via the default execute URL (default_location). Not called when the agent uses a custom per-capability location.

Agent Auth configuration options - requireAuthForCapabilities

requireAuthForCapabilities: boolean, not required. Require a host or agent JWT to list and describe capabilities.

Agent Auth configuration options - approvalMethods

approvalMethods: string[], not required. Supported approval methods. Defaults to ['ciba', 'device_authorization'].

Agent Auth configuration options - resolveApprovalMethod

resolveApprovalMethod: function, not required. Choose the approval method for a request.

Agent Auth configuration options - deviceAuthorizationPage

deviceAuthorizationPage: string, not required. Path or absolute URL for the user-facing device approval page.

Agent Auth configuration options - defaultHostCapabilities

defaultHostCapabilities: string[] | function, not required. Default capabilities applied to newly created hosts.

Agent Auth configuration options - allowDynamicHostRegistration

allowDynamicHostRegistration: boolean | function, not required. Allow unknown hosts to register dynamically.

Agent Auth configuration options - onEvent

onEvent: function, not required. Callback for audit and lifecycle events.

Agent Auth configuration options - trustProxy

trustProxy: boolean, not required. Trust X-Forwarded-Proto when validating JWT aud against request host (use behind a reverse proxy). Defaults to false.

Agent Auth plugin stability warning

The Agent Auth plugin is an implementation of a standard on heavy development. It is not yet stable and may change in the future. Report issues or bugs on Github at https://github.com/better-auth/agent-auth.

Example onExecute handler implementation

Example showing onExecute handler for 'deploy_project' and 'list_projects' capabilities. The handler receives {capability, arguments, agentSession}, checks capability name, and returns appropriate response. For deploy_project it returns {ok: true, projectId: args?.projectId, requestedBy: agentSession.user.id}.

Example createFromOpenAPI usage

Example showing how to use createFromOpenAPI. Fetch an OpenAPI spec, spread the result of createFromOpenAPI(spec, {baseUrl: 'https://api.example.com'}) into agentAuth plugin config. This automatically creates capabilities from operationIds and proxies requests to the upstream API.

Example custom location handler

Example showing POST handler for api/issues/route.ts that uses auth.api.getAgentSession({headers: request.headers}) to verify agent JWT, checks if agentSession exists, then checks agentSession.agent.capabilityGrants to allow/deny access to the 'create_issue' capability.

Example approval methods configuration

Example showing agentAuth config with approvalMethods: ['ciba', 'device_authorization'], resolveApprovalMethod callback that returns preferredMethod if supported else device_authorization, and deviceAuthorizationPage: '/device/capabilities'.

Give your agent this brain