@better-auth/agent-auth is better-auth’s attempt to add AI-agent support alongside a human-first auth library. It is marked “heavy development, not yet stable” in their repo as of 2026-03. If you started there to get agent identity with the broader better-auth feature set, moving to theAuth gives you a single codebase where agents are a first-class entity instead of a separate package bolted onto the user model.
Both libraries share the same ancestor on the human-auth side. Most of the familiar hooks keep their names. The agent story is the part that changes materially.
If you use the human-auth half of better-auth and not the agent plugin yet, read the general better-auth migration guide first, this page only covers the agent-plugin deltas.
Where the model diverges
better-auth treats an agent as an OAuth client attached to a user. A single-hop delegation is possible. There is no delegation chain tracking, no trust score, no cost attribution, no ephemeral session type, and no MCP OAuth 2.1 authorization server built in. theAuth treats an agent as a primary database entity with its own lifecycle:AgentIdentityrow in the schema, owned by a user, with status transitions (active,revoked,expired).- Multi-hop delegation chains with a per-call depth limit and cascading revocation of chains.
- Trust scoring, 5 levels, computed from the audit log.
- Cost attribution per agent, tool, and chain.
- An MCP OAuth 2.1 authorization server (
createMcpModule) that sits alongside the same instance and adapter. - Ephemeral agent sessions for one-off tasks (
createEphemeralSessionModule).
Concepts map
Server setup
emailAndPassword config key, its built-in password module authenticates by username (see Username and password). The rest of the human-auth config (organization, twoFactor, etc.) keeps a similar plugin shape, imported from @glinr/theauth/auth rather than @glinr/theauth/plugins. Check each feature’s page, the option names are not identical.
Creating an agent
scopes: ['github:read'] list maps to { resource: 'mcp:github:*', actions: ['read'] }. The extra structure pays for itself when you need to add rate caps, argument allowlists, or time windows. In a resource pattern, * matches the rest of the path from that position on, so mcp:github:* also covers mcp:github:repos:list. ownerId must be the id of an existing user (theauth_users).
Authorizing a tool call
Delegation
delegate throws. expiresAt is required.
Revocation works on chains, not on the parent agent. theauth.agent.revoke(parent.id) marks that agent revoked so its own calls are denied, but it does not touch the chains it already issued. Call theauth.delegation.revoke(chain.id) to cut the child off, which also revokes the chains the child delegated onward. Use theauth.delegation.listChains(agentId) to find them.
maxDepth is checked on each call to theauth.delegate: the new link’s depth must be less than or equal to the maxDepth you pass on that call (default 3). Depth is one more than the deepest active chain that ends at fromAgent. So maxDepth: 2 stops a third hop only if you pass it when creating that third link. Nothing stores a root-level cap that later calls inherit, so pass the same value from your delegation helper every time.
Trust scoring
@better-auth/agent-auth does not ship scoring. theAuth computes a 0-100 score from the audit history, mapped to five named levels. Useful as a gate for sensitive actions that should only run for agents with a clean track record.
MCP server
If you were running a separate MCP OAuth server alongside better-auth (because the@better-auth/mcp plugin is a thin OIDC wrapper without agent semantics), you can retire it. theAuth’s OAuth 2.1 server is a module you create with createMcpModule from @glinr/theauth/mcp and pass to your framework adapter. It does not take the theauth instance, and it has no built-in database: you supply the storage callbacks. MCP has a complete in-memory example of those callbacks.
mcpStore supplies storeClient, findClient, storeAuthorizationCode, consumeAuthorizationCode, storeToken, findTokenByRefreshToken, revokeToken, and resolveUserId. The adapter serves /mcp/register, /mcp/authorize, and /mcp/token, plus the two .well-known documents, all relative to its mount path (/api/theauth by default). MCP clients look for the .well-known documents at the root of your origin, so add root-level routes or rewrites when you mount under a prefix, see MCP.
Data migration
Agent rows in better-auth live in whatever table the plugin writes to (check the plugin’s schema migration). theAuth stores agents intheauth_agents and their permissions in theauth_permissions, and it keeps only the SHA-256 hash of the full kv_... token. A better-auth token hash cannot be reused: the bearer would have to be a kv_ token whose SHA-256 matches, which no old token is. So do not copy token hashes with SQL. Recreate each agent through the API and hand the owner a new token:
Cutover plan
- Stand up theAuth next to better-auth against the same database (or a shadow copy). Do not delete the better-auth schema yet.
- Import agents with
theauth.agent.create. Validate one new service token withtheauth.authorizeByToken(token, {...}). - Give a single non-critical service its new token and switch it to
theauth.authorizeByTokeninstead ofauth.api.verifyAgentToken. - Watch the audit log for
allowed: falseentries. Fix permission mappings. - Expand the theAuth-guarded agent surface one service at a time.
- Remove the
@better-auth/agent-authplugin fromlib/auth.tsonce no service still calls it.
Rollback
Keep the better-auth agent plugin wired for at least one rotation cycle after the cut-over. If you need to revert:- Re-enable the
agent()plugin inlib/auth.ts. - Point services back at
auth.api.verifyAgentToken. - theAuth agent rows remain, they just stop being read. Old better-auth bearers keep working on better-auth because you never revoked them there, new
kv_tokens only work against theAuth.
Runnable example
examples/migrate-from-better-auth-agent-plugin runs the AFTER patterns end-to-end: AgentIdentity creation, multi-hop delegation with maxDepth, authorize-falls-back-to-chain semantics, and cascading chain revocation. The script uses the monorepo workspace:* version so it tracks the released package, and a vitest smoke suite runs it in CI.
Next steps
Agent identity
The primary entity model and lifecycle.
Delegation chains
Multi-hop delegation with depth and cascading revocation.
Trust scoring
Graduated autonomy by audit history.
MCP OAuth 2.1
The authorization server the better-auth plugin does not ship.