# theAuth: full site content > Plain-markdown rendering of every page on https://theauth.dev, generated at build time. Index: https://theauth.dev/llms.txt --- URL: https://theauth.dev/ [New: MCP OAuth 2.1 authorization server](https://docs.theauth.dev/mcp) # Identity for humans, and the agents they send. theAuth is the open-source auth library that treats AI agents as first-class identities: scoped permissions, delegation chains with depth limits, an MCP OAuth 2.1 server, and an audit trail for every action. Passkeys, SSO and 14 human sign-in methods are included. [Read the quickstart](https://docs.theauth.dev/quickstart) [Star on GitHub](https://github.com/glincker/theauth) `npm install @glinr/theauth` `go get github.com/glincker/theauth-go/v2` - MIT licensed - 3 runtime deps - 2.45M policy evals/sec, p99 625 ns - Workers, Bun, Deno Works where you ship - TypeScript - Go - Python - Next.js - Hono - Cloudflare Workers - Bun - Deno - PostgreSQL - Svelte - Nuxt - Express What it is ## One auth layer for the people and the programs acting for them. 01 ### Agent identity kv_... mcp:github:* Every agent gets its own cryptographic bearer token and a set of permissions, instead of borrowing a human session. Each action is checked against those permissions and written to the audit trail, so you can answer who did what, and on whose behalf. - Cryptographic bearer tokens (kv_...) per agent - Wildcard permission matching, such as mcp:github:* - Delegation chains with configurable depth limits - CIBA-style approval flows for sensitive tool calls [Agent identity docs](https://docs.theauth.dev/agents) 02 ### MCP OAuth 2.1 An MCP client starts with only the MCP server URL, discovers the authorization server from metadata, registers, and authorizes with PKCE S256. theAuth issues the token, and the MCP server validates its signature, audience, scope and expiry before it runs the tool. An OAuth 2.1 authorization server for your MCP servers, built to the MCP authorization spec. Clients discover it, register, and authorize with PKCE S256 without you hand-rolling the flow. - PKCE with S256 on every authorization code flow - RFC 9728 and RFC 8414 metadata for discovery - RFC 8707 resource indicators, RFC 7591 client registration - Go: refresh token rotation with family revocation [MCP docs](https://docs.theauth.dev/mcp) 03 ### Human auth People sign in with the methods you enable, such as passkeys, magic links, OAuth providers and TOTP two-factor codes. theAuth turns a successful sign-in into one session that your app reads. The sign-in side is covered too: 14 methods and 17 OAuth providers, plus organizations, SSO and SCIM. Every agent is created with an owner (`ownerId`), so a human is always accountable for what it does. - Passkeys (WebAuthn), TOTP 2FA, magic link, email OTP - Email and password with HIBP breach check - 17 OAuth providers plus a generic OIDC factory - Organizations with RBAC, SAML 2.0 and OIDC SSO, SCIM 2.0 [Human auth docs](https://docs.theauth.dev/auth) Agent lifecycle ## From first credential to instant revoke Five moments in the life of one agent. Scroll to step through them, or use the list. agent credentialactive scopes mcp:github:* [read]file:reports/* [read] delegationmaxDepth 2 - plannermcp:github:* [read, comment] - code-reviewermcp:github:pulls [read, comment] - diff-fetchermcp:github:pulls [read] Each hop can only narrow. A wider request is refused when the link is created. approval neededpending **github-reader** wants to delete file:prod-data/export.csv Approve onceDeny The agent waits. A denial or a timeout means no. audit loggithub-reader - allow read mcp:github:repos aud_71c2 - allow read mcp:github:pulls aud_71c3 - hold delete file:prod-data/* aud_71c4 - deny read mcp:slack:channels aud_71c5 agents1 revoked **github-reader revoked** authorize() => allowed: false Links created downstream of this agent are revoked with it. It applies on the next call, not to work already run. How it works ## How an agent call gets authorized 1 ### Create the agent with scoped permissions Give the agent an owner, a name and the resources and actions it may touch, such as read on mcp:github:*. 2 ### Delegate to sub-agents with a depth limit Agents can hand work to other agents through delegation chains, and the chain depth is capped by configuration. 3 ### Authorize each action at the MCP server Before a tool runs, ask the auth layer whether this agent may perform this action on this resource. 4 ### Read the audit trail Every decision is recorded per agent, so you can trace an action back to the agent and its owner. [Agents docs](https://docs.theauth.dev/agents) agent.ts ```ts const agent = await auth.agent.create({ ownerId: "user-123", name: "github-reader", type: "autonomous", permissions: [{ resource: "mcp:github:*", actions: ["read"] }], }); const result = await auth.authorize(agent.id, { action: "read", resource: "mcp:github:repos", }); // { allowed: true, auditId: "aud_..." } ``` main.go ```go a, _ := theauth.New(theauth.Config{ Storage: memory.New(), BaseURL: "http://localhost:8080", }) r := chi.NewRouter() a.Mount(r) // /auth/* magic-link, email-password, OAuth, passkeys, TOTP, SAML r.With(a.RequireAuth()).Get("/me", func(w http.ResponseWriter, r *http.Request) { user, _ := theauth.UserFromContext(r.Context()) w.Write([]byte("hello " + user.Email)) }) http.ListenAndServe(":8080", r) ``` Go ships the OAuth 2.1 and MCP authorization server as a library, so it mounts into your existing router. { allowed: true, auditId: "aud_..." } What travels with an agent ## Every call carries its limits An agent identity is more than a key. Scope, spend, lifetime, trust and the key it is bound to are checked on every call, not once at login. - read:calendar what it may touch - $5.00 budget policy cap - 15m credential lifetime - 0.92 trust score from anomaly detection - DPoP token bound to a client key (Go AS) - 2/3 delegation depth used Values are examples. Hover the hub to pause it. Standards ## Built on the specs, not around them ### MCP authorization - RFC 9728 - RFC 8707 - RFC 8414 - RFC 7591 - CIMD ### OAuth 2.1 - PKCE S256 - Refresh rotation, family revocation - RFC 8693 token exchange - RFC 9449 DPoP - RFC 9126 PAR - RFC 9101 JAR - RFC 9509 CIBA ### Identity - WebAuthn / FIDO2 passkeys - SAML 2.0 - SCIM 2.0 - OIDC ### Supply chain - SLSA level 3 provenance - Sigstore-signed SBOM - MIT Token exchange, DPoP, PAR, JAR, CIBA, CIMD and the SLSA and SBOM items apply to the Go library, where releases carry the provenance. Row by row status for both libraries is on [the features index](https://theauth.dev/features/), and release and stability policy is under [open source and transparency](https://theauth.dev/open/). 2.45M policy evaluations per second, warm cache, p99 625 ns Reproducible: `pnpm bench` in `packages/core/bench`. [Method and full results](https://theauth.dev/benchmarks/) Compliance reports map to the EU AI Act, NIST, SOC 2 and ISO 42001. They are reports, not certifications. SDKs and adapters ## One auth model, three languages and a Terraform provider TypeScript is the reference implementation. The Go and Python SDKs talk to the same concepts: agents, permissions, delegation and audit. Versions below are pre-1.0 where noted. ### TypeScript packages Core is at 0.5.0 and the other packages are 0.x, so expect API movement before 1.0. Core runs on Node, Bun, Deno and Cloudflare Workers. - @glinr/theauthCore: agents, auth, MCP server `npm i @glinr/theauth` - @glinr/theauth-clientBrowser and Node client `npm i @glinr/theauth-client` - @glinr/theauth-reactReact hooks and components `npm i @glinr/theauth-react` - @glinr/theauth-vueVue bindings `npm i @glinr/theauth-vue` - @glinr/theauth-svelteSvelte bindings `npm i @glinr/theauth-svelte` - @glinr/theauth-expoExpo and React Native `npm i @glinr/theauth-expo` - @glinr/theauth-electronElectron apps `npm i @glinr/theauth-electron` - @glinr/theauth-cliCommand line tool `npm i @glinr/theauth-cli` - @glinr/theauth-gatewayAPI gateway `npm i @glinr/theauth-gateway` - @glinr/create-theauth-appProject scaffolder `npx @glinr/create-theauth-app` #### Framework adapters - Next.js - SvelteKit - Nuxt - Hono - Express - Fastify - Astro - NestJS - SolidStart - TanStack Start **Databases:** SQLite, PostgreSQL, MySQL and Cloudflare D1 are built into core. A Prisma adapter shares an existing PrismaClient. [Adapter docs](https://docs.theauth.dev/adapters) ### Go: theauth-go Requires Go 1.25 or newer. Storage backends are Postgres, MySQL and in-memory. Observability is OpenTelemetry and Prometheus, and audit events can go to webhook or Splunk HEC sinks. `go get github.com/glincker/theauth-go/v2` - StoragePostgres, MySQL, in-memory - Go version1.25+ - mcpresourceZero-dependency module for MCP resource servers - ReleasesSLSA level 3 provenance, Sigstore-signed SBOM [Go docs](https://pkg.go.dev/github.com/glincker/theauth-go/v2) [pkg.go.dev](https://pkg.go.dev/github.com/glincker/theauth-go/v2) [GitHub](https://github.com/glincker/theauth-go) ### Python: theauth An async-capable client built on httpx. Version 0.1.0, marked Beta, and not yet published to PyPI, so install it from the repository for now. `pip install "git+https://github.com/glincker/theauth.git#subdirectory=sdks/python"` - Python3.9+ - HTTPhttpx (the only runtime dependency) - Version0.1.0, Beta - LicenseMIT [Source on GitHub](https://github.com/glincker/theauth/tree/main/sdks/python) [Quickstart](https://docs.theauth.dev/quickstart) ### Terraform provider Manage agents, permissions, API keys and organizations as Terraform resources, so every grant goes through code review. **Not published to a registry yet:** the README at 0.1.0 describes building from source and using a dev override. - Resourcestheauth_agent, theauth_permission, theauth_api_key, theauth_organization - Data sourcestheauth_agent, theauth_agents - RequiresTerraform 1.5+, Go 1.21+ to build, a running theAuth deployment - Version0.1.0 [Source on GitHub](https://github.com/glincker/theauth) [Docs](https://docs.theauth.dev) Self-host or Cloud ## Self-host it, or run it on our Cloud The library is the product. Run it yourself under MIT, or let us host it. Cloud is in early access. Self-hosted ### Your database, your infrastructure - MIT licensed, so there is no license fee and no per-MAU charge from us. - Runs against your own SQLite, PostgreSQL, MySQL or Cloudflare D1 database. - Runs on Cloudflare Workers, Bun and Deno without code changes. - Three runtime dependencies in the TypeScript core: drizzle-orm, jose and zod. - You operate it: upgrades, backups and uptime are yours. [Self-host quickstart](https://docs.theauth.dev/quickstart) Cloud Early access ### Hosted theAuth - Managed theAuth on Cloudflare Workers, so you skip running the server yourself. - Dashboard for agents, API keys and audit logs. - Same open-source library underneath, so you can move to self-hosting later. - Early access: pricing is not published yet. [Ask about early access](https://github.com/glincker/theauth/discussions) ### Enterprise capabilities What ships in the library today. Compliance items are reports mapped to frameworks, not certifications. ### How it compares Feature comparison of Auth0, Clerk, Better Auth and theAuth | Feature | Auth0 | Clerk | Better Auth | theAuth | | --- | --- | --- | --- | --- | | Source license | No, Proprietary | No, Proprietary | Yes, MIT | Yes, MIT | | Self-hostable | Partial or different, Managed private cloud only | No, No | Yes, Yes | Yes, Yes | | OAuth 2.1 server for MCP | Yes, Yes | Yes, Yes | Yes, Yes | Yes, Yes | | Agent identity as its own model | Partial or different, Add-on: Token Vault, CIBA | Partial or different, Not found in docs | Partial or different, Plugin, not yet stable | Yes, Yes, core | | Enterprise SSO | Yes, Yes | Yes, Yes | Partial or different, Plugin | Yes, SAML 2.0, OIDC, SCIM | Checked against each vendor's public docs on 2026-10-07. Vendors change fast, so verify against their docs. [Full comparisons](https://theauth.dev/compare/) FAQ ## Questions developers ask first Short answers, taken from the repositories. Anything not covered is in the [docs](https://docs.theauth.dev) or [GitHub Discussions](https://github.com/glincker/theauth/discussions). **What is theAuth?** theAuth is an open-source auth library for AI agents and humans, built by [GLINCKER](https://glincker.com), the open-source division of [GLINR STUDIOS](https://glinr.com). It handles human sign-in (passkeys, OAuth, SSO) and gives each AI agent its own identity, scoped permissions and audit trail. It also ships an MCP OAuth 2.1 authorization server. SDKs exist for TypeScript, Go and Python. **Is theAuth an Auth0 alternative for AI agents?** It can be, if you want agent identity and delegation chains in the same library as human auth, MIT licensed and self-hostable. Auth0 is a mature hosted product that now has its own MCP authorization and AI agent features, so compare both against your requirements. The [Auth0 comparison](https://theauth.dev/compare/auth0/) lists what each covers, with sources. **How do I secure an MCP server with theAuth?** Run theAuth as the OAuth 2.1 authorization server for your MCP server. It supports PKCE S256 and the RFCs MCP clients expect: 9728 protected resource metadata, 8707 resource indicators, 8414 server metadata and 7591 dynamic client registration. Your MCP server then validates the issued tokens, and in Go the zero-dependency [theauth-go/mcpresource](https://pkg.go.dev/github.com/glincker/theauth-go/v2) module covers that resource-server role. The [MCP guide](https://docs.theauth.dev/mcp) walks through setup. **How are AI agents modeled differently from API keys?** An API key is a shared secret for a service. A theAuth agent is an identity with an owner, a cryptographic bearer token, wildcard permissions such as mcp:github:*, and delegation chains with configurable depth limits. Agents can also carry budget policies and a trust score, sensitive tool calls can require CIBA-style approval, and every action lands in a per-agent audit trail. API keys still exist for server-to-server access, managed separately. **Can I self-host it and where does it run?** Yes. theAuth is MIT licensed and runs against your own database: SQLite, PostgreSQL, MySQL or Cloudflare D1 in TypeScript, and Postgres, MySQL or in-memory storage in Go. The TypeScript core runs on Cloudflare Workers, Deno and Bun without code changes, with three runtime dependencies: drizzle-orm, jose and zod. A hosted Cloud version is in early access. **Which languages and frameworks are supported?** TypeScript has the broadest coverage: core, client, React, Vue, Svelte, Expo and Electron packages, plus adapters for Next.js, SvelteKit, Nuxt, Hono, Express, Fastify, Astro, NestJS, SolidStart and TanStack Start. Go has [theauth-go](https://pkg.go.dev/github.com/glincker/theauth-go/v2) (Go 1.25+). Python has a pip package (Python 3.9+, httpx client) at version 0.1.0. A Terraform provider exists in the repository and is built from source. **What is the license and who maintains it?** theAuth is MIT licensed. It is maintained by [GLINCKER](https://glincker.com), the open-source division of [GLINR STUDIOS](https://glinr.com), in the open on [GitHub](https://github.com/glincker/theauth). Compliance reports map to the EU AI Act, NIST, SOC 2 and ISO 42001, but they are reports, not certifications. --- URL: https://theauth.dev/agent-identity/ Agent identity # Identity for AI agents An agent is not a user and not a shared API key. In theAuth it is an identity with an owner, its own kv_ bearer token, scoped permissions, an optional expiry and an audit row for every decision. [Read the quickstart](https://docs.theauth.dev/quickstart) [Agents docs](https://docs.theauth.dev/agents) agent recordactive authorize(agent.id, read, mcp:github:repos) => allowed, auditId aud_... Agent lifecycle ## From first credential to instant revoke Five moments in the life of one agent. Scroll to step through them, or use the list. agent credentialactive scopes mcp:github:* [read]file:reports/* [read] delegationmaxDepth 2 - plannermcp:github:* [read, comment] - code-reviewermcp:github:pulls [read, comment] - diff-fetchermcp:github:pulls [read] Each hop can only narrow. A wider request is refused when the link is created. approval neededpending **github-reader** wants to delete file:prod-data/export.csv Approve onceDeny The agent waits. A denial or a timeout means no. audit loggithub-reader - allow read mcp:github:repos aud_71c2 - allow read mcp:github:pulls aud_71c3 - hold delete file:prod-data/* aud_71c4 - deny read mcp:slack:channels aud_71c5 agents1 revoked **github-reader revoked** authorize() => allowed: false Links created downstream of this agent are revoked with it. It applies on the next call, not to work already run. Anatomy ## What the token is, and is not Tokens are kv_ plus 32 random bytes. The plaintext is returned once at creation. Only a SHA-256 hash is stored, so a database dump does not reveal a live token. Rotation issues a new token and invalidates the old one. type: autonomousRuns unattended with the permissions declared at creation. type: delegatedReceives permissions through a delegation chain. Suited to short-lived sub-agents. type: serviceLong-lived identity for infrastructure such as an MCP server. limitsDefault cap of 10 active agents per user, configurable with agents.maxPerUser. revokePermanent. Later authorize calls return allowed: false. Permissions ## Wildcard matching, then constraints A permission is a colon-separated resource pattern plus actions. A * segment matches everything from that position on. Constraints must all pass: maxCallsPerHour, allowedArgPatterns, timeWindow (UTC), ipAllowlist (CIDR) and requireApproval. Matching behavior from the policy source (policy/abac.ts) | Pattern | Resource | Match | | --- | --- | --- | | mcp:github:* | mcp:github:repos | Yes | | mcp:github:* | mcp:github:repos:comments | Yes, * covers the remaining segments | | mcp:github:* | mcp:slack:channels | No | | mcp:github:repos | mcp:github:repos:comments | No, exact patterns must match in length | | * | any | Yes | How a delegation chain is checked ## Narrow at every hop, capped by depth An orchestrator hands a subset of its permissions to a sub-agent. Two checks run when the link is created, and more run on every call. 1. human**user-123** - mcp:github:* [read, comment] - mcp:slack:* [read] - file:reports/* [read] 2. agent**planner** - mcp:github:* [read, comment] - mcp:slack:* [read] - file:reports/* [read] 3. sub-agent**diff-fetcher** - mcp:github:pulls [read] - mcp:github:* [read, comment] Struck-through scopes are what the previous holder had and this hop does not. A link can only hand down a subset of what its parent holds, and the depth limit stops the chain at maxDepth. 1. plannerautonomous mcp:github:* [read, write, comment] delegate(planner, code-reviewer, mcp:github:pulls [read, comment], maxDepth 2) **Subset.** The parent must hold every permission it hands over. Wider resources or new actions are rejected. 2. code-reviewerdelegated, depth 1 mcp:github:pulls [read, comment] delegate(code-reviewer, diff-fetcher, ..., maxDepth 2) **Depth.** New depth is the deepest incoming link plus one. It must not exceed this call's maxDepth (default 3). Depth 2 passes. 3. diff-fetcherdelegated, depth 2 mcp:github:pulls [read] delegate(diff-fetcher, another-agent, ..., maxDepth 2) **Rejected.** Depth 3 exceeds the maximum of 2, which prevents unbounded chains. 4. another-agentno link created On every authorize() call 1. A**Status.** The agent must exist and be active, not revoked or expired. 2. B**Own permissions.** Pattern, action and constraints are evaluated first. 3. C**Delegated permissions.** If B denies, grants from active, unexpired chains are tried. 4. D**Audit.** The decision is written and its auditId returned. Revoking a link also revokes every link created downstream of it. It takes effect on the next authorize call, not on operations already running. Delegated grants carry resource and actions only. See [delegation docs](https://docs.theauth.dev/delegation). Sensitive actions ## Approval, budgets and audit ### Denied until approved A permission with `requireApproval: true` is denied. Your app catches the denial. ### Request created `approval.request()` persists it with a default TTL of 5 minutes and fires your `webhookUrl` or `onApprovalNeeded`. ### Human decides Your UI calls `approval.approve()` or `deny()`. Delivering the notification is your app's job. ### Agent retries The retried action passes the permission check once the request is approved. - **Budget policies** cap token cost and call counts per agent, user or tenant. On breach: warn, throttle, block or revoke. [Budget docs](https://docs.theauth.dev/budget-policies). - **Audit trail.** Each entry records agent, owner, action, resource, parameters, result (allowed, denied, rate_limited), duration and timestamp. Export as JSON or CSV. [Audit docs](https://docs.theauth.dev/audit). - **Trust score.** Each agent gets a 0 to 100 score from its age, call volume and audit history. See [trust scoring](https://docs.theauth.dev/trust). Automatic anomaly detection is not shipped: the `anomaly.detected` event name is reserved, but nothing emits it yet. Honest limit Approval requests are stored by theAuth, but it ships no approval UI and does not deliver the notification. You build that step. Create and authorize ## Create an agent, authorize an action The same calls run on Postgres, SQLite, MySQL or D1. Go has its own agent model on top of OAuth client credentials, documented in the [Go package](https://pkg.go.dev/github.com/glincker/theauth-go/v2). agent.ts ```ts import { createTheAuth } from "@glinr/theauth"; const auth = await createTheAuth({ database: { provider: "postgres", url: process.env.DATABASE_URL }, }); // Create an AI agent with scoped MCP permissions const agent = await auth.agent.create({ ownerId: "user-123", name: "github-reader", type: "autonomous", permissions: [{ resource: "mcp:github:*", actions: ["read"] }], }); const result = await auth.authorize(agent.id, { action: "read", resource: "mcp:github:repos", }); // { allowed: true, auditId: "aud_..." } ``` Your code calls authorize() for an agent: theAuth checks the agent's permissions, writes the decision to the audit log and returns allowed plus an auditId before the action runs on your MCP server or API. Compared ## Agent identity, shared API keys, human sessions General patterns, not claims about any vendor. A shared key is often the right call for one service talking to one API you control. | Question | Shared API key | Human session | theAuth agent | | --- | --- | --- | --- | | Who is it? | Whoever holds the string | A person at a browser | One named agent with an owner | | Scope | Whatever the key allows, usually coarse | The user's full rights | Resource and action patterns plus constraints | | Handing work to a sub-agent | Copy the key | Not designed for it | Narrower delegation with a depth cap | | Attribution in logs | The key, not the caller | The user, not the agent | Per agent and owner on every decision | | Stopping one caller | Rotate for everyone | End the session | Revoke or rotate one agent | | Human sign-off | Build it yourself | The user is already present | requireApproval constraint | - [MCP OAuth 2.1 server](https://theauth.dev/mcp-oauth/) - [Human auth](https://theauth.dev/human-auth/) - [Security](https://theauth.dev/security/) - [Agents on the homepage](https://theauth.dev/#agents) [DPoP, CIBA and device flow](https://theauth.dev/agent-oauth/) [Delegated authorization for multi-agent systems](https://theauth.dev/use-cases/multi-agent/) [Auth0 alternative for agents](https://theauth.dev/compare/auth0/) --- URL: https://theauth.dev/human-auth/ Human auth # Sign-in for the humans who own agents Each method is a plugin you opt into. Use passkeys, OAuth, magic links or SSO for people, and keep agent identity separate. [Browse auth methods](https://docs.theauth.dev/auth) [Quickstart](https://docs.theauth.dev/quickstart) Methods ## All 14 methods 1. 01Email and passwordTS: PBKDF2-SHA256, optional HIBP check 2. 02Username and passwordHandles instead of email 3. 03Magic linkSigned, single-use email link 4. 04Email OTPSix-digit code by email 5. 05Phone SMSCode through any SMS provider 6. 06Passkey / WebAuthnTouch ID, Face ID, security keys 7. 07TOTP 2FAAny RFC 6238 authenticator, backup codes 8. 08AnonymousSessions without an account 9. 09Google One TapGoogle sign-in prompt 10. 10Sign In With EthereumEIP-4361 wallet sign-in 11. 11Device authorizationFor TVs and CLIs 12. 12CaptchaBot checks on auth endpoints 13. 13Password resetToken-based reset flow 14. 14Session freshnessRequire a recent sign-in for sensitive actions OAuth ## 17 providers, plus generic OIDC Every provider is configured the same way through the oauth() plugin. The ids below are the first-class providers in the source. Apple is the exception to the pattern: it needs a signed ES256 JWT client secret that you generate yourself and pass in. - Appleapple - Atlassianatlassian - Discorddiscord - Dropboxdropbox - Figmafigma - GitHubgithub - GitLabgitlab - Googlegoogle - LinkedInlinkedin - Microsoftmicrosoft - Notionnotion - Redditreddit - Slackslack - Spotifyspotify - Twitchtwitch - Twitter/Xtwitter - Zoomzoom - Any other OIDC providergenericOIDC() Details ## Passkeys, TOTP, SSO, organizations - **Passkeys.** WebAuthn with Touch ID, Face ID, Windows Hello or hardware keys, through the passkey() plugin. [Passkey docs](https://docs.theauth.dev/auth/passkey). - **TOTP.** The twoFactor() plugin adds QR enrollment, six-digit codes and backup codes. [Two-factor docs](https://docs.theauth.dev/auth/two-factor). - **Magic link.** Signed, single-use links with configurable expiry. [Magic link docs](https://docs.theauth.dev/auth/magic-link). - **SSO basics.** SAML 2.0 and OIDC connections, such as Okta or Azure AD, with just-in-time provisioning. [SSO docs](https://docs.theauth.dev/auth/sso). - **Organizations.** Create orgs, invite members, assign roles, cap membership. [Organization docs](https://docs.theauth.dev/auth/organizations). - **Passwords.** TypeScript hashes with PBKDF2-SHA256. Go uses Argon2id. Signing in without a browser ### Approve the CLI from your phone terminal@glinr/theauth-cli ```sh $ theauth login --server https://app.example.com/api/theauth Open https://app.example.com/device and enter the code: WDJB-MJHT (or open https://app.example.com/device?user_code=WDJB-MJHT) waiting for approval (polling the token endpoint) Logged in to https://app.example.com/api/theauth as user-123. $ theauth whoami ada@example.com (https://app.example.com/api/theauth) ``` /device Nothing to approve yet Signed in as ada@example.com /device Sign in theauth-cli? Code WDJB-MJHT. Only approve if you started this in your own terminal. ApproveDeny /device Approved Return to your terminal. The code works once. 1. Run theauth login. The CLI asks the server for a device code. 2. It prints a short code and opens the verification page. 3. You approve on any device where you are signed in. The CLI polls meanwhile. 4. The server returns a token. The CLI stores it with mode 0600. 5. Later commands such as whoami reuse it. This is the CLI login in the TypeScript SDK (RFC 8628 device authorization). The terminal text is from the CLI source; the code, host and email are examples. The Go server's device grant is a separate open pull request. auth.ts ```ts import { createTheAuth } from "@glinr/theauth"; import { emailPassword, passkey } from "@glinr/theauth/auth"; const auth = await createTheAuth({ database: { provider: "postgres", url: process.env.DATABASE_URL }, plugins: [emailPassword(), passkey()], }); ``` Frameworks ## Adapters Core databases: SQLite, PostgreSQL, MySQL and Cloudflare D1. Client packages exist for React, Vue, Svelte, Expo and Electron. - Next.js `@glinr/theauth-nextjs` - SvelteKit `@glinr/theauth-sveltekit` - Nuxt `@glinr/theauth-nuxt` - Hono `@glinr/theauth-hono` - Express `@glinr/theauth-express` - Fastify `@glinr/theauth-fastify` - Astro `@glinr/theauth-astro` - NestJS `@glinr/theauth-nestjs` - SolidStart `@glinr/theauth-solidstart` - TanStack Start `@glinr/theauth-tanstack` - Prisma `@glinr/theauth-prisma` - [Adapter docs](https://docs.theauth.dev/adapters) - [Agent identity](https://theauth.dev/agent-identity/) - [Enterprise](https://theauth.dev/enterprise/) - [Human auth on the homepage](https://theauth.dev/#human) [Passkeys and device flow](https://theauth.dev/agent-oauth/) [Open source auth for TypeScript](https://theauth.dev/get-started/) [Clerk alternative](https://theauth.dev/compare/clerk/) --- URL: https://theauth.dev/mcp-oauth/ MCP authorization # MCP OAuth 2.1 authorization server Secure an MCP server with an authorization server you host. theAuth implements the discovery, registration and token steps MCP clients expect, and adds agent identity and delegation chains behind the token. [Read the MCP guide](https://docs.theauth.dev/mcp) [mcpresource on pkg.go.dev](https://pkg.go.dev/github.com/glincker/theauth-go/mcpresource) Discover, register, get a token ## What an MCP client does, step by step The client starts knowing only the MCP server URL. Everything else is discovered. Client to resource server ### Call without a token The MCP server answers 401 with a `WWW-Authenticate: Bearer` header that points at its resource metadata (RFC 6750, RFC 9728). Client to resource server ### Read protected resource metadata `GET /.well-known/oauth-protected-resource` names the resource and its authorization servers (RFC 9728). Client to authorization server ### Read server metadata `GET /.well-known/oauth-authorization-server` lists endpoints and `code_challenge_methods_supported: ["S256"]` (RFC 8414). Client to authorization server ### Register Dynamic registration (RFC 7591), or in Go a CIMD client whose `client_id` is an https URL the server fetches (MCP spec 2025-11-25). Client to authorization server ### Authorize with PKCE The client sends a PKCE S256 challenge and a `resource` indicator (RFC 8707). The user consents and a code returns. Client to authorization server ### Exchange the code The code and verifier go to the token endpoint. The access token is bound to the audience. Client to resource server ### Call with the token The MCP server validates signature, audience, scope and expiry before running the tool. Endpoint URLs are advertised in the metadata, so clients do not hard-code them. The TypeScript server serves `/mcp/register`, `/mcp/authorize` and `/mcp/token`. The Go server serves `/oauth/register`, `/oauth/authorize` and `/oauth/token`. The token it issues ## Read the token one claim at a time What a resource server sees once the client has its token, and what each claim is for. access token payload (decoded, example) ```json { "sub": "user-123", "act": { "sub": "agt_planner" }, "aud": "https://mcp.example.com", "scope": "read:calendar", "cnf": { "jkt": "0ZcOCORZ..." }, "exp": 1790000900 } ``` 1. subWho the token speaks for: the human who owns the grant. 2. actWho is acting. After an RFC 8693 token exchange the agent appears here, so the resource server sees both the owner and the actor. 3. audThe one resource server this token is for (RFC 8707 resource indicator). Any other server should refuse it. 4. scopeWhat it may do. An exchange can narrow scope, never widen it. 5. cnf.jktRFC 9449 DPoP binding: the thumbprint of the client key. A stolen token without that key is not accepted. 6. expExpiry. Short lifetimes limit what a leak is worth. The Go server defaults to one hour and lets you shorten it. Values are made up. act and cnf.jkt appear in the Go authorization server (token exchange and DPoP are opt-in features). Claim names follow the RFCs. Go ## CIMD, rotation and the resource module - **CIMD.** When enabled, a `client_id` that is an https URL is resolved by fetching a metadata document. The document's `client_id` must equal the URL it was fetched from. The trust policy defaults to deny all; you opt in with `AllowHTTPSHosts` or `AllowAnyHTTPS`. - **Refresh rotation with family revocation.** Presenting an already-used refresh token revokes the whole token family (RFC 9700). - **mcpresource.** A standalone Go module with no dependencies outside the standard library. It checks the JWT against a cached JWKS, enforces audience, and walks the RFC 8693 actor chain through introspection. Revocation reaches it within the cache TTL, 60 seconds by default. - **More Go grants.** RFC 8693 token exchange, 9449 DPoP, 9126 PAR, 9101 JAR and 9509 CIBA. main.go ```go // Resource server: go get github.com/glincker/theauth-go/mcpresource v := mcpresource.New( "https://mcp.example.com", mcpresource.WithJWKS("https://as.example.com/oauth/jwks"), mcpresource.WithIntrospection( "https://as.example.com/oauth/introspect", "mcp-client-id", "mcp-client-secret", ), ) r := chi.NewRouter() r.Use(v.Middleware) // JWT validation, audience check, actor-chain walk r.Get("/tools/run", func(w http.ResponseWriter, r *http.Request) { p, _ := v.Principal(r.Context()) // p.Subject (user), p.Actor (final agent), p.ActorChain (delegation path) }) ``` Runnable example: [examples/mcp-server](https://github.com/glincker/theauth-go/tree/main/examples/mcp-server). auth.ts ```ts import { createTheAuth } from "@glinr/theauth"; const auth = await createTheAuth({ database: { provider: "postgres", url: process.env.DATABASE_URL }, mcp: { enabled: true, issuer: "https://auth.yourapp.com", baseUrl: "https://auth.yourapp.com", signingSecret: process.env.MCP_SIGNING_SECRET, }, }); ``` TypeScript ## Enable it in the core Mount the MCP routes through a framework adapter, then validate tokens with auth.mcp.validate(token) or the adapter's withMcpAuth middleware. TypeScript access tokens are HS256 at+jwt signed with your secret, so validation happens in the same deployment. The Go server signs with Ed25519 and publishes a JWKS, which lets separate resource servers verify tokens on their own. Where it fits ## What differs from other options Other identity products also document MCP OAuth support, so the protocol alone is not the difference. What theAuth adds: - [Agent identity and delegation chains](https://theauth.dev/agent-identity/) behind the same tokens, with per-agent audit. - MIT license and self-hosting on your own database. - A zero-dependency Go resource-server module. Choose another tool if you already run a hosted identity provider that meets your MCP needs and you do not need agent-level identity or self-hosting. - [Agent identity](https://theauth.dev/agent-identity/) - [Security](https://theauth.dev/security/) - [MCP on the homepage](https://theauth.dev/#mcp) - [MCP authorization spec](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization) [DPoP and device flow for agents](https://theauth.dev/agent-oauth/) [Secure an MCP server in TypeScript](https://theauth.dev/guides/mcp-server-typescript/) [Better Auth alternative](https://theauth.dev/compare/better-auth/) [Auth0 for MCP compared](https://theauth.dev/compare/auth0-for-mcp/) --- URL: https://theauth.dev/enterprise/ Enterprise # Enterprise controls, self-hosted Organizations, SSO, directory sync and audit export in the same MIT-licensed library as agent identity. You run it, so the data stays in your database. [Talk to us in Discussions](https://github.com/glincker/theauth/discussions) [Quickstart](https://docs.theauth.dev/quickstart) ## Enterprise datasheet **Datasheet**TypeScript core unless noted Identity and access Audit and data Go also ships a SAML 2.0 service provider, SCIM 2.0 and RBAC. See the [Go package](https://pkg.go.dev/github.com/glincker/theauth-go/v2). SSO connections link an organization to an identity provider over SAML 2.0 or OIDC, and a SCIM 2.0 endpoint takes users and groups from the customer's directory. Agents can carry a tenantId so you can list them by tenant; enforcing tenant boundaries stays in your own resource checks. audit.go ```go sink, err := splunkhec.New("https://splunk.example.com:8088", os.Getenv("SPLUNK_HEC_TOKEN")) if err != nil { log.Fatal(err) } a, _ := theauth.New(theauth.Config{ Storage: store, BaseURL: "https://myapp.com", Audit: &theauth.AuditConfig{ Sinks: []theauth.AuditSink{sink}, }, }) ``` Audit export ## Stream audit events to your SIEM The Go audit log is append-only and asynchronous. If the buffer fills, events are dropped and counted rather than slowing sign-in. A failing sink never blocks storage writes. Compliance mapping ## Mapped, not certified These are evidence aids for your own assessment. theAuth holds no certification against any of them. - EU AI ActAudit records for record-keeping (Article 12), approval gates and depth limits for human oversight (Article 14).mapping - NISTIdentity provenance, least-privilege permissions, revocation and expiry, audit trail.mapping - SOC 2Access control, agent limits, role-based grants and event logging mapped to CC6 and CC7.mapping - ISO 42001Logged inputs, results and durations mapped to Annex A.8.mapping Contact No sales channel is documented. Questions about enterprise needs go to [GitHub Discussions](https://github.com/glincker/theauth/discussions). Pricing is on the [pricing page](https://theauth.dev/pricing/). - [Security](https://theauth.dev/security/) - [Human auth](https://theauth.dev/human-auth/) - [Agent identity](https://theauth.dev/agent-identity/) - [Trust on the homepage](https://theauth.dev/#trust) --- URL: https://theauth.dev/pricing/ Pricing # Free to self-host. Cloud is early access. The library is MIT licensed. theAuth Cloud has no published prices, and this page will not invent any. ## Two ways to run theAuth Library MIT FreeYou run it on your own database and hosting - Agent identity, MCP OAuth 2.1 server and human auth - TypeScript, Go and Python SDKs - Postgres, SQLite, MySQL, D1 (Go: Postgres, MySQL, in-memory) [Read the quickstart](https://docs.theauth.dev/quickstart) theAuth Cloud Early access Not priced yetNo public prices, no published limits - A managed option for teams that would rather not operate auth - Scope and terms are still being decided [Ask in GitHub Discussions](https://github.com/glincker/theauth/discussions) Total cost ## Think in cost of ownership, not a price per user In general terms, and without comparing any vendor's prices: - Per-MAU pricingThe bill grows with active users, and with agents if they count as identities. Cheap at small scale, harder to forecast at large scale. - Self-hostingNo per-user meter. You pay for a database, compute and the engineering time to patch, monitor and back it up. - Switching costAn open license and a database you own make leaving cheaper. Hosted identity data is harder to move. - What to modelUsers and agents at 12 and 36 months, ops hours, compliance work, and the cost of an outage. FAQ ## Pricing questions **Is theAuth free?** The library is MIT licensed and free to self-host, including the MCP OAuth 2.1 server, agent identity and human auth. You pay for your own database and hosting. **How much does theAuth Cloud cost?** theAuth Cloud is in early access and has no published prices yet. We will not quote numbers until they are public and approved. **How do I get early access to theAuth Cloud?** Ask in GitHub Discussions on the theauth repository. That is the only early access channel we document. **Why not just count monthly active users?** Per-MAU pricing ties your bill to growth, and agents add identities that are not people. Self-hosting removes that meter, but you take on operations. The right choice depends on your team and traffic. **Can I move between self-hosted and Cloud?** Cloud is not generally available, so we make no migration promises. The library runs on Postgres, SQLite, MySQL or D1, and your data stays in a database you control. - [Security](https://theauth.dev/security/) - [Agent identity](https://theauth.dev/agent-identity/) - [Self-host or Cloud](https://theauth.dev/#trust) --- URL: https://theauth.dev/get-started/ Get started # Pick a track: people signing in, or agents calling. Most apps need both. A person logs in and gets a session. An AI agent, an MCP client or a script presents a scoped token instead. theAuth handles each with its own mechanism, in one library, in TypeScript or Go. [Human auth](https://theauth.dev/get-started/#human) [AI agent auth](https://theauth.dev/get-started/#agent) How the two differ ## A session proves who someone is. A token proves what a caller may do. [Agent identity in depth](https://theauth.dev/agent-identity/) [Human auth in depth](https://theauth.dev/human-auth/) People and agents enter through the same library and leave with different credentials. A person gets a server-side session. An agent gets a scoped token with an owner, an expiry and an audit trail. Track 1 ## Human auth in about ten lines. Install, configure one sign-in method, read the signed-in user. Magic links need no password database to start, and passkeys, TOTP, OAuth and SAML add on top. 1 Scaffold a full app, or add the package to your own. `pnpm create @glinr/theauth-app` Or add it to an existing project. The SQLite driver is a peer dependency, so install it too: `pnpm add @glinr/theauth sql.js` npm users: npm create @glinr/theauth-app and npm install @glinr/theauth sql.js. 2 Create the instance and send a sign-in link. auth.ts ```ts import { createTheAuth } from "@glinr/theauth"; const theauth = await createTheAuth({ database: { provider: "sqlite", url: "app.db" }, baseUrl: "http://localhost:3000", auth: { session: { secret: process.env.SESSION_SECRET! } }, // 32+ characters magicLink: { appUrl: "http://localhost:3000", sendMagicLink: async (email, _token, url) => { console.log(`sign-in link for ${email}: ${url}`); }, }, }); await theauth.magicLink?.sendLink("ada@example.com"); ``` [TypeScript quickstart](https://docs.theauth.dev/quickstart) [All sign-in methods](https://docs.theauth.dev/auth) [Guide: human login in Hono](https://theauth.dev/guides/hono-human-and-agent-auth/) 1 Add the module. Keep the /v2 suffix. `go get github.com/glincker/theauth-go/v2` Optional embedded SQLite backend (needs Go 1.26): `go get github.com/glincker/theauth-go/storage/sqlite` 2 Mount it in your router. Imports: theauth, storage/memory, chi. main.go (fragment) ```go a, err := theauth.New(theauth.Config{ Storage: memory.New(), BaseURL: "http://localhost:8080", }) if err != nil { log.Fatal(err) } defer a.Close() r := chi.NewRouter() a.Mount(r) // /auth/*: magic link, passkeys, TOTP, OAuth, sessions r.With(a.RequireAuth()).Get("/me", func(w http.ResponseWriter, r *http.Request) { user, _ := theauth.UserFromContext(r.Context()) w.Write([]byte("hello " + user.Email)) }) log.Fatal(http.ListenAndServe(":8080", r)) ``` [theauth-go overview](https://theauth.dev/go/) [Go quick start](https://docs.theauth.dev/go/getting-started/quick-start) [Runnable SQLite example](https://github.com/glincker/theauth-go/tree/main/examples/single-binary-sqlite) Track 2 ## AI agent auth: identities, scoped tokens, MCP. Give each agent its own owner, permissions and audit trail, or put an OAuth 2.1 authorization server in front of your MCP server so clients you have never met can register and sign in. 1 Install the core. Add the Hono adapter if you want the MCP OAuth endpoints. `pnpm add @glinr/theauth sql.js` `pnpm add @glinr/theauth-hono hono @hono/node-server` 2 Create an agent and authorize a call by its token. agent.ts ```ts import { createTheAuth } from "@glinr/theauth"; const theauth = await createTheAuth({ database: { provider: "sqlite", url: "app.db" }, agents: { enabled: true }, }); const agent = await theauth.agent.create({ ownerId: "user-123", // a row that exists in theauth_users name: "report-bot", type: "autonomous", permissions: [{ resource: "reports:*", actions: ["read"] }], }); // agent.token is "kv_...", shown once. Store it now. const result = await theauth.authorizeByToken(agent.token, { action: "read", resource: "reports:q3", }); // result.allowed === true, result.auditId links to the audit row ``` [Guide: secure an MCP server](https://theauth.dev/guides/mcp-server-typescript/) [Agents docs](https://docs.theauth.dev/agents) [MCP OAuth docs](https://docs.theauth.dev/mcp) 1 The authorization server is in the main module. MCP servers validate tokens with the small resource module. `go get github.com/glincker/theauth-go/v2` `go get github.com/glincker/theauth-go/mcpresource` 2 Protect your MCP server's routes with one middleware. main.go (fragment) ```go v := mcpresource.New( "https://mcp.example.com", // your MCP server's resource URI mcpresource.WithJWKS("https://auth.example.com/oauth/jwks"), ) r := chi.NewRouter() r.Use(v.Middleware) // 401 with resource metadata pointers when the token is bad r.Get("/tools", func(w http.ResponseWriter, r *http.Request) { p, _ := v.Principal(r.Context()) json.NewEncoder(w).Encode(map[string]any{"subject": p.Subject, "scope": p.Scope}) }) ``` [Guide: the authorization server too](https://theauth.dev/guides/mcp-authorization-server-go/) [MCP authorization docs](https://docs.theauth.dev/go/concepts/mcp-authorization) [theauth-go overview](https://theauth.dev/go/) Before you run two servers ## Pick where short-lived state lives Rate limit counters, device codes and nonces default to process memory. Switch one line when you add instances. ```text // default, no config createTheAuth({ /* ... */ }) ``` - **Atomic counters:** yes. - **Shared across instances:** no. - **Lost on restart.** Fine for development and one process. ```text secondaryStorage: "database" ``` - **Atomic counters:** yes, a single guarded UPDATE. - **Shared across instances:** yes. - **Runs on SQLite, Postgres, MySQL and D1,** with no new infrastructure. ```text secondaryStorage: cloudflareKvStorage(env.AUTH_KV) ``` - **Atomic counters:** no. Rate limits are soft. - **Shared:** eventually, a write can take up to a minute to show elsewhere. - **Good for** plain values such as device codes, if you accept the delay. ```text secondaryStorage: redisStorage(new Redis(url)) ``` - **Atomic counters:** yes. - **Shared across instances:** yes. - **Works with** Redis, Valkey, Upstash and Dragonfly. ```text defineSecondaryStorage({ get, set, delete, incr }) ``` - **Bring your own** get, set and delete. - **Atomic counters:** only if you supply incr. - **Without it,** the helper builds one from get and set, and it is not atomic. Secondary storage holds rate limit counters, device codes and other short-lived state. See the [secondary storage docs](https://docs.theauth.dev/secondary-storage) for the interface and tradeoffs. ## Where to go next [Guides](https://theauth.dev/guides/) [Full quickstart](https://docs.theauth.dev/quickstart) [Compare with other auth tools](https://theauth.dev/compare/) [Multi-agent systems](https://theauth.dev/use-cases/multi-agent/) [Changelog](https://theauth.dev/changelog/) Commands checked against npm and the Go module proxy on 2026-10-08: @glinr/theauth 0.6.0, @glinr/theauth-hono 4.0.0, @glinr/create-theauth-app 0.3.0, theauth-go v2.7.1. --- URL: https://theauth.dev/go/ Go library # theauth-go: auth and an MCP authorization server for Go Mount it into your own net/http or chi server. Humans sign in with passkeys, magic links or OAuth. Agents and MCP clients get scoped OAuth 2.1 tokens from the same process. MIT licensed, no hosted service. `go get github.com/glincker/theauth-go/v2` Go 1.25 or newer. Keep the /v2: the bare path is frozen at v1.0.0. [Go quick start](https://docs.theauth.dev/go/getting-started/quick-start) [Build an MCP authorization server](https://theauth.dev/guides/mcp-authorization-server-go/) What it offers ## One library for the human side and the agent side. Agent-grade OAuth ## DPoP, CIBA, PAR and JAR each sit behind their own config field. The authorization server implements the specs that matter when the client is an autonomous agent rather than a browser tab. Each one is opt-in through its own config field. Standards implemented by the theauth-go authorization server | Standard | What it gives an agent deployment | | --- | --- | | RFC 9449 DPoP | Access tokens bound to a client key, so a leaked token is useless without the private key. | | RFC 9509 CIBA | Backchannel authentication: an agent asks, a human approves out of band. Needs memory or Postgres storage. | | RFC 9126 PAR | Pushed authorization requests, so request parameters never travel through the browser. | | RFC 9101 JAR | Signed authorization request objects. | | RFC 8693 token exchange | Delegation and impersonation with a capped actor chain (`MaxActorChainDepth`). | | RFC 9728 and RFC 8414 | Protected resource and authorization server metadata, so MCP clients discover everything from the resource URL. | | CIMD (MCP 2025-11-25) | Client ID Metadata Documents. Off by default and fail-closed: you choose which hosts may be fetched. | | RFC 7591 dynamic registration | Closed unless you issue registration tokens or explicitly allow anonymous registration. | Source: the [theauth-go llms.txt](https://github.com/glincker/theauth-go/blob/main/llms.txt) and [README](https://github.com/glincker/theauth-go/blob/main/README.md). TypeScript parity differs: the TypeScript library covers PKCE S256, RFC 9728, 8707, 8414 and 7591. See the [MCP OAuth page](https://theauth.dev/mcp-oauth/). Minimal quickstart ## An authorization server and a protected MCP route in one file. This is the program from the [MCP authorization server guide](https://theauth.dev/guides/mcp-authorization-server-go/). It was built and run end to end against v2.7.1 on 2026-10-08. Sign-in emails print to the terminal. main.go ```go package main import ( "context" "crypto/rand" "encoding/json" "fmt" "log" "net/http" "github.com/glincker/theauth-go/mcpresource" "github.com/glincker/theauth-go/v2" "github.com/glincker/theauth-go/v2/storage/memory" "github.com/go-chi/chi/v5" ) const ( baseURL = "http://localhost:8080" resource = baseURL + "/mcp" ) // logSender prints each email instead of sending it, so you can copy the // magic link out of the terminal. type logSender struct{} func (logSender) Send(_ context.Context, to, subject, body string) error { fmt.Printf("\n--- email to %s: %s ---\n%s\n\n", to, subject, body) return nil } func main() { key := make([]byte, 32) if _, err := rand.Read(key); err != nil { log.Fatal(err) } a, err := theauth.New(theauth.Config{ Storage: memory.New(), // swap for storage/sqlite or Postgres to keep data BaseURL: baseURL, EmailSender: logSender{}, EncryptionKey: key, AuthorizationServer: &theauth.AuthorizationServerConfig{ Issuer: baseURL, Resources: []theauth.ProtectedResource{ {Identifier: resource, Scopes: []string{"tools.read"}}, }, // Dynamic client registration is closed unless you open it. This token is // the "initial access token" an MCP client presents to register itself. RegistrationTokens: []string{"dev-registration-token"}, }, }) if err != nil { log.Fatal(err) } defer a.Close() r := chi.NewRouter() a.Mount(r) // /auth/*, /oauth/*, /.well-known/* // The MCP resource server: validates JWTs issued by the server above. v := mcpresource.New(resource, mcpresource.WithJWKS(baseURL+"/oauth/jwks")) r.Route("/mcp", func(r chi.Router) { r.Use(v.Middleware) r.Get("/", func(w http.ResponseWriter, req *http.Request) { p, _ := v.Principal(req.Context()) _ = json.NewEncoder(w).Encode(map[string]any{"subject": p.Subject, "scope": p.Scope}) }) }) log.Println("listening on", baseURL) log.Fatal(http.ListenAndServe(":8080", r)) } ``` Run go mod init example.com/mcp-as && go mod tidy && go run ., then open /.well-known/oauth-authorization-server. For a human-only server with SQLite, start from [examples/single-binary-sqlite](https://github.com/glincker/theauth-go/tree/main/examples/single-binary-sqlite). Storage ## Pick the database by the features you need. New fails at startup if you enable a feature your storage backend cannot hold, so you find out before deploy. Feature support by storage backend | Capability | memory | sqlite | postgres | mysql | | --- | --- | --- | --- | --- | | Users, sessions, magic links, passwords | Yes | Yes | Yes | Yes | | OAuth accounts, passkeys, TOTP, audit log | Yes | Yes | Yes | Yes | | Scoped API tokens, device grant | Yes | Yes | Yes | Yes | | Organizations, SAML, SCIM, RBAC | Yes | No | Yes | Yes | | OAuth 2.1 server, agent identity | Yes | No | Yes | Yes | | CIBA backchannel auth | Yes | No | Yes | No | From the theauth-go README. Postgres and MySQL support for the newer token, device and session capabilities is recent and passes the new storagetest suites; the README says to treat it as newly added. In the authorization server ## Attacks it already blocks Behavior of the merged Go authorization server, shown as before and after. Nothing here is a certification or a pen test result. SSRF ### Internal fetch stopped Client JWKS and metadata URLs come from outside parties. The Go server fetches them with an SSRF-guarded client that refuses loopback, private and link-local (cloud metadata) addresses, follows no redirects and caps the body at 512 KB. Refresh reuse ### Old token revokes the family Refresh tokens rotate on every use. Presenting one that was already rotated is treated as theft, and the whole rotation family is revoked (RFC 9700, section 4.14). Code replay ### Second use undoes the first Authorization codes are stored hashed and live 60 seconds by default. Redeeming one a second time revokes the tokens already issued from it and writes an oauth.code_replay_revoked audit event. Supply chain and speed ## Signed releases, and hot paths with numbers you can rerun. Release artifacts ship with an SBOM and Sigstore signatures, and the releases carry SLSA level 3 provenance. The verification steps are in the [releases and verification](https://docs.theauth.dev/go/security/releases) doc. We do not claim a third-party audit or certification. Twelve Go benchmarks gate every release against regressions. Argon2id runs at the production work factor, so password hashing is slow on purpose. Everything else on the hot path is measured in nanoseconds to microseconds, in memory storage. Full table, machine and commit are on the [benchmarks page](https://theauth.dev/benchmarks/). Apple M4 Max, Go go1.26.5, snapshot 2026-10-07. Per operation, median of five runs. ## theauth-go: common questions **Which import path do I use?** Use `github.com/glincker/theauth-go/v2`. The path without `/v2` is frozen at v1.0.0, so a plain `go get github.com/glincker/theauth-go` installs the old release. The `mcpresource` and `storage/sqlite` modules are separate modules without the `/v2` suffix. **Is it a hosted service?** No. It is a library you mount into your own `net/http` or `chi` server, under the MIT license. Data stays in your database: memory, SQLite, Postgres or MySQL. **Which Go versions does it need?** The root module declares Go 1.25. The separate `storage/sqlite` module needs Go 1.26. **Does it work without Postgres?** Yes. SQLite gives you one static binary with one database file. SQLite has no organizations, SAML, SCIM, RBAC or OAuth authorization server, so MCP authorization needs memory, Postgres or MySQL. **How stable is the API?** Packages that were stable before v2.6 keep their SemVer guarantees. The agent identity APIs, `policy`, `clientauth` and `storage/sqlite` are marked experimental and may change in a minor release. The stability page lists the exact split. [DPoP and device flow](https://theauth.dev/agent-oauth/) [Go documentation](https://docs.theauth.dev/go) [pkg.go.dev reference](https://pkg.go.dev/github.com/glincker/theauth-go/v2) [Get started in TypeScript or Go](https://theauth.dev/get-started/) [MCP OAuth 2.1](https://theauth.dev/mcp-oauth/) [Changelog](https://theauth.dev/changelog/) --- URL: https://theauth.dev/guides/ Guides # Tutorials you can run top to bottom. Each guide is a complete program. The code was built and run against the published packages on the date shown, and the expected output is on the page. If a step does not match what you see, tell us in a GitHub discussion. ## Start here 1. [Secure an MCP server with theAuth in 10 minutesTypeScript. Discovery, dynamic registration, PKCE and a protected route, with a client script that walks the flow.](https://theauth.dev/guides/mcp-server-typescript/) 2. [Add human login plus agent auth to a Hono appTypeScript. Magic-link sessions for people, scoped tokens for agents, and the line between them.](https://theauth.dev/guides/hono-human-and-agent-auth/) 3. [Build an MCP authorization server in GoGo. An OAuth 2.1 server and a token-checked MCP route in one program, then a curl walkthrough.](https://theauth.dev/guides/mcp-authorization-server-go/) [Install for TypeScript or Go](https://theauth.dev/get-started/) [Reference documentation](https://docs.theauth.dev) [Use cases](https://theauth.dev/use-cases/) [DPoP, device flow and passkeys](https://theauth.dev/agent-oauth/) [theauth-go](https://theauth.dev/go/) --- URL: https://theauth.dev/guides/mcp-server-typescript/ Guide # Secure an MCP server with theAuth in 10 minutes An MCP client discovers your server, registers itself, sends a person through an authorization step with PKCE and comes back with a token your route can check. You will build that flow in one file and then run a client against it. Run end to end on 2026-10-08 with @glinr/theauth 0.6.0, @glinr/theauth-hono 4.0.0, Hono 4 and Node 22. ## What you will build - An OAuth 2.1 authorization server with discovery documents, dynamic client registration, PKCE S256 and a token endpoint. - A protected /mcp/tools route that answers 401 without a token and runs for a token with the mcp:read scope. - A short client script that performs the whole flow so you can watch each step succeed. ## Before you start - Node 22 or newer and pnpm. npm works too: swap pnpm add for npm install. - A terminal. No database to install: this guide uses the built-in SQLite driver (sql.js) and in-memory stores for the OAuth state. ## Create the project Make a folder and install the packages. sql.js is the SQLite driver theAuth uses by default, and it is a peer dependency, so pnpm will not install it for you. terminal ```js mkdir mcp-demo && cd mcp-demo pnpm init && pnpm pkg set type=module pnpm add @glinr/theauth @glinr/theauth-hono hono @hono/node-server sql.js pnpm add -D tsx typescript @types/node ``` Create a signing secret for access tokens. It must be at least 32 characters, and the server refuses to start with a shorter one. terminal ```js export MCP_SIGNING_SECRET=$(openssl rand -hex 32) ``` ## Write the server Save this as src/server.ts. Read the comments: three pieces matter. createMcpModule is the authorization server, and you give it storage as plain functions. theAuthHono mounts its endpoints. requireScopes guards your own route. src/server.ts ```ts import { serve } from "@hono/node-server"; import { createTheAuth } from "@glinr/theauth"; import { createMcpModule } from "@glinr/theauth/mcp"; import type { McpAccessToken, McpAuthorizationCode, McpClient, McpSession, } from "@glinr/theauth/mcp"; import { theAuthHono } from "@glinr/theauth-hono"; import { Hono } from "hono"; const ORIGIN = "http://localhost:3000"; // In-memory stores. Swap these for your database before you deploy. const clients = new Map(); const codes = new Map(); const tokens = new Map(); const byRefresh = new Map(); const theauth = await createTheAuth({ database: { provider: "sqlite", url: "theauth.db" }, baseUrl: ORIGIN, }); const mcp = createMcpModule({ config: { enabled: true, issuer: ORIGIN, baseUrl: `${ORIGIN}/api/theauth`, signingSecret: process.env.MCP_SIGNING_SECRET ?? "", scopes: ["mcp:read", "mcp:execute"], }, storeClient: async (client) => { clients.set(client.clientId, client); }, findClient: async (clientId) => clients.get(clientId) ?? null, storeAuthorizationCode: async (code) => { codes.set(code.code, code); }, consumeAuthorizationCode: async (code) => { const found = codes.get(code) ?? null; if (found) codes.delete(code); return found; }, storeToken: async (token) => { tokens.set(token.accessToken, token); if (token.refreshToken) byRefresh.set(token.refreshToken, token.accessToken); }, findTokenByRefreshToken: async (refreshToken) => { const access = byRefresh.get(refreshToken); return access ? (tokens.get(access) ?? null) : null; }, revokeToken: async (accessToken) => { tokens.delete(accessToken); }, // Demo only: every request is "signed in" as this user. resolveUserId: async () => "demo-user", }); const app = new Hono<{ Variables: { mcpSession: McpSession } }>(); // The adapter also mounts an agent REST API with no authentication of its own. // Let only the OAuth endpoints through and answer 404 for the rest. app.use("/api/theauth/*", async (c, next) => { const path = c.req.path; const oauthOnly = path.startsWith("/api/theauth/mcp/") || path.startsWith("/api/theauth/.well-known/"); return oauthOnly ? next() : c.json({ error: "not found" }, 404); }); app.route("/api/theauth", theAuthHono(theauth, { mcp })); // MCP clients look for discovery documents at the origin root. app.get("/.well-known/oauth-authorization-server", (c) => c.json(mcp.getMetadata())); app.get("/.well-known/oauth-protected-resource", (c) => c.json(mcp.getProtectedResourceMetadata())); app.use("/mcp/*", async (c, next) => { const check = await mcp.requireScopes(c.req.raw, ["mcp:read"]); if (!check.authorized) return check.response; c.set("mcpSession", check.session); await next(); }); app.get("/mcp/tools", (c) => { const session = c.get("mcpSession"); return c.json({ user: session.userId, client: session.clientId, tools: ["echo"] }); }); serve({ fetch: app.fetch, port: 3000 }); console.log(`listening on ${ORIGIN}`); ``` Two lines deserve a second look. The use("/api/theauth/*") block is there because the Hono adapter also mounts an agent REST API (create, list and audit agents) with no authentication of its own. This server only needs the OAuth endpoints, so everything else answers 404. And resolveUserId returns a fixed user: it is where your real session lookup goes, and the next guide wires it to a login. ## Start it and read the discovery document terminal ```ts pnpm tsx src/server.ts # in a second terminal: curl -s http://localhost:3000/.well-known/oauth-authorization-server ``` The metadata lists the authorization, token and registration endpoints and code_challenge_methods_supported: ["S256"]. The adapter serves the same documents under /api/theauth/.well-known/. MCP clients look at the root of your origin, which is why the server file adds the two root routes. ## Run a client against it Save this as src/flow.ts. It does what an MCP client does: try the route, register, authorize with a PKCE challenge, exchange the code with the verifier, then call the route with the token. src/flow.ts ```ts import { createHash, randomBytes } from "node:crypto"; const ORIGIN = "http://localhost:3000"; const API = `${ORIGIN}/api/theauth`; const redirectUri = "http://localhost:8976/callback"; // 1. Without a token the MCP route answers 401 with a WWW-Authenticate header. const denied = await fetch(`${ORIGIN}/mcp/tools`); console.log("no token:", denied.status, denied.headers.get("www-authenticate")); // 2. Register a public client (RFC 7591). const reg = await fetch(`${API}/mcp/register`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ client_name: "flow-script", redirect_uris: [redirectUri], grant_types: ["authorization_code"], token_endpoint_auth_method: "none", }), }); const client = (await reg.json()) as { client_id: string }; // 3. Authorize with PKCE S256. The server answers with a redirect carrying the code. const verifier = randomBytes(32).toString("base64url"); const challenge = createHash("sha256").update(verifier).digest("base64url"); const authUrl = new URL(`${API}/mcp/authorize`); authUrl.search = new URLSearchParams({ response_type: "code", client_id: client.client_id, redirect_uri: redirectUri, scope: "mcp:read", code_challenge: challenge, code_challenge_method: "S256", resource: ORIGIN, }).toString(); const authRes = await fetch(authUrl, { redirect: "manual" }); const code = new URL(authRes.headers.get("location") ?? "").searchParams.get("code"); if (!code) throw new Error(`no code, status ${authRes.status}`); // 4. Exchange the code with the verifier. const tokenRes = await fetch(`${API}/mcp/token`, { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ grant_type: "authorization_code", code, redirect_uri: redirectUri, client_id: client.client_id, code_verifier: verifier, resource: ORIGIN, }), }); const token = (await tokenRes.json()) as { access_token: string }; // 5. Call the protected route. const ok = await fetch(`${ORIGIN}/mcp/tools`, { headers: { authorization: `Bearer ${token.access_token}` }, }); console.log("with token:", ok.status, await ok.json()); ``` terminal ```json pnpm tsx src/flow.ts ``` Expected output (the client id differs): output ```ts no token: 401 Bearer resource_metadata="http://localhost:3000/api/theauth/.well-known/oauth-protected-resource" with token: 200 { user: 'demo-user', client: 'fb67f6fa-970a-4046-a5c5-98bf91c37262', tools: [ 'echo' ] } ``` The 401 carries a WWW-Authenticate header that points at the protected resource metadata. That pointer is how a client that has never seen your server finds out where to sign in. ## Point a real MCP client at it Give the client your MCP endpoint URL. A spec-compliant client reads the 401 header, fetches the metadata, registers through /api/theauth/mcp/register, and sends the person to /api/theauth/mcp/authorize. Because resolveUserId is a stub, the person is signed in as demo-user without a prompt. Replace that function before anyone else can reach the server. ## Before you ship this - **Replace resolveUserId.** Return the signed-in user from your session, or null to send the person to loginPage. The [Hono guide](https://theauth.dev/guides/hono-human-and-agent-auth/) shows a real login. - **Move the OAuth state to a database.** The Maps lose clients, codes and tokens on restart. Keep the single-use rule on consumeAuthorizationCode. - **Serve over HTTPS** and set ORIGIN to the public URL. The issuer appears in every token. - **Keep the signing secret out of the repository** and rotate it deliberately: tokens signed with the old one stop validating. - **Check the audience.** validateToken confirms an audience claim exists but does not compare it with your resource URL. See [the MCP docs](https://docs.theauth.dev/mcp) for expectedAudience. ## Questions **Do I need a database?** Not for this guide. The OAuth state is in memory and theAuth keeps its own tables in SQLite through sql.js. For production, back the store functions with your database. **Why does the adapter need a guard?** The Hono adapter mounts the agent REST API as well as the OAuth endpoints, and those routes do not authenticate callers. The guard in the server file lets only the MCP OAuth paths through. **Does this work with Go?** Yes. The Go library has its own authorization server and a resource-server module. See the Go guide below. ## Keep going [Add human login plus agent auth to Hono](https://theauth.dev/guides/hono-human-and-agent-auth/) [The same in Go](https://theauth.dev/guides/mcp-authorization-server-go/) [MCP OAuth docs](https://docs.theauth.dev/mcp) [Use case: MCP servers](https://theauth.dev/use-cases/mcp-servers/) --- URL: https://theauth.dev/guides/hono-human-and-agent-auth/ Guide # Add human login plus agent auth to a Hono app People and agents authenticate differently, and a good app keeps them apart. A person signs in with a link and holds a session cookie. An agent presents a token that names its owner and the few things it may do. You will build both in one file. Run end to end on 2026-10-08 with @glinr/theauth 0.6.0, Hono 4 and Node 22. ## What you will build - Magic-link sign-in that sets an HTTP-only session cookie, and a /me route that reads it. - A POST /agents route where a signed-in person mints an agent limited to reports:* with the read action. - Agent routes that allow a read and deny a delete, with each decision written to the audit log. ## Before you start - Node 22 or newer and pnpm, in an empty folder with type: module (see step 1 of the [MCP guide](https://theauth.dev/guides/mcp-server-typescript/)). - Email delivery is stubbed: the sign-in link prints to your terminal. ## Install and set a session secret terminal ```sh pnpm add @glinr/theauth hono @hono/node-server sql.js pnpm add -D tsx typescript @types/node export SESSION_SECRET=$(openssl rand -hex 32) ``` The session secret signs the session tokens and must be at least 32 characters. ## Write the app Save this as src/app.ts. src/app.ts ```ts import { serve } from "@hono/node-server"; import { createTheAuth } from "@glinr/theauth"; import { Hono, type Context } from "hono"; import { getCookie, setCookie } from "hono/cookie"; const ORIGIN = "http://localhost:3000"; const theauth = await createTheAuth({ database: { provider: "sqlite", url: "app.db" }, baseUrl: ORIGIN, auth: { session: { secret: process.env.SESSION_SECRET ?? "" } }, agents: { enabled: true }, magicLink: { appUrl: ORIGIN, callbackPath: "/login/verify", // Swap this for your email provider. Logging the link is enough to follow along. sendMagicLink: async (email, _token, url) => { console.log(`magic link for ${email}: ${url}`); }, }, }); const sessions = theauth.auth.session; const magic = theauth.magicLink; if (!sessions || !magic) throw new Error("session and magicLink must be configured"); const bearerOf = (header: string | undefined) => header?.replace(/^Bearer /, ""); const app = new Hono(); // Human sign-in: send the link, then verify it and set the session cookie. app.post("/login", async (c) => { const { email } = await c.req.json<{ email: string }>(); await magic.sendLink(email.trim().toLowerCase()); return c.json({ sent: true }); }); app.get("/login/verify", async (c) => { const result = await magic.verify(c.req.query("token") ?? ""); if (!result) return c.json({ error: "invalid or expired link" }, 401); setCookie(c, "theauth_session", result.session.token, { httpOnly: true, sameSite: "Lax", secure: false, // set to true behind HTTPS path: "/", expires: result.session.expiresAt, }); return c.json({ userId: result.user.id, email: result.user.email }); }); // Resolve the signed-in human from the cookie (or a bearer header for scripts). const currentUserId = async (c: Context): Promise => { const token = bearerOf(c.req.header("authorization")) ?? getCookie(c, "theauth_session"); const session = token ? await sessions.validate(token) : null; return session?.userId ?? null; }; app.get("/me", async (c) => { const userId = await currentUserId(c); return userId ? c.json({ userId }) : c.json({ error: "sign in first" }, 401); }); // A signed-in human mints a scoped agent. The raw token is shown once. app.post("/agents", async (c) => { const userId = await currentUserId(c); if (!userId) return c.json({ error: "sign in first" }, 401); const agent = await theauth.agent.create({ ownerId: userId, name: "report-bot", type: "autonomous", permissions: [{ resource: "reports:*", actions: ["read"] }], }); return c.json({ id: agent.id, token: agent.token }); }); // Agent routes: authorize by the agent's own bearer token, not a session. app.get("/reports/:id", async (c) => { const token = bearerOf(c.req.header("authorization")); if (!token) return c.json({ error: "missing token" }, 401); const result = await theauth.authorizeByToken(token, { action: "read", resource: `reports:${c.req.param("id")}`, }); if (!result.allowed) return c.json({ error: "denied", reason: result.reason }, 403); return c.json({ report: c.req.param("id"), auditId: result.auditId }); }); app.delete("/reports/:id", async (c) => { const token = bearerOf(c.req.header("authorization")); if (!token) return c.json({ error: "missing token" }, 401); const result = await theauth.authorizeByToken(token, { action: "delete", resource: `reports:${c.req.param("id")}`, }); return c.json({ allowed: result.allowed, reason: result.reason }, result.allowed ? 200 : 403); }); serve({ fetch: app.fetch, port: 3000 }); console.log(`listening on ${ORIGIN}`); ``` How the pieces fit: - auth.session turns on signed, server-side-revocable session tokens. magicLink and agents each create the tables they need, so turn on only what you use. - We call theauth.magicLink.sendLink and verify from our own routes. That keeps the paths ours and works under any mount prefix. - verify returns a session token. The route puts it in an HTTP-only cookie, which is what currentUserId reads back. - authorizeByToken takes the agent's own token, never a session. An agent that presents a human cookie gets nothing, and a human cannot act through an agent token. ## Sign in as a person terminal ```ts pnpm tsx src/app.ts # second terminal: curl -s -X POST localhost:3000/login -H 'content-type: application/json' -d '{"email":"ada@example.com"}' ``` The server terminal prints magic link for ada@example.com: http://localhost:3000/login/verify?token=.... Open it with a cookie jar so the session sticks: terminal ```ts curl -s -c jar "http://localhost:3000/login/verify?token=PASTE_TOKEN" curl -s -b jar localhost:3000/me ``` The second call returns {"userId":"..."}. Without the cookie it returns 401 sign in first. ## Mint an agent as that person terminal ```ts curl -s -b jar -X POST localhost:3000/agents ``` The response is {"id":"...","token":"kv_..."}. The token is shown once, and only a hash is stored. The agent's owner is the signed-in user, so every action it takes traces back to a person. ## Call the agent routes terminal ```ts TOKEN=kv_PASTE_HERE curl -s localhost:3000/reports/q3 -H "authorization: Bearer $TOKEN" curl -s -X DELETE localhost:3000/reports/q3 -H "authorization: Bearer $TOKEN" ``` The first call returns {"report":"q3","auditId":"..."}. The second returns 403 with No permission grants agent "report-bot" access to "delete" on "reports:q3". Both decisions are in the audit log, linked by auditId. ## Before you ship this - **Set secure: true on the cookie** once you serve HTTPS, and keep sameSite at Lax or Strict. - **Protect POST /agents from cross-site requests.** It is cookie-authenticated, so check the Origin header or add a CSRF token before real users touch it. - **Limit who can mint agents.** The guide lets any signed-in person do it. Cap it with agents.maxPerUser and decide who is allowed. - **Do not mount the whole adapter by accident.** theAuthHono exposes agent management and audit routes without authentication. Mount it only behind your own guard, as in the [MCP guide](https://theauth.dev/guides/mcp-server-typescript/). - **Send real email.** Replace the console.log in sendMagicLink with your provider. ## Questions **Why a cookie for people and a bearer token for agents?** A cookie suits a browser and is easy to revoke server-side. An agent is not a browser, so it carries a token that names its owner and its permissions, and you can revoke one agent without ending anyone's session. **Can I use passkeys or OAuth providers instead of magic links?** Yes. theAuth supports passkeys, OAuth providers, TOTP and more for people. The agent half of this guide does not change. **Where do I read the audit log?** Through the audit module, for example filtering by agent id, or the JSON and CSV export. See the audit docs. ## Keep going [Secure an MCP server](https://theauth.dev/guides/mcp-server-typescript/) [Delegate to sub-agents](https://theauth.dev/use-cases/multi-agent/) [Audit docs](https://docs.theauth.dev/audit) [Get started](https://theauth.dev/get-started/) --- URL: https://theauth.dev/guides/mcp-authorization-server-go/ Guide # Build an MCP authorization server in Go One Go program that issues OAuth 2.1 tokens, signs a person in, and protects an MCP route by validating those tokens. You will then walk the flow with curl so every step is visible. Run end to end on 2026-10-08 with theauth-go v2.7.1, mcpresource v0.1.0, chi v5 and Go 1.26. ## What you will build - An authorization server mounted at /oauth/* and /.well-known/*, with a gated dynamic client registration endpoint. - A protected /mcp route that validates the JWTs the server issues, using the mcpresource module. - A curl walkthrough: discovery, register, sign in, authorize with PKCE, exchange the code, call the route. ## Before you start - Go 1.25 or newer, curl and openssl. - Memory storage keeps this to one file. The OAuth server needs memory, Postgres or MySQL: SQLite does not support it. ## Create the module terminal ```text mkdir mcp-as && cd mcp-as go mod init example.com/mcp-as ``` Use the /v2 import path. The path without it is frozen at v1.0.0. ## Write main.go main.go ```go package main import ( "context" "crypto/rand" "encoding/json" "fmt" "log" "net/http" "github.com/glincker/theauth-go/mcpresource" "github.com/glincker/theauth-go/v2" "github.com/glincker/theauth-go/v2/storage/memory" "github.com/go-chi/chi/v5" ) const ( baseURL = "http://localhost:8080" resource = baseURL + "/mcp" ) // logSender prints each email instead of sending it, so you can copy the // magic link out of the terminal. type logSender struct{} func (logSender) Send(_ context.Context, to, subject, body string) error { fmt.Printf("\n--- email to %s: %s ---\n%s\n\n", to, subject, body) return nil } func main() { key := make([]byte, 32) if _, err := rand.Read(key); err != nil { log.Fatal(err) } a, err := theauth.New(theauth.Config{ Storage: memory.New(), // swap for storage/sqlite or Postgres to keep data BaseURL: baseURL, EmailSender: logSender{}, EncryptionKey: key, AuthorizationServer: &theauth.AuthorizationServerConfig{ Issuer: baseURL, Resources: []theauth.ProtectedResource{ {Identifier: resource, Scopes: []string{"tools.read"}}, }, // Dynamic client registration is closed unless you open it. This token is // the "initial access token" an MCP client presents to register itself. RegistrationTokens: []string{"dev-registration-token"}, }, }) if err != nil { log.Fatal(err) } defer a.Close() r := chi.NewRouter() a.Mount(r) // /auth/*, /oauth/*, /.well-known/* // The MCP resource server: validates JWTs issued by the server above. v := mcpresource.New(resource, mcpresource.WithJWKS(baseURL+"/oauth/jwks")) r.Route("/mcp", func(r chi.Router) { r.Use(v.Middleware) r.Get("/", func(w http.ResponseWriter, req *http.Request) { p, _ := v.Principal(req.Context()) _ = json.NewEncoder(w).Encode(map[string]any{"subject": p.Subject, "scope": p.Scope}) }) }) log.Println("listening on", baseURL) log.Fatal(http.ListenAndServe(":8080", r)) } ``` terminal ```go go mod tidy go run . ``` The server logs two warnings about secure cookies and trusted proxies. They are expected on plain HTTP in development and have config switches for when you deploy. What the config does: AuthorizationServer.Resources lists the protected resources and their scopes, and every token request must name one. RegistrationTokens gates dynamic client registration behind a bearer token, since open registration is off by default. mcpresource.New builds a validator that fetches the server's keys from /oauth/jwks on first use. ## Look at the discovery documents terminal ```sh B=http://localhost:8080 R=$B/mcp CB=http://localhost:9999/cb curl -s $B/.well-known/oauth-authorization-server curl -s $B/.well-known/oauth-protected-resource curl -si $R | head -5 ``` The first lists the endpoints and S256 as the only PKCE method. The last call returns 401 with a WWW-Authenticate header whose resource_metadata points at the protected resource document. ## Register a client terminal ```text CID=$(curl -s $B/oauth/register -H 'content-type: application/json' \ -H 'authorization: Bearer dev-registration-token' \ -d '{"client_name":"demo","redirect_uris":["'$CB'"],"grant_types":["authorization_code"],"response_types":["code"],"token_endpoint_auth_method":"none"}' \ | sed -E 's/.*"client_id":"([^"]+)".*/\1/') echo $CID ``` You get a client id such as client-01M4E3V4.... Without the bearer token the endpoint refuses the request. ## Sign in as a person terminal ```sh curl -s -c jar $B/auth/magic-link -H 'content-type: application/json' -d '{"email":"ada@example.com"}' ``` The server terminal prints the email with a link ending in /auth/magic-link/verify?token=.... Open it with the cookie jar: terminal ```sh curl -s -b jar -c jar "PASTE_THE_LINK" curl -s -b jar $B/auth/me ``` The first call returns {"ok":true} and stores the session cookie. The second returns the user. ## Authorize with PKCE Make a one-time verifier and its S256 challenge, then ask for a code. The signed-in cookie stands in for the consent screen, and the answer is a 302 to your redirect URI. terminal ```text VER=$(openssl rand -base64 48 | tr -d '=+/\n' | cut -c1-64) CH=$(printf %s "$VER" | openssl dgst -sha256 -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=') LOC=$(curl -si -b jar -G "$B/oauth/authorize" \ --data-urlencode response_type=code --data-urlencode client_id=$CID \ --data-urlencode redirect_uri=$CB --data-urlencode scope=tools.read \ --data-urlencode "resource=$R" --data-urlencode code_challenge=$CH \ --data-urlencode code_challenge_method=S256 --data-urlencode state=xyz \ | sed -n 's/^[Ll]ocation: //p' | tr -d '\r') CODE=$(echo "$LOC" | sed -E 's/.*code=([^&]+).*/\1/') echo $LOC ``` The location looks like http://localhost:9999/cb?code=...&state=xyz. Nothing listens on port 9999, and nothing needs to. ## Exchange the code and call the route terminal ```sh RESP=$(curl -s $B/oauth/token -d grant_type=authorization_code -d code=$CODE \ -d redirect_uri=$CB -d client_id=$CID -d code_verifier=$VER \ --data-urlencode "resource=$R") TOK=$(echo $RESP | sed -E 's/.*"access_token":"([^"]+)".*/\1/') curl -s $R -H "authorization: Bearer $TOK" ``` The token endpoint verifies the verifier against the stored challenge. The route then answers {"scope":["tools.read"],"subject":"01M4..."}, where the subject is the person who signed in. Try the same call with a changed character in the token and you get 401. ## Before you ship this - **Swap the storage.** memory.New() forgets everything on restart. Use the Postgres or MySQL backend for the OAuth server and keep EncryptionKey in a secret store, not generated per run. - **Use HTTPS issuer and base URLs.** The issuer is the iss claim in every token. - **Treat the registration token as a credential.** Load it from the environment, and look at AllowAnonymousRegistration only if you really want open registration. - **Send real email.** Replace logSender with an implementation of the email.Sender interface. - **Turn on the hardening you need.** DPoP, PAR, JAR and CIBA are separate config fields. The [Go overview](https://theauth.dev/go/) lists what each gives you. - **Set TrustedProxies** when you run behind a reverse proxy, or every client shares one rate-limit bucket. ## Questions **Why a separate mcpresource module?** It has no dependencies and validates tokens inside an MCP server, so your resource server does not pull in the whole authorization library. Here both run in one process for convenience. **Can the MCP server and the authorization server be separate services?** Yes. Point mcpresource.WithJWKS at the authorization server's JWKS URL, or use token introspection instead. **Does it support CIMD?** Yes, through AuthorizationServerConfig.CIMD. It is off by default and fail-closed: you choose which hosts the server may fetch client metadata from. ## Keep going [theauth-go overview](https://theauth.dev/go/) [MCP authorization docs](https://docs.theauth.dev/go/concepts/mcp-authorization) [The same flow in TypeScript](https://theauth.dev/guides/mcp-server-typescript/) [examples/mcp-server](https://github.com/glincker/theauth-go/tree/main/examples/mcp-server) --- URL: https://theauth.dev/changelog/ Changelog # What shipped, library by library. Short summaries of recent releases of the TypeScript library and theauth-go, taken from their changelogs. The repositories hold the full record, including every item trimmed here. Snapshot of 2026-10-08, refreshed with npm run sync:changelog. The TypeScript timeline is curated by hand and can trail the newest npm release, so check GitHub Releases for the latest. ## theauth-go Latest: v2.7.1. [Full Go changelog](https://github.com/glincker/theauth-go/blob/main/CHANGELOG.md) and [releases](https://github.com/glincker/theauth-go/releases). See also the [Go overview](https://theauth.dev/go/). **v2.7.1 (2026-10-07)** #### Upgrade notes - JWKS URLs must use `https`. Plain `http` is refused unless `JWTBearerConfig.AllowPrivateJWKSNetworks` is set. - JWKS hosts that resolve to loopback, private, link-local, CGNAT or cloud metadata addresses are refused. Local development and tests that serve a JWKS from `localhost` need `AllowPrivateJWKSNetworks: true`, or an (more in the full changelog) - Redirects are not followed. A JWKS URL must serve the document directly. - Rotated keys are picked up after the cache TTL (`JWKSCacheTTL`, default 5 minutes) instead of never. 1 more in the full changelog. #### Security - JWKS fetching for `private_key_jwt` client `jwks_uri` and `TrustedJWTIssuer.JWKSURL` is now SSRF-guarded. - The in-process JWKS cache now expires entries (`JWTBearerConfig.JWKSCacheTTL`, default 5 minutes) so rotated keys are picked up, is bounded (`JWKSCacheMaxEntries`, default 256) and never caches failed fetches. - The address guard now lives in a shared `internal/safehttp` package used by both CIMD and JWKS fetching. **v2.7.0 (2026-10-05)** #### Added - `OAuthConfig.RedirectURI`, `RedirectURIAllowedHosts` and `AllowInsecureRedirectURI` to override and validate the OAuth redirect URI, plus `(*TheAuth).OAuthStart` and `OAuthCallback` for apps hosting their own routes. - `WebAuthnConfig.UserHandleResolver`: lets imported passkeys whose authenticator holds a foreign user handle sign in; the credential's stored owner stays authoritative and the resolver must agree with it. #### Changed - Default logs no longer contain email addresses (password signin/signup/reset, magic link, `email.Noop`); lines carry `user_id` or a 12-hex `email_ref` hash instead. #### Fixed - `PasswordPolicy.OnLegacyHashAccepted` is now invoked (in a goroutine, after the new Argon2id hash is persisted) on signin and step-up; it was declared but never called. - `ResetPasswordAdmin` now also clears the email's per-IP login backoff entries (new optional `LoginThrottleEntryDeleter` store capability; implemented by the memory, sqlite, postgres and mysql stores). **v2.6.0 (2026-10-05)** #### Upgrade notes - Module path is now `github.com/glincker/theauth-go/v2`; update imports. The v2.x tags were never resolvable by the Go toolchain because the module path lacked the `/v2` suffix, so (more in the full changelog) - Login throttle is on by default. Password signin is gated by per (client IP, normalized email) backoff and a per-user lockout. - JSON error bodies. Handlers that returned plain-text `http.Error` bodies now return `{"code","message"}` JSON with a stable code (`bad_request`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, (more in the full changelog) - TOTP verify and recovery routes rotate the session cookie. They set a new cookie and revoke the pending token, so clients must keep the cookie from the response. 11 more in the full changelog. #### Added - `Config.PathPrefix`. Serve the auth routes under a custom prefix (default `/auth`, validated) with no `http.StripPrefix`. - **`(*TheAuth).Handler()`.** Returns an `http.Handler` serving every route `Mount` registers, so `net/http` ServeMux users need no chi import. - Storage capability interfaces and `Config.CoreStorage`. `Storage` is now the embedding of small capability interfaces (`UserStorage`, `SessionStorage`, `MagicLinkStorage`, `PasswordStorage`, `OAuthAccountStorage`, (more in the full changelog) - `storage/sqlite` adapter (separate module). Pure Go (`modernc.org/sqlite`) storage for `CoreStorage` plus the OAuthAccount, WebAuthn, TOTP and Audit capabilities. 28 more in the full changelog. #### Changed - Repository layout. The module root now holds only the public face of the library. - Module path is now `github.com/glincker/theauth-go/v2` (see Upgrade notes). - JSON error bodies replace plain-text `http.Error` bodies (see Upgrade notes). - OAuth login CSRF closed with a real browser binding. The `/start` cookie now carries a secret distinct from the `state` parameter; the server stores its hash and verifies it in constant time at `/callback`. 3 more in the full changelog. #### Fixed - Synced-passkey login failure (backup-eligible flag). WebAuthn login failed with a generic "verification failed" for any credential whose authenticator reports the backup-eligible (BE) flag, which is the overwhelming (more in the full changelog) - `PasswordPolicy.AllowLegacyBcrypt` is now honored at signin, step-up and password change, with rehash to Argon2id on success. - Existing accounts are no longer linked by an unverified provider email: a callback whose email matches an existing user fails unless the provider marks it verified, and provider emails are lower-cased and trimmed before (more in the full changelog) - MySQL `CreateUser` defaults zero `CreatedAt` and `UpdatedAt` instead of failing. #### Security - Login throttle. Password signin is now gated before any credential work by per (client IP, normalized email) exponential backoff after a grace period, plus a per-user lockout that auto-expires and can be cleared (more in the full changelog) - MFA hardening. TOTP codes are single use: the last accepted time-step is recorded per user and replays are rejected (RFC 6238 section 5.2). - First-run bootstrap. `Config.Bootstrap` closes public signup and requires a one-time setup token (generated and logged at startup, or supplied) to create the first user. - Email canonicalization. Every email entry point (password, magic link, rate-limit key, SAML, SCIM) trims and lowercases, and folds Unicode compatibility forms when `Config.EmailNFKC` is set. 4 more in the full changelog. **v2.5.0 (2026-07-14)** #### Added - `Config.LifecycleHooks` fully wired (#76). `OnSignup` now also fires from SAML signup and a user's first WebAuthn credential (passkey registration has no true account-creation moment, so the first credential is the (more in the full changelog) - `AuthorizationServerConfig.Clock` (#38). Injectable time source for the introspection cache and agent-chain cache, so tests can assert revocation propagation deterministically instead of sleeping past (more in the full changelog) - Password policy documented in README (#39). Minimum length, Argon2id hashing, and the anti-enumeration dummy-verify behavior. #### Fixed - `a.Mount()` bypassed `LifecycleHooks` for password, TOTP, and WebAuthn. `passwordhandlers`/`totphandlers`/`webauthnhandlers` held the raw internal `Service` directly instead of a hook-aware adapter, unlike OAuth/ (more in the full changelog) - SCIM `PATCH /Groups/{id}` silently discarded member-write errors, always returning 200 even when the storage write failed. - Admin `GET /audit` classified bad-cursor errors by substring-matching `err.Error()` instead of `errors.Is`. - `storage/mysql.MoveTOTPSecret` treated any error from its existence check (not just "no rows") as "primary already has a secret," which could silently delete a secondary user's real TOTP secret on a transient DB (more in the full changelog) 3 more in the full changelog. **v2.5.0-rc.1 (2026-06-22)** #### Added - `Config.LifecycleHooks` surface (#76, partial). New optional hook bundle lets consumers react to authentication-lifecycle events without forking handlers or wrapping endpoints at the HTTP boundary. - `Auth.UserByID` (#77). Public lookup that previously forced consumers to reach into storage directly. - `Config.Tenancy` auto-provisioning (#77). New `TenancyConfig` lets consumers opt into automatic personal-organization creation on signup. #### Fixed - `RequireAuth` now emits RFC 7807 problem+json on 401 (#78). Previously `RequireAuth` and `RequirePendingOrFull` wrote plain-text bodies (`"unauthorized"`) while `RequirePermission` already emitted RFC 7807, forcing (more in the full changelog) **v2.4.0 (2026-06-22)** #### Added - MySQL 8.x storage backend (#62). `storage/mysql` implements `theauth.Storage` and `OAuthServerStorage` with full parity with the existing postgres backend. - Cognito + Auth0 migration CLI (#63). New `cmd/theauth-migrate/` binary with sub-commands `cognito` and `auth0` exports users from AWS Cognito (CSV or JSON input) and Auth0 (Management API or bulk export) into an (more in the full changelog) - PAR (RFC 9126) + JAR (RFC 9101) for FAPI-adjacent profile (#64). Pushed Authorization Requests and JWT-Secured Authorization Requests are now supported by the OAuth 2.1 AS. - JWT-Bearer client auth + grant + token exchange polish (#65, RFC 7523). The AS now accepts JWT client assertions (`client_assertion_type= urn:ietf:params:oauth:client-assertion-type:jwt-bearer`) as a client (more in the full changelog) 4 more in the full changelog. #### Changed - `AuthorizationServerConfig` extended with new optional sub-configs (additive). `PAR *PARConfig`, `JAR *JARConfig`, `JWTBearer *JWTBearerConfig`, `CIBA *CIBAConfig`. - Token exchange response now sets `issued_token_type` explicitly (#65). Previously the field was omitted. #### Fixed - `gofmt` fixup on `jwtbearer.go` and `par_serialise.go` (#68). Two files landed in #64 and #65 with minor formatting inconsistencies. #### Security - Supply chain: goreleaser + cosign + SLSA (#57). Every release artifact (source archive, SBOM) is now signed with Sigstore keyless signing via the GitHub Actions OIDC identity. - Trust documentation (#61). `docs/THREAT-MODEL.md` (STRIDE analysis across all subsystems), `docs/COMPLIANCE-SOC2.md` (AICPA TSC 2017 criteria mapping), and `docs/COMPLIANCE-GDPR.md` (GDPR data handling reference and (more in the full changelog) ## theAuth for TypeScript Core package @glinr/theauth. [Full changelog](https://github.com/glincker/theauth/blob/main/CHANGELOG.md) and [releases](https://github.com/glincker/theauth/releases). See [get started](https://theauth.dev/get-started/). **v0.5.0, July 2026** #### Summary - No breaking change. All `legacy` exported identifiers now have `TheAuth*` canonical equivalents. **@glinr/theauth-nextjs-auth v0.1.0, May 2, 2026** #### Summary - New package. A focused Next.js (14/15/16) adapter for apps whose auth backend lives outside Next.js (Spring, Rails, Hono, Go, etc.). **v0.4.2, April 18, 2026** #### Summary - Fix on a missed barrel in 0.4.0. The ten new OAuth providers were added to `providers/index.ts` but the top-level `auth/index.ts` still pointed at the old nine-provider list, so `import { notion } from "@glinr/theauth/auth"` did not resolve. **v0.4.1, April 18, 2026** #### Summary - `@glinr/theauth/standards` shipped in 0.4.0 but was missing from the `exports` field in `package.json` and from the tsup build entries, which meant `import { AGENTIC_JWT_CLAIMS } from "@glinr/theauth/standards"` failed at resolve time. **v0.4.0, April 18, 2026** #### Summary - Four things shipped together. **v0.3.0, April 17, 2026** #### Summary - Two adapter additions and a schema defaults change. ## Related [How releases work](https://theauth.dev/open/releases/) [Stability policy](https://theauth.dev/open/stability/) [Roadmap](https://theauth.dev/open/roadmap/) [Guides](https://theauth.dev/guides/) --- URL: https://theauth.dev/compare/ Alternatives, with sources # Compare theAuth with Auth0, Clerk, Better Auth and more Looking for an open source or self-hosted alternative for AI agents? Each page below says what the other tool does well, where theAuth differs, and links to the sources we checked. Last verified: 2026-10-07 ## When to pick what Three honest options. Only the last one is theAuth. theAuth runs as a library inside your own app, mounted through a framework adapter, with your own database behind it (Postgres, MySQL, SQLite or Cloudflare D1). You run the whole stack in your infrastructure, and identities stay in your database. ## Overview across six tools Only rows we could verify from each tool's public docs. Open a comparison for the detail and sources. Overview of Auth0, Clerk, Better Auth, Supabase Auth, Firebase Auth, Keycloak and theAuth | Feature | Auth0 | Clerk | Better Auth | Supabase | Firebase | Keycloak | theAuth | | --- | --- | --- | --- | --- | --- | --- | --- | | Delivery model | Hosted platform | Hosted platform | Open source library | Backend platform | Managed service | Identity server | Library you run; Cloud in early access | | Source license | No, Proprietary | No, Proprietary | Yes, MIT | Yes, MIT | Managed service | Yes, Apache 2.0 | Yes, MIT | | Self-hostable | Partial or different, Managed private cloud only | No, No | Yes, Yes | Yes, Yes | No, No | Yes, Yes | Yes, Yes | | OAuth 2.1 server for MCP | Yes, Yes | Yes, Yes | Yes, Yes | Yes, Yes | Partial or different, Not documented | Yes, Yes | Yes, Yes | | Agent identity as its own model | Partial or different, Add-on: Token Vault, CIBA | Partial or different, Not found | Partial or different, Plugin, not yet stable | Partial or different, Agents act as users | Partial or different, Not documented | Partial or different, Not found | Yes, Yes, core | | Enterprise SSO | Yes, Yes | Yes, Yes | Yes, Plugin | Yes, SAML 2.0 | Partial or different, Identity Platform upgrade | Yes, Yes | Yes, SAML 2.0, OIDC, SCIM | Check mark: yes. Dash: partial, different, or not found in the docs we checked. Cross: no. Last verified: 2026-10-07. ## Pick a comparison - [theAuthvsAuth0Auth0 is the hosted platform with Universal Login and enterprise connections. theAuth is the MIT library you run yourself.Read the comparison](https://theauth.dev/compare/auth0/) - [theAuthvsClerkClerk is hosted auth with polished drop-in components. theAuth is an MIT library you run, with agents as identities.Read the comparison](https://theauth.dev/compare/clerk/) - [theAuthvsBetter AuthBoth are MIT libraries. Better Auth has the larger community and plugin set; theAuth builds agent identity into the core.Read the comparison](https://theauth.dev/compare/better-auth/) - [theAuthvsSupabase AuthSupabase Auth is one part of a Postgres platform with Row Level Security. theAuth is auth alone, with agents as identities.Read the comparison](https://theauth.dev/compare/supabase-auth/) - [theAuthvsFirebase AuthFirebase Authentication is Google's managed sign-in for mobile and web. theAuth is a self-hosted MIT library for agents and humans.Read the comparison](https://theauth.dev/compare/firebase-auth/) - [theAuthvsKeycloakKeycloak is an Apache 2.0 identity server for SSO across many apps. theAuth is a library embedded in your app.Read the comparison](https://theauth.dev/compare/keycloak/) - [theAuthvsAuth0 for MCPAuth for MCP and Token Vault against a self-hosted MCP authorization server. Token Vault is the part theAuth does not offer.Read the comparison](https://theauth.dev/compare/auth0-for-mcp/) - [theAuthvsStytchStytch Connected Apps is hosted OAuth for MCP clients. theAuth is the same job as a library you run, with agents as identities.Read the comparison](https://theauth.dev/compare/stytch/) - [theAuthvsWorkOSWorkOS AuthKit hosts the MCP authorization server and you verify tokens. theAuth hands you the server itself.Read the comparison](https://theauth.dev/compare/workos/) - [theAuthvsDescopeDescope sells an Agentic Identity Hub, including managed third-party credentials. theAuth is an MIT library with delegation chains.Read the comparison](https://theauth.dev/compare/descope/) ## Choosing an auth tool: common questions **Which auth tool is the best alternative for AI agents?** It depends on where you want to run it. Several tools now offer an OAuth 2.1 authorization server for MCP, so the difference is how agents are modeled. theAuth gives each agent its own identity with an owner, delegation limits, budgets and an audit trail, in an MIT library you run yourself. **Is theAuth better than Auth0 or Clerk?** Not for every team. Auth0 and Clerk are hosted products with polished login experiences, and that is the right choice if you want a vendor to run auth. theAuth fits when you want to self-host, own your data, and model agents as identities. **Should I use a library or a hosted vendor for auth?** Use a hosted vendor when speed and not operating anything matter most. Use a library when you need your data in your own database, want the code in your repository, or have requirements a vendor does not cover. [Migration guides](https://docs.theauth.dev/migrate) [Agent identity](https://theauth.dev/#agents) [MCP OAuth 2.1](https://theauth.dev/#mcp) [Docs comparisons](https://docs.theauth.dev/compare) --- URL: https://theauth.dev/compare/auth0/ The open source Auth0 alternative for AI agents # theAuth vs Auth0 Auth0 is a hosted identity platform you call as a service. theAuth is an MIT library you run next to your own data, with AI agents modeled as identities of their own. Last verified: 2026-10-07. Hosted platform against an MIT library. [Read the quickstart](https://docs.theauth.dev/quickstart) [Migration steps](https://theauth.dev/compare/auth0/#migration) Moving from Auth0? You can [migrate to theAuth without a rewrite](https://theauth.dev/migrate/) by running both systems and moving users as they sign in. Docs: [Auth0 migration guide](https://docs.theauth.dev/migrate/from-auth0). [Plan the migration](https://theauth.dev/migrate/) ## Short answer ### Choose Auth0 if - You want a vendor to run login, with a hosted Universal Login page you customize from a dashboard. - You need enterprise SSO connections and a support relationship with a large hosted vendor. - You want Auth0 for AI Agents (Token Vault for third-party API tokens, asynchronous authorization) without operating anything. ### Choose theAuth if - Your agents need their own identity: an owner, scoped permissions, delegation depth limits, budgets and a per-agent audit trail, in the same library as human sign-in. - You need to self-host, or keep tokens, sessions and audit data in your own database. - You want auth code in your repository under MIT, running on Workers, Deno or Bun. theAuth is an open source Auth0 alternative for teams that want agent identity in the same library as human sign-in. It is not the right pick for every team, and the first column says so. ## theAuth vs Auth0 feature comparison Feature comparison of Auth0 and theAuth | Feature | Auth0 | theAuth | | --- | --- | --- | | Source license | No, Proprietary (per theAuth README) | Yes, MIT | | Self-hostable | Partial or different, Managed private cloud on AWS or Azure for teams that cannot use the public cloud; not self-hosted | Yes, Yes, on your own database | | OAuth 2.1 authorization server for MCP | Yes, Yes, Auth0 for MCP | Yes, Yes, built in | | Dynamic client registration | Partial or different, Supported; Auth0 recommends manual CIMD registration for production and lists open DCR security controls as Enterprise only | Yes, RFC 7591 supported; CIMD in the Go module | | Agent-specific features | Partial or different, Auth0 for AI Agents: Token Vault and CIBA, sold as an add-on on paid plans | Yes, Agent identity, delegation chains, budgets, audit | | Hosted login page | Yes, Universal Login, customizable in the dashboard | Partial or different, Headless building blocks and client SDKs, no hosted page | | Enterprise SSO | Yes, Enterprise connections; included counts vary by plan | Yes, SAML 2.0 and OIDC SSO, SCIM 2.0 | | Entry cost | Yes, A free plan exists; see the pricing page for limits | Yes, MIT library; Cloud in early access, no published prices | Check mark: yes. Dash: partial, different, or not found in the docs we checked. Cross: no. Claims about Auth0 are from its own public docs (see Sources); theAuth rows are from its repositories. 01 ## Auth0 alternative for AI agents: identity and delegation Both cover agents acting for users. They model them differently. Auth0 Auth0 for AI Agents is an add-on to paid plans. Its Token Vault manages issuance, storage, rotation and revocation of tokens for external APIs such as Google, Microsoft, Jira and Notion, and it supports asynchronous authorization (CIBA). The focus is an agent acting on behalf of a signed-in user with centralized authorization. theAuth theAuth models an agent as an identity with an owner, a cryptographic bearer token (kv_...), wildcard permissions such as mcp:github:*, and delegation chains with configurable depth limits. On top of that sit budget policies per agent, trust scoring, CIBA-style approval for sensitive tool calls, and a full audit trail of every agent action. Read the [agents guide](https://docs.theauth.dev/agents) and [delegation docs](https://docs.theauth.dev/delegation). 02 ## MCP OAuth 2.1 support Auth0 can be your MCP authorization server too. Auth0 Auth0 documents Auth for MCP: it acts as the authorization server, issues tokens, exposes discovery metadata, and lets an MCP server exchange a client token for a short-lived token scoped to an internal API. For production it recommends manual CIMD registration over open dynamic client registration, and says the security options for open registration are for Enterprise customers. theAuth theAuth ships an OAuth 2.1 authorization server for MCP: PKCE S256, RFC 9728 protected resource metadata, RFC 8707 resource indicators, RFC 8414 server metadata and RFC 7591 dynamic client registration. The Go module adds RFC 8693 token exchange, DPoP, PAR, JAR, CIBA, CIMD per the MCP spec of 2025-11-25 and refresh token rotation with family revocation. See the [MCP guide](https://docs.theauth.dev/mcp). 03 ## Self-hosted Auth0 alternative: data ownership Hosted by Auth0, or stored in your database. Auth0 Auth0 runs the service. For organizations that cannot use the multi-tenant public cloud it offers managed private cloud on AWS or Azure. In both cases Auth0 operates it; you do not run the code yourself. theAuth theAuth is MIT licensed and runs against your own database: SQLite, PostgreSQL, MySQL or Cloudflare D1 in TypeScript, and Postgres, MySQL or in-memory storage in Go. Users, sessions, tokens and audit records stay in storage you control. A hosted theAuth Cloud is in early access for teams that would rather not run it. 04 ## Licensing and cost model Proprietary plans against an MIT library. Auth0 Auth0 is proprietary and sold by plan, with limits that change by plan: monthly active users, organizations, enterprise connections, machine-to-machine tokens and the AI agents add-on. Prices and limits move, so read the [Auth0 pricing page](https://auth0.com/pricing) instead of trusting a number copied here. theAuth The library is free under the MIT license. Your costs are the database, the compute and the engineering time to operate it. theAuth Cloud is in early access and has no published prices. 05 ## Edge runtimes Where each one runs. Auth0 Auth0 is a hosted service your app reaches over HTTPS, so any runtime that can make requests and verify JWTs can use it. How much SDK support you get on a given edge platform varies, so check the SDK for your runtime. theAuth The TypeScript core runs on Cloudflare Workers, Deno and Bun without code changes, with three runtime dependencies: drizzle-orm, jose and zod. Adapters cover Next.js, SvelteKit, Nuxt, Hono, Express, Fastify, Astro, NestJS, SolidStart and TanStack Start. ## Migrating from Auth0 to theAuth theAuth has an [Auth0 migration guide](https://docs.theauth.dev/migrate/from-auth0). It maps tenants, applications, machine-to-machine clients, Actions and organizations to theAuth equivalents, with code diffs, a user export and import plan, and a rollback plan. Plan for what you give up: Auth0's hosted Universal Login page and Guardian MFA app have no direct equivalent, because theAuth ships headless building blocks. The repository also has a [migrate-from-auth0 example](https://github.com/glincker/theauth/tree/main/examples/migrate-from-auth0). [Auth0 migration guide](https://docs.theauth.dev/migrate/from-auth0) [All migration guides](https://docs.theauth.dev/migrate) ## Auth0 alternative: common questions **Is theAuth an Auth0 alternative for AI agents?** It can be. theAuth is an open source library that gives each AI agent its own identity, scoped permissions, delegation limits and audit trail, and it includes an MCP OAuth 2.1 authorization server. Auth0 also offers Auth0 for AI Agents and Auth for MCP as a hosted service, so the real choice is how you want to run it and how you want to model agents. **Can I self-host Auth0?** No. Auth0 offers managed private cloud on AWS or Azure for organizations that cannot use the multi-tenant public cloud, but Auth0 operates it. theAuth is MIT licensed and runs on your own database. **Does Auth0 support MCP OAuth 2.1?** Yes. Auth0 documents Auth for MCP, where it acts as the authorization server for an MCP server. It recommends manual CIMD registration over open dynamic client registration in production. theAuth also ships an MCP OAuth 2.1 authorization server, built into the library. **What do I lose when I move from Auth0 to theAuth?** Mainly the hosted pieces. Universal Login is a hosted page that Auth0 runs and you customize in a dashboard, and theAuth provides headless building blocks instead. You also give up having a vendor operate the service. **How does Auth0 pricing compare with theAuth?** Auth0 sells plans with limits on monthly active users, organizations, connections and add-ons, and those numbers change, so check its pricing page. The theAuth library is free under MIT, and you pay for your own database and compute. theAuth Cloud is in early access with no published prices. ## Sources Last verified: 2026-10-07. Competitor facts come from the public pages below; plans and prices change, so confirm there. - [Auth0 pricing](https://auth0.com/pricing) auth0.com/pricing - [Auth0 for AI Agents](https://auth0.com/ai) auth0.com/ai - [Auth0 for MCP overview](https://auth0.com/ai/docs/mcp/intro/overview) auth0.com/ai/docs/mcp/intro/overview - [Auth0 dynamic client registration for MCP](https://auth0.com/ai/docs/mcp/guides/registering-your-mcp-client-application/dynamic-client-registration) auth0.com/ai/docs/mcp/guides/registering-your-mcp-client-application/dynamic-client-registration - [Auth0 private cloud deployment](https://auth0.com/docs/deploy-monitor/deploy-private-cloud) auth0.com/docs/deploy-monitor/deploy-private-cloud - [Auth0 Universal Login](https://auth0.com/docs/authenticate/login/auth0-universal-login) auth0.com/docs/authenticate/login/auth0-universal-login - [theAuth README comparison table](https://github.com/glincker/theauth) github.com/glincker/theauth ## Keep reading [Auth0 for MCP and Token Vault, compared](https://theauth.dev/compare/auth0-for-mcp/) [All comparisons](https://theauth.dev/compare/) [Agent identity](https://theauth.dev/#agents) [MCP OAuth 2.1](https://theauth.dev/#mcp) [Trust and enterprise](https://theauth.dev/#trust) [Docs comparisons](https://docs.theauth.dev/compare) --- URL: https://theauth.dev/compare/auth0-for-mcp/ Auth0 Auth for MCP against a self-hosted MCP authorization server # theAuth vs Auth0 for MCP Auth0 now sells Auth for MCP and Token Vault as part of Auth0 for AI Agents. This page covers only the MCP and agent parts. For the general comparison see theAuth vs Auth0. Last verified: 2026-10-08. Hosted MCP authorization against an MIT library. General comparison: [theAuth vs Auth0](https://theauth.dev/compare/auth0/). [Get started](https://theauth.dev/get-started/) [Feature table](https://theauth.dev/compare/auth0-for-mcp/#table) Moving from Auth0? You can [migrate to theAuth without a rewrite](https://theauth.dev/migrate/) by running both systems and moving users as they sign in. Docs: [Auth0 migration guide](https://docs.theauth.dev/migrate/from-auth0). [Plan the migration](https://theauth.dev/migrate/) ## Short answer ### Choose Auth0 for MCP if - You already run Auth0 and want your MCP server to use the same tenant, connections and enterprise identity providers. - Your agents call Google, Microsoft, Jira or Notion for users, and you want Token Vault to hold and rotate those tokens. - You want On-Behalf-Of token exchange so an MCP server can call an internal API with a short-lived token. ### Choose theAuth if - You need to self-host the MCP authorization server and keep tokens in your own database. - You want agents modeled as identities with owners, delegation depth limits, budgets and approval gates. - You want open dynamic client registration without an Enterprise plan, with the controls under your own config. If you are choosing between the two on MCP alone, the questions are hosting, the outbound token vault, and how agents are represented. ## theAuth vs Auth0 for MCP feature comparison Feature comparison of Auth0 for MCP and theAuth | Feature | Auth0 for MCP | theAuth | | --- | --- | --- | | Authorization server for MCP | Yes, Yes, Auth for MCP issues and validates OAuth tokens | Yes, Yes, built in | | Sign-in through enterprise identity providers | Yes, Yes, such as Okta, Entra ID, Ping and Google Workspace | Yes, SAML 2.0 and OIDC SSO, SCIM 2.0 | | Token exchange for internal APIs | Yes, Yes, On-Behalf-Of flow | Yes, RFC 8693 token exchange in the Go module | | Third-party API token vault | Yes, Yes, Token Vault for Google, Microsoft, Jira, Notion and others | No, Not offered | | Dynamic client registration | Partial or different, Supported; manual CIMD registration recommended for production, and open registration security options listed as Enterprise | Yes, RFC 7591; CIMD in the Go module | | Self-hostable | No, No, managed service (private cloud is operated by Auth0) | Yes, Yes, on your own database | | Agent identity with delegation chains | Partial or different, Scoped permissions for agents; no owner and depth-capped delegation model found in the pages we checked | Yes, Owner, token, delegation chains, budgets, audit | Check mark: yes. Dash: partial, different, or not found in the docs we checked. Cross: no. Claims about Auth0 for MCP are from its own public pages (see Sources). theAuth rows are from its repositories. 01 ## Auth for MCP against the built-in server Both can issue the token your MCP server validates. Auth0 for MCP Auth0 documents Auth for MCP as user authentication through identity providers, OAuth 2.0 access token issuance and validation, standards-aligned client registration and discovery, scoped permissions, and On-Behalf-Of token exchange for calling internal APIs. For production it recommends manual CIMD registration over open dynamic client registration. theAuth theAuth ships the authorization server in the library: PKCE S256, RFC 9728, RFC 8707, RFC 8414 and RFC 7591, with DPoP, PAR, JAR, CIBA and CIMD in the Go module. You run it. Walk through it in [the TypeScript guide](https://theauth.dev/guides/mcp-server-typescript/). 02 ## Calling third-party APIs The main thing theAuth does not do. Auth0 for MCP Token Vault manages issuance, storage, rotation and revocation of tokens for external APIs such as Google, Microsoft, Jira and Notion, so an agent can act in those services without your code handling the credentials. Auth0 sells this as part of Auth0 for AI Agents. theAuth theAuth authorizes actions on your own resources and issues tokens for them. It has no outbound token vault, so tokens for third-party APIs stay in your hands or in another tool. If that is the center of your agent design, Auth0 is the stronger fit. 03 ## How an agent is represented Permissions on a client, or an identity with an owner. Auth0 for MCP Auth0 for AI Agents focuses on an agent acting for a signed-in user with centralized authorization, plus asynchronous authorization through CIBA. theAuth theAuth makes the agent a named identity with an owner and wildcard permission patterns, hands sub-agents a narrower subset through delegation chains with a depth cap, and writes an audit row per decision. See [delegation](https://docs.theauth.dev/delegation) and [approval](https://docs.theauth.dev/approval). ## Auth0 for MCP alternative: common questions **Does Auth0 support MCP authorization?** Yes. Auth0 documents Auth for MCP, where it acts as the authorization server for an MCP server, and Token Vault for calling third-party APIs. theAuth also ships an MCP OAuth 2.1 authorization server. **What is the difference between Auth for MCP and Token Vault?** Auth for MCP covers authenticating users and issuing tokens that an MCP server validates. Token Vault stores and rotates tokens for external APIs that an agent calls on a user's behalf. **Can I self-host an Auth0 MCP setup?** No. Auth0 operates the service, including private cloud. theAuth is MIT licensed and runs on your own database. **Does theAuth replace Token Vault?** No. theAuth has no outbound token vault. It authorizes what agents do in your own system. ## Sources Last verified: 2026-10-08. Competitor facts come from the public pages below. Plans, limits and prices change, so confirm there. The general comparison page was re-read against the same pages on this date and its claims about Auth for MCP and Token Vault still hold. - [Auth0 for MCP overview](https://auth0.com/ai/docs/mcp/intro/overview) auth0.com/ai/docs/mcp/intro/overview - [Auth0 for AI Agents](https://auth0.com/ai) auth0.com/ai - [Auth0 dynamic client registration for MCP](https://auth0.com/ai/docs/mcp/guides/registering-your-mcp-client-application/dynamic-client-registration) auth0.com/ai/docs/mcp/guides/registering-your-mcp-client-application/dynamic-client-registration - [Auth0 private cloud deployment](https://auth0.com/docs/deploy-monitor/deploy-private-cloud) auth0.com/docs/deploy-monitor/deploy-private-cloud - [Auth0 pricing](https://auth0.com/pricing) auth0.com/pricing - [theAuth repository and README](https://github.com/glincker/theauth) github.com/glincker/theauth - [theauth-go repository and README](https://github.com/glincker/theauth-go) github.com/glincker/theauth-go ## Keep reading [All comparisons](https://theauth.dev/compare/) [Get started](https://theauth.dev/get-started/) [MCP OAuth 2.1](https://theauth.dev/mcp-oauth/) [Agent identity](https://theauth.dev/agent-identity/) [Guides](https://theauth.dev/guides/) --- URL: https://theauth.dev/compare/stytch/ A self-hosted Stytch alternative for AI agents # theAuth vs Stytch Stytch is a hosted authentication service with Connected Apps for MCP and agent access. theAuth is an MIT library you run next to your own data, with AI agents modeled as identities of their own. Last verified: 2026-10-08. Hosted service against an MIT library. [Get started](https://theauth.dev/get-started/) [Feature table](https://theauth.dev/compare/stytch/#table) Moving from Stytch? You can [migrate to theAuth without a rewrite](https://theauth.dev/migrate/) by running both systems and moving users as they sign in. Docs: [importing users from a CSV or JSON export](https://docs.theauth.dev/migrate/import-users) and [picking a migration path](https://docs.theauth.dev/migrate/choose-a-path). [Plan the migration](https://theauth.dev/migrate/) ## Short answer ### Choose Stytch if - You want a vendor to run authentication and the OAuth server for your MCP clients, with an SDK on your side. - Your pricing model fits its usage metering, which counts AI agents next to users on its pricing page. - You prefer buying a service to operating a database, signing keys and a login surface yourself. ### Choose theAuth if - You need to self-host, or keep users, tokens and audit rows in your own database. - Your agents need an identity of their own: an owner, scoped permissions, delegation depth limits, budgets and a per-agent audit trail. - You write Go as well as TypeScript and want the same model in both. Both can protect an MCP server with OAuth 2.1. The difference is who runs it and how an agent is represented, not whether it is possible. ## theAuth vs Stytch feature comparison Feature comparison of Stytch and theAuth | Feature | Stytch | theAuth | | --- | --- | --- | | Self-hostable | Partial or different, Hosted service; no self-hosting option found in the docs we checked | Yes, Yes, on your own database | | OAuth server for MCP clients | Yes, Yes, Connected Apps | Yes, Yes, built in | | Dynamic client registration | Yes, Yes, MCP clients can self-register | Yes, RFC 7591 supported; closed by default in Go | | Agent as its own identity | Partial or different, Agents are counted in pricing; an owner and delegation model was not found in the pages we checked | Yes, Owner, token, permissions, delegation chains, budgets, audit | | Access control | Yes, Role-based access control with scopes and permissions | Yes, Wildcard permissions, RBAC, ReBAC, policy engine | | Runs on edge runtimes | Partial or different, Hosted API reached over HTTPS | Yes, Workers, Deno, Bun (TypeScript); single static binary (Go) | | Cost model | Partial or different, Usage-based, with a free allowance; see its pricing page | Yes, MIT library; Cloud in early access, no published prices | Check mark: yes. Dash: partial, different, or not found in the docs we checked. Cross: no. Claims about Stytch are from its own public pages (see Sources). theAuth rows are from its repositories. 01 ## How each one models an agent Counted as a user-like principal, or its own identity. Stytch Stytch Connected Apps lets third-party apps and AI agents get access to your application on a user's behalf. Its pricing page counts monthly active users and AI agents together. We did not find a documented owner, delegation chain or per-agent budget in the pages we checked. theAuth theAuth models an agent as an identity with an owner, a cryptographic bearer token, wildcard permissions such as mcp:github:*, and delegation chains with configurable depth limits. Budget policies, trust scoring and approval gates sit on top, and every decision is written to the audit log. Read the [agents guide](https://docs.theauth.dev/agents). 02 ## Protecting an MCP server Both can be the authorization server. Stytch Stytch documents using Connected Apps with an MCP server built on the open @modelcontextprotocol/sdk. The authorization is hosted: your server validates what Stytch issues, and MCP clients register dynamically. theAuth theAuth ships the OAuth 2.1 authorization server inside the library: PKCE S256, RFC 9728 resource metadata, RFC 8707 resource indicators, RFC 8414 metadata and RFC 7591 registration. The Go module adds DPoP, PAR, JAR, CIBA and CIMD. A step-by-step version is in [Secure an MCP server in 10 minutes](https://theauth.dev/guides/mcp-server-typescript/). 03 ## Who operates it, and how it is billed A metered service against a library you run. Stytch Stytch is a hosted service with usage-based pricing and a free allowance. That removes the work of running auth. It also means users, tokens and sessions live with the vendor, and cost follows usage. theAuth The library is free under MIT. Your costs are the database, the compute and the time to operate it. You also own the failure modes: signing key rotation, backups and upgrades are yours. theAuth Cloud is in early access and has no published prices. ## Stytch alternative: common questions **Is theAuth a Stytch alternative for AI agents?** It can be. theAuth is an open source library that gives each AI agent its own identity, scoped permissions, delegation limits and audit trail, and it includes an MCP OAuth 2.1 authorization server. Stytch offers Connected Apps as a hosted service, so the real choice is who runs it. **Can I self-host Stytch?** We found no self-hosting option in the Stytch pages we checked. Stytch is described as a hosted service. theAuth is MIT licensed and runs on your own database. **Does Stytch support MCP?** Yes. Stytch documents Connected Apps for MCP servers, including dynamic client registration. theAuth also ships an MCP OAuth 2.1 authorization server in the library. **What do I give up by choosing theAuth?** Mainly the hosted operation. You run the database and the upgrade path, and there is no vendor support contract. theAuth Cloud is in early access for teams that would rather not run it. ## Sources Last verified: 2026-10-08. Competitor facts come from the public pages below. Plans, limits and prices change, so confirm there. - [Stytch: MCP servers with Connected Apps](https://stytch.com/docs/guides/connected-apps/mcp-servers) stytch.com/docs/guides/connected-apps/mcp-servers - [Stytch pricing](https://stytch.com/pricing) stytch.com/pricing - [theAuth repository and README](https://github.com/glincker/theauth) github.com/glincker/theauth - [theauth-go repository and README](https://github.com/glincker/theauth-go) github.com/glincker/theauth-go ## Keep reading [All comparisons](https://theauth.dev/compare/) [Get started](https://theauth.dev/get-started/) [MCP OAuth 2.1](https://theauth.dev/mcp-oauth/) [Agent identity](https://theauth.dev/agent-identity/) [Guides](https://theauth.dev/guides/) --- URL: https://theauth.dev/compare/workos/ A self-hosted WorkOS alternative for MCP authorization # theAuth vs WorkOS WorkOS AuthKit can act as the OAuth authorization server for your MCP server, and you verify tokens. theAuth puts the authorization server inside a library you run, and models agents as identities. Last verified: 2026-10-08. Hosted authorization server against an MIT library. [Get started](https://theauth.dev/get-started/) [Feature table](https://theauth.dev/compare/workos/#table) Moving from WorkOS? You can [migrate to theAuth without a rewrite](https://theauth.dev/migrate/) by running both systems and moving users as they sign in. Docs: [importing users from a CSV or JSON export](https://docs.theauth.dev/migrate/import-users) and [picking a migration path](https://docs.theauth.dev/migrate/choose-a-path). [Plan the migration](https://theauth.dev/migrate/) ## Short answer ### Choose WorkOS if - You want a vendor to run the authorization server, consent flow and token issuance, and your MCP server only verifies JWTs. - You want Client ID Metadata Documents on by default and Cross App Access support from a hosted service. - You already use WorkOS for your users and want MCP clients to sign in against the same directory. ### Choose theAuth if - You need to self-host the authorization server, or keep tokens and audit data in your own database. - Your agents need an owner, scoped permissions, delegation depth limits and per-agent audit, beyond a client and a token. - You want one library that covers human sign-in, agent identity and the MCP authorization server, in TypeScript or Go. WorkOS and theAuth both cover MCP authorization. WorkOS keeps the server on its side and hands you a verifier. theAuth hands you the server. ## theAuth vs WorkOS feature comparison Feature comparison of WorkOS and theAuth | Feature | WorkOS | theAuth | | --- | --- | --- | | Self-hostable | Partial or different, Hosted; no self-hosting option found in the docs we checked | Yes, Yes, on your own database | | OAuth authorization server for MCP | Yes, Yes, AuthKit as a spec-compatible server | Yes, Yes, built in | | Client ID Metadata Documents (CIMD) | Yes, Yes, the default for new MCP clients | Yes, Yes in the Go module; opt-in and fail-closed | | Dynamic client registration | Yes, Yes, kept for older MCP clients | Yes, RFC 7591; closed by default in Go | | Resource indicators | Yes, Yes, with wildcard support | Yes, RFC 8707 supported | | Agent as its own identity | Partial or different, Not found in the MCP docs we checked | Yes, Owner, token, permissions, delegation chains, budgets, audit | | What you build | Partial or different, Bearer middleware, JWT verification and metadata endpoints | Partial or different, Storage callbacks (TypeScript) or a config struct (Go), then mount | Check mark: yes. Dash: partial, different, or not found in the docs we checked. Cross: no. Claims about WorkOS are from its own public pages (see Sources). theAuth rows are from its repositories. 01 ## Where the authorization server runs A hosted server you verify against, or a library you mount. WorkOS WorkOS documents AuthKit as the OAuth authorization server for MCP. It handles authorization, token issuance and consent. Your MCP server verifies JWTs against a remote JWKS and serves the protected resource metadata endpoint. CIMD is the default for new clients, and dynamic client registration stays for older ones. theAuth theAuth runs the authorization server in your process. You supply storage and a way to know which user is signed in, and theAuth serves the metadata, registration, authorize and token endpoints. The tradeoff is that you operate it. See [the TypeScript guide](https://theauth.dev/guides/mcp-server-typescript/) or [the Go guide](https://theauth.dev/guides/mcp-authorization-server-go/). 02 ## What an agent is A client with a token, or an identity with an owner. WorkOS In the MCP material we checked, WorkOS treats the MCP client as an OAuth client that a signed-in user authorizes. It also documents Cross App Access through an ID Token JWT Authorization Grant exchange for enterprise setups. theAuth theAuth adds an agent layer on top of OAuth: an owner, wildcard permission patterns with constraints, delegation chains that narrow at every hop and cap their depth, budgets, and approval gates. Revoking an agent does not touch anyone else. Read the [delegation docs](https://docs.theauth.dev/delegation). 03 ## Operations and billing What you run, what you pay. WorkOS WorkOS operates the service, so there is no database or signing key for you to run for authorization. Plans and prices change; read its pricing page instead of a number copied here. theAuth The library is free under MIT, with your own database and compute. theAuth Cloud is in early access with no published prices. ## WorkOS alternative: common questions **Is theAuth a WorkOS alternative?** For MCP authorization and agent identity, it can be. theAuth is an open source library with its own authorization server, agent identities and human sign-in. WorkOS offers AuthKit as a hosted service, so the choice is mostly about who runs it. **Does WorkOS support MCP?** Yes. WorkOS documents AuthKit as an OAuth authorization server for MCP, with Client ID Metadata Documents and dynamic client registration. theAuth also ships an MCP OAuth 2.1 authorization server. **Can I self-host WorkOS AuthKit?** We found no self-hosting option in the WorkOS pages we checked. theAuth is MIT licensed and runs on your own database. **Does theAuth support CIMD?** The Go module supports Client ID Metadata Documents per the MCP spec of 2025-11-25, off by default. The TypeScript library supports dynamic client registration. ## Sources Last verified: 2026-10-08. Competitor facts come from the public pages below. Plans, limits and prices change, so confirm there. The WorkOS pricing page is linked for reference; we state no WorkOS prices here. - [WorkOS: MCP authorization overview](https://workos.com/docs/authkit/mcp) workos.com/docs/authkit/mcp - [WorkOS pricing](https://workos.com/pricing) workos.com/pricing - [theAuth repository and README](https://github.com/glincker/theauth) github.com/glincker/theauth - [theauth-go repository and README](https://github.com/glincker/theauth-go) github.com/glincker/theauth-go ## Keep reading [All comparisons](https://theauth.dev/compare/) [Get started](https://theauth.dev/get-started/) [MCP OAuth 2.1](https://theauth.dev/mcp-oauth/) [Agent identity](https://theauth.dev/agent-identity/) [Guides](https://theauth.dev/guides/) --- URL: https://theauth.dev/compare/descope/ A self-hosted Descope alternative for AI agents # theAuth vs Descope Descope sells an Agentic Identity Hub with agent identities, MCP server authentication and managed connections to third-party services. theAuth covers agent identity and MCP authorization as an MIT library you run. Last verified: 2026-10-08. Hosted platform against an MIT library. [Get started](https://theauth.dev/get-started/) [Feature table](https://theauth.dev/compare/descope/#table) Moving from Descope? You can [migrate to theAuth without a rewrite](https://theauth.dev/migrate/) by running both systems and moving users as they sign in. Docs: [importing users from a CSV or JSON export](https://docs.theauth.dev/migrate/import-users) and [picking a migration path](https://docs.theauth.dev/migrate/choose-a-path). [Plan the migration](https://theauth.dev/migrate/) ## Short answer ### Choose Descope if - You want agents to call third-party services with managed credentials, using prebuilt connection templates, without storing those tokens yourself. - You want a vendor to run MCP server authentication, client registration and consent. - You want enterprise customers to manage agent permissions from their own identity provider (Cross-App Access). ### Choose theAuth if - You need to self-host, or keep tokens, sessions and audit data in your own database. - You want agent identity, delegation chains with depth limits, budgets and approval gates in the same library as human sign-in. - You want the authorization server in your own repository, readable and forkable under MIT. Descope is the closest hosted match to what theAuth does for agents. Its distinct strength is managed outbound connections, which theAuth does not offer. ## theAuth vs Descope feature comparison Feature comparison of Descope and theAuth | Feature | Descope | theAuth | | --- | --- | --- | | Self-hostable | Partial or different, Sold as plans with a free tier; no self-hosting option found in the pages we checked | Yes, Yes, on your own database | | Dedicated identities for agents | Yes, Yes, with attributes for users, tenants and tool scopes | Yes, Yes, with owner, type and token | | MCP server authentication | Yes, Yes, OAuth 2.1, client registration and consent | Yes, Yes, built in | | Access policies per tool | Yes, Per tool, tenant and MCP server | Yes, Wildcard permission patterns, constraints, policy engine | | Audit of agent actions | Yes, Yes, linked to the delegating user | Yes, Yes, every decision, JSON or CSV export | | Managed credentials for third-party APIs | Yes, Yes, 50+ templates plus OAuth and API key setups | No, Not offered; you hold those tokens | | Delegation chains with a depth cap | Partial or different, Not found in the pages we checked | Yes, Yes, default maximum depth of 3 | Check mark: yes. Dash: partial, different, or not found in the docs we checked. Cross: no. Claims about Descope are from its own public pages (see Sources). theAuth rows are from its repositories. 01 ## Agent identity Both treat the agent as a first-class thing. Descope Descope's Agentic Identity Hub gives agents dedicated identities with attributes such as associated users, tenants and tool-level scopes. It issues short-lived, scoped credentials, applies access policies per tool, tenant and MCP server, and logs agent actions against the delegating user. theAuth theAuth gives each agent an owner, a kv_... bearer token (only a hash is stored), wildcard permissions with constraints, delegation chains that can only narrow permissions, and budget policies per agent. See [agent identity](https://theauth.dev/agent-identity/). 02 ## Calling other services as the user Where Descope is ahead. Descope Descope documents managed connections to downstream services with more than 50 prebuilt templates, plus plain OAuth and API key setups, so an agent can call those services without you storing the tokens. theAuth theAuth does not run an outbound token vault. It authorizes what an agent may do inside your system and issues tokens for your own resources. If your agents mainly call Google, Slack or Jira on behalf of users, that is a reason to look at Descope or Auth0 Token Vault. 03 ## Operations and billing Plans and meters, or a library. Descope Descope has a free tier and paid plans with usage-based overages that meter things such as monthly active users, tenants and M2M token exchanges. Check its pricing page for current limits. theAuth The library is free under MIT. You run the database and compute. theAuth Cloud is in early access with no published prices. ## Descope alternative: common questions **Is theAuth a Descope alternative for AI agents?** For agent identity and MCP authorization, yes. Both give agents identities and protect MCP servers with OAuth 2.1. The differences are hosted versus self-hosted, and that Descope also offers managed credentials for third-party services, which theAuth does not. **Does Descope support MCP?** Yes. Descope documents MCP server authentication with OAuth 2.1, client registration and consent flows, as part of its Agentic Identity Hub. **Can I self-host Descope?** We found no self-hosting option in the pages we checked. theAuth is MIT licensed and runs on your own database. **Where is Descope the better choice?** When agents mainly call third-party APIs for users and you want a vendor to hold those credentials, or when enterprise customers should govern agent permissions from their own identity provider. ## Sources Last verified: 2026-10-08. Competitor facts come from the public pages below. Plans, limits and prices change, so confirm there. The Descope pages we checked did not state whether it can be self-hosted, so that row says only what we did not find. - [Descope: AI and agentic identity](https://www.descope.com/use-cases/ai) www.descope.com/use-cases/ai - [Descope pricing](https://www.descope.com/pricing) www.descope.com/pricing - [theAuth repository and README](https://github.com/glincker/theauth) github.com/glincker/theauth - [theauth-go repository and README](https://github.com/glincker/theauth-go) github.com/glincker/theauth-go ## Keep reading [All comparisons](https://theauth.dev/compare/) [Get started](https://theauth.dev/get-started/) [MCP OAuth 2.1](https://theauth.dev/mcp-oauth/) [Agent identity](https://theauth.dev/agent-identity/) [Guides](https://theauth.dev/guides/) --- URL: https://theauth.dev/compare/clerk/ The open source Clerk alternative for AI agents # theAuth vs Clerk Clerk is a hosted auth service with prebuilt UI components. theAuth is an MIT library you run yourself, with AI agents modeled as identities of their own. Last verified: 2026-10-07. Hosted platform against an MIT library. [Read the quickstart](https://docs.theauth.dev/quickstart) [Migration steps](https://theauth.dev/compare/clerk/#migration) Moving from Clerk? You can [migrate to theAuth without a rewrite](https://theauth.dev/migrate/) by running both systems and moving users as they sign in. Docs: [Clerk migration guide](https://docs.theauth.dev/migrate/from-clerk). [Plan the migration](https://theauth.dev/migrate/) ## Short answer ### Choose Clerk if - You want prebuilt sign-in, profile and organization components and a hosted backend you never operate. - You build on React, Next.js, Vue or Astro and want the fastest path to a working login screen. - You need MCP authorization for user-delegated access through Clerk's OAuth server and helpers, and do not need agents as separate identities. ### Choose theAuth if - Agents need their own identity with an owner, delegation depth limits, budgets and a per-agent audit trail. - You must self-host, or you want sessions and user data in your own database. - You want an MIT license and no vendor billing tied to your user counts, plus Go and Python SDKs next to TypeScript. theAuth is an open source Clerk alternative for teams that want agent identity in the same library as human sign-in. It is not the right pick for every team, and the first column says so. ## theAuth vs Clerk feature comparison Feature comparison of Clerk and theAuth | Feature | Clerk | theAuth | | --- | --- | --- | | Source license | No, Proprietary (per theAuth README) | Yes, MIT | | Self-hostable | No, No, hosted service (per theAuth README) | Yes, Yes, on your own database | | Prebuilt UI components | Yes, Component suite across React, Next.js, Vue, Astro and more | Partial or different, Client SDKs for React, Vue, Svelte, Expo and Electron | | OAuth 2.1 authorization server for MCP | Yes, Yes, Clerk OAuth server with CIMD and DCR | Yes, Yes, built in | | Agent identity with delegation and budgets | Partial or different, Not found in the Clerk docs we checked | Yes, Owner, delegation chains, budgets, audit | | Organizations | Partial or different, Offered as a B2B add-on, priced separately | Yes, Organizations with RBAC in the library | | Enterprise SSO | Yes, SSO connections; one included on paid plans, more priced per connection | Yes, SAML 2.0 and OIDC SSO, SCIM 2.0 | | Billing unit | Monthly retained users, so sign-ups who never return are not counted | Library has no per-user fee; Cloud in early access | Check mark: yes. Dash: partial, different, or not found in the docs we checked. Cross: no. Claims about Clerk are from its own public docs (see Sources); theAuth rows are from its repositories. 01 ## Clerk alternative for AI agents: identity and delegation Users delegating to agents, or agents as identities. Clerk Clerk's MCP and OAuth support is built around users granting access to an MCP server you build, with helpers such as mcp-handler and @clerk/mcp-tools. In the Clerk docs we reviewed we did not find an agent identity model with delegation chains or per-agent budgets. If you need one, check Clerk's docs for your case. theAuth theAuth models an agent as an identity with an owner, a cryptographic bearer token (kv_...), wildcard permissions such as mcp:github:*, and delegation chains with configurable depth limits. On top of that sit budget policies per agent, trust scoring, CIBA-style approval for sensitive tool calls, and a full audit trail of every agent action. Read the [agents guide](https://docs.theauth.dev/agents) and [delegation docs](https://docs.theauth.dev/delegation). 02 ## MCP OAuth 2.1 support Clerk can issue the tokens for an MCP server. Clerk Clerk documents building an MCP server in your app with Clerk acting as the OAuth server. It supports Client ID Metadata Documents (recommended for AI agents) and dynamic client registration, each toggled in the dashboard, and it requires PKCE with S256 for the DCR path it shows. theAuth theAuth ships an OAuth 2.1 authorization server for MCP: PKCE S256, RFC 9728 protected resource metadata, RFC 8707 resource indicators, RFC 8414 server metadata and RFC 7591 dynamic client registration. The Go module adds RFC 8693 token exchange, DPoP, PAR, JAR, CIBA, CIMD per the MCP spec of 2025-11-25 and refresh token rotation with family revocation. See the [MCP guide](https://docs.theauth.dev/mcp). 03 ## Self-hosted Clerk alternative: data ownership A hosted service against your own database. Clerk Clerk is a hosted service. We found no self-hosted option, and the theAuth README lists Clerk as not self-hostable. User records live with the vendor. If your data must stay in your own infrastructure, that rules it out. theAuth theAuth is MIT licensed and runs against your own database: SQLite, PostgreSQL, MySQL or Cloudflare D1 in TypeScript, and Postgres, MySQL or in-memory storage in Go. Users, sessions, tokens and audit records stay in storage you control. A hosted theAuth Cloud is in early access for teams that would rather not run it. 04 ## Licensing and cost model Hosted billing against an MIT library. Clerk Clerk is proprietary and bills on monthly retained users, with separate pricing for the B2B organizations add-on and for SSO connections beyond the included one. Plans and limits change, so check the [Clerk pricing page](https://clerk.com/pricing). theAuth The library is free under the MIT license. Your costs are the database, the compute and the engineering time to operate it. theAuth Cloud is in early access and has no published prices. 05 ## Edge runtimes Where each one runs. Clerk Because Clerk is hosted, your app talks to it through a framework SDK or by verifying its tokens. Runtime support depends on the SDK for your framework, so confirm it in Clerk's docs for the platform you deploy on. theAuth The TypeScript core runs on Cloudflare Workers, Deno and Bun without code changes, with three runtime dependencies: drizzle-orm, jose and zod. Adapters cover Next.js, SvelteKit, Nuxt, Hono, Express, Fastify, Astro, NestJS, SolidStart and TanStack Start. ## Migrating from Clerk to theAuth theAuth has a [Clerk migration guide](https://docs.theauth.dev/migrate/from-clerk) with a concepts map, a hooks and middleware diff, a Clerk data export plan and a rollout plan. Prebuilt Clerk components do not carry over, so budget time for your sign-in screens. [Clerk migration guide](https://docs.theauth.dev/migrate/from-clerk) [All migration guides](https://docs.theauth.dev/migrate) ## Clerk alternative: common questions **Is theAuth a Clerk alternative for AI agents?** It can be. theAuth is an open source library with agent identity, scoped permissions, delegation limits, budgets and audit, plus an MCP OAuth 2.1 authorization server. Clerk also documents an OAuth server for MCP, so pick based on whether you want a hosted service or a library, and whether agents need their own identity. **Can I self-host Clerk?** We found no self-hosted option for Clerk, and the theAuth README lists it as not self-hostable. theAuth is MIT licensed and runs on your own database. **Does Clerk support MCP?** Yes. Clerk documents using its OAuth server to protect an MCP server you build, with support for Client ID Metadata Documents and dynamic client registration. theAuth includes its own MCP OAuth 2.1 authorization server. **How is Clerk billed compared with theAuth?** Clerk bills on monthly retained users, with separate pricing for organizations and extra SSO connections, and the numbers change, so see its pricing page. The theAuth library is free under MIT, you pay for your own database and compute, and theAuth Cloud is in early access with no published prices. **How hard is it to migrate from Clerk to theAuth?** There is a step-by-step guide that maps Clerk concepts to theAuth, shows the hooks and middleware changes and covers exporting Clerk data. The main manual work is replacing prebuilt Clerk components with your own sign-in screens. ## Sources Last verified: 2026-10-07. Competitor facts come from the public pages below; plans and prices change, so confirm there. - [Clerk pricing](https://clerk.com/pricing) clerk.com/pricing - [Clerk: build an MCP server](https://clerk.com/docs/nextjs/guides/ai/mcp/build-mcp-server) clerk.com/docs/nextjs/guides/ai/mcp/build-mcp-server - [Clerk components overview](https://clerk.com/docs/components/overview) clerk.com/docs/components/overview - [Clerk home page](https://clerk.com/) clerk.com/ - [theAuth README comparison table](https://github.com/glincker/theauth) github.com/glincker/theauth ## Keep reading [All comparisons](https://theauth.dev/compare/) [Agent identity](https://theauth.dev/#agents) [MCP OAuth 2.1](https://theauth.dev/#mcp) [Trust and enterprise](https://theauth.dev/#trust) [Docs comparisons](https://docs.theauth.dev/compare) --- URL: https://theauth.dev/compare/better-auth/ An open source Better Auth alternative for AI agents # theAuth vs Better Auth Both are MIT auth libraries you run yourself. Better Auth has the larger community and plugin set; theAuth builds agent identity into its core and adds Go and Python SDKs. Last verified: 2026-10-07. Open source library against an MIT library. [Read the quickstart](https://docs.theauth.dev/quickstart) [Migration steps](https://theauth.dev/compare/better-auth/#migration) Moving from Better Auth? You can [migrate to theAuth without a rewrite](https://theauth.dev/migrate/) by running both systems and moving users as they sign in. Docs: [Better Auth migration guide](https://docs.theauth.dev/migrate/from-better-auth). [Plan the migration](https://theauth.dev/migrate/) ## Short answer ### Choose Better Auth if - You build a TypeScript app, want a large community and the broad plugin set: organization, SSO, SCIM, passkey and API key. - You want to stay in the ecosystem most TypeScript teams already know, with 30.2k GitHub stars when we checked. - You want its Agent Auth plugin and accept that its docs describe it as under heavy development and not yet stable. ### Choose theAuth if - Agent identity is a core requirement: an owner, delegation depth limits, per-agent budgets and audit built into the library. - Your backend is Go or Python as well as TypeScript, and you want one model across all three. - You want an OAuth 2.1 server for MCP together with the Go RFC set (token exchange, DPoP, PAR, JAR, CIBA) and a resource-server module. theAuth is an open source Better Auth alternative for teams that want agent identity in the same library as human sign-in. It is not the right pick for every team, and the first column says so. ## theAuth vs Better Auth feature comparison Feature comparison of Better Auth and theAuth | Feature | Better Auth | theAuth | | --- | --- | --- | | Source license | Yes, MIT | Yes, MIT | | Self-hostable | Yes, Yes, runs in your app | Yes, Yes, on your own database | | Language | TypeScript | TypeScript core, plus Go and Python SDKs | | OAuth 2.1 authorization server for MCP | Yes, Yes, MCP plugin with PKCE and RFC 9728 metadata | Yes, Yes, built in | | Dynamic client registration | Partial or different, Available but never enabled implicitly; CIMD recommended | Yes, RFC 7591 supported; CIMD in the Go module | | Agent identity | Partial or different, Agent Auth plugin: delegated and autonomous agents, capabilities; docs say not yet stable | Yes, Core feature: owner, bearer token, wildcard permissions | | Approval flows | Yes, Device authorization and CIBA in the Agent Auth plugin | Yes, CIBA-style approval for sensitive tool calls | | Per-agent budgets | Partial or different, Not found in the Better Auth docs we checked | Yes, Budget policies | | Organizations, SSO and SCIM | Yes, Plugins for organization, SSO and SCIM | Yes, Organizations with RBAC, SAML 2.0, OIDC SSO, SCIM 2.0 | Check mark: yes. Dash: partial, different, or not found in the docs we checked. Cross: no. Claims about Better Auth are from its own public docs (see Sources); theAuth rows are from its repositories. 01 ## Better Auth alternative for AI agents: identity and delegation A plugin on one side, the core model on the other. Better Auth Better Auth ships an Agent Auth plugin that implements the Agent Auth Protocol: agents register through discovery documents, request approval by device authorization or CIBA, and run narrowly scoped capabilities with short-lived signed JWTs, in delegated or autonomous mode. An onEvent hook reports lifecycle events for audit. Its docs say the plugin is under heavy development and not yet stable. theAuth theAuth models an agent as an identity with an owner, a cryptographic bearer token (kv_...), wildcard permissions such as mcp:github:*, and delegation chains with configurable depth limits. On top of that sit budget policies per agent, trust scoring, CIBA-style approval for sensitive tool calls, and a full audit trail of every agent action. Read the [agents guide](https://docs.theauth.dev/agents) and [delegation docs](https://docs.theauth.dev/delegation). 02 ## MCP OAuth 2.1 support Both can be the authorization server. Better Auth Better Auth's MCP plugin lets your app act as an OAuth authorization server and protected resource for MCP clients. It serves RFC 9728 metadata, uses PKCE, can enforce DPoP, requires the JWT plugin, and treats dynamic client registration as opt-in because MCP deprecates it in favor of CIMD. theAuth theAuth ships an OAuth 2.1 authorization server for MCP: PKCE S256, RFC 9728 protected resource metadata, RFC 8707 resource indicators, RFC 8414 server metadata and RFC 7591 dynamic client registration. The Go module adds RFC 8693 token exchange, DPoP, PAR, JAR, CIBA, CIMD per the MCP spec of 2025-11-25 and refresh token rotation with family revocation. See the [MCP guide](https://docs.theauth.dev/mcp). 03 ## Self-hosting and data ownership Same ownership model. Better Auth Better Auth is a library that runs inside your application against your own database, so user data stays in your infrastructure. On this point the two are the same. The difference is language reach: Better Auth is built for TypeScript, while theAuth also ships Go and Python SDKs. theAuth theAuth is MIT licensed and runs against your own database: SQLite, PostgreSQL, MySQL or Cloudflare D1 in TypeScript, and Postgres, MySQL or in-memory storage in Go. Users, sessions, tokens and audit records stay in storage you control. A hosted theAuth Cloud is in early access for teams that would rather not run it. 04 ## Licensing and cost model Two MIT libraries. Better Auth Better Auth is MIT licensed and free to use. As with theAuth, you pay for your own database, compute and the time to run it. There is no license difference to weigh, so decide on features and fit. theAuth The library is free under the MIT license. Your costs are the database, the compute and the engineering time to operate it. theAuth Cloud is in early access and has no published prices. 05 ## Edge runtimes Check the matrix for your platform. Better Auth We did not verify Better Auth's edge runtime support from its docs, so we make no claim either way. Check its documentation for Cloudflare Workers, Deno or Bun before you commit. theAuth The TypeScript core runs on Cloudflare Workers, Deno and Bun without code changes, with three runtime dependencies: drizzle-orm, jose and zod. Adapters cover Next.js, SvelteKit, Nuxt, Hono, Express, Fastify, Astro, NestJS, SolidStart and TanStack Start. ## Migrating from Better Auth to theAuth theAuth has a [Better Auth migration guide](https://docs.theauth.dev/migrate/from-better-auth) with a concepts map, code diffs, data migration SQL and a rollback strategy. If you already use Better Auth's agent plugin there is a separate [agent plugin migration guide](https://docs.theauth.dev/migrate/from-better-auth-agent-plugin) covering the delegation chain shape and cascading revocation. [Better Auth migration guide](https://docs.theauth.dev/migrate/from-better-auth) [Agent plugin migration guide](https://docs.theauth.dev/migrate/from-better-auth-agent-plugin) [All migration guides](https://docs.theauth.dev/migrate) ## Better Auth alternative: common questions **Is theAuth a Better Auth alternative for AI agents?** Yes, if agent identity is central to your design. Both are MIT libraries you run yourself. Better Auth offers an Agent Auth plugin that its docs call not yet stable, while theAuth builds agent identity, delegation limits, budgets and audit into the core and adds Go and Python SDKs. **What does Better Auth do better than theAuth?** It has the larger community, with 30.2k GitHub stars when we checked, and a wide plugin set that includes organization, SSO, SCIM, passkey and API key. If you only need human auth in a TypeScript app, it is a strong choice. **Does Better Auth support MCP OAuth 2.1?** Yes. Its MCP plugin lets your app act as an OAuth authorization server for MCP clients, with PKCE, RFC 9728 metadata and optional DPoP. theAuth also includes an MCP OAuth 2.1 authorization server. **Are Better Auth and theAuth both open source?** Yes. Both are MIT licensed and both run in your own infrastructure against your own database. **Can I migrate from Better Auth to theAuth?** Yes. theAuth documents a migration from Better Auth, and a separate one for the Better Auth agent plugin, with concept maps, code diffs and a rollback plan. ## Sources Last verified: 2026-10-07. Competitor facts come from the public pages below; plans and prices change, so confirm there. - [Better Auth introduction](https://better-auth.com/docs/introduction) better-auth.com/docs/introduction - [Better Auth MCP plugin](https://better-auth.com/docs/plugins/mcp) better-auth.com/docs/plugins/mcp - [Better Auth Agent Auth plugin](https://better-auth.com/docs/plugins/agent-auth) better-auth.com/docs/plugins/agent-auth - [Better Auth on GitHub](https://github.com/better-auth/better-auth) github.com/better-auth/better-auth - [theAuth README comparison table](https://github.com/glincker/theauth) github.com/glincker/theauth ## Keep reading [All comparisons](https://theauth.dev/compare/) [Agent identity](https://theauth.dev/#agents) [MCP OAuth 2.1](https://theauth.dev/#mcp) [Trust and enterprise](https://theauth.dev/#trust) [Docs comparisons](https://docs.theauth.dev/compare) --- URL: https://theauth.dev/compare/supabase-auth/ An open source Supabase Auth alternative for AI agents # theAuth vs Supabase Auth Supabase Auth is the identity piece of a Postgres backend platform. theAuth is a standalone auth library whose agents are identities of their own, not stand-ins for existing users. Last verified: 2026-10-07. Backend platform against an MIT library. [Read the quickstart](https://docs.theauth.dev/quickstart) [Migration steps](https://theauth.dev/compare/supabase-auth/#migration) Moving from Supabase Auth? You can [migrate to theAuth without a rewrite](https://theauth.dev/migrate/) by running both systems and moving users as they sign in. Docs: [importing users from a CSV or JSON export](https://docs.theauth.dev/migrate/import-users) and [picking a migration path](https://docs.theauth.dev/migrate/choose-a-path). [Plan the migration](https://theauth.dev/migrate/) ## Short answer ### Choose Supabase Auth if - You already run on Supabase Postgres and want authorization through Row Level Security policies. - You want one platform for database, auth and APIs, hosted or self-hosted with Docker Compose. - Letting an AI agent act as one of your existing users, with RLS applied, is exactly the model you want. ### Choose theAuth if - Auth should be separate from your database choice: SQLite, PostgreSQL, MySQL or Cloudflare D1. - Agents need their own identity, delegation limits, budgets and audit rather than acting as a user. - You deploy to Workers, Deno or Bun, or need Go and Python SDKs. theAuth is an open source Supabase Auth alternative for teams that want agent identity in the same library as human sign-in. It is not the right pick for every team, and the first column says so. ## theAuth vs Supabase Auth feature comparison Feature comparison of Supabase Auth and theAuth | Feature | Supabase Auth | theAuth | | --- | --- | --- | | Source license | Yes, MIT (the supabase/auth server) | Yes, MIT | | Self-hostable | Yes, Yes, self-host Supabase with Docker Compose | Yes, Yes, on your own database | | Scope | Auth is one part of a platform with database and APIs | Auth only; you bring the database | | Database-level authorization | Yes, Row Level Security integration | Partial or different, Own policy engine (RBAC, ReBAC), not tied to Postgres RLS | | OAuth 2.1 authorization server for MCP | Yes, Yes, OAuth 2.1 with PKCE; MCP clients can register | Yes, Yes, built in | | Agent identity | Partial or different, Agents authenticate as your existing users | Yes, Own identity: owner, delegation, budgets, audit | | Enterprise SSO | Yes, SAML 2.0, on paid plans | Yes, SAML 2.0 and OIDC SSO, SCIM 2.0 | | Multi-factor auth | Yes, TOTP and phone | Yes, TOTP 2FA and passkeys | | Billing unit | Monthly active users, with separate SSO and third-party MAU and an advanced MFA add-on | Library has no per-user fee; Cloud in early access | Check mark: yes. Dash: partial, different, or not found in the docs we checked. Cross: no. Claims about Supabase Auth are from its own public docs (see Sources); theAuth rows are from its repositories. 01 ## Supabase Auth alternative for AI agents: identity and delegation Agents as existing users, or as identities. Supabase Auth In Supabase's MCP guide, "AI agents authenticate as your existing users": the user approves access, Supabase issues access and refresh tokens, and the MCP server calls your API with Row Level Security applied. That is a clean fit if you want agents to inherit exactly a user's database rights, and it means an agent has no identity of its own. theAuth theAuth models an agent as an identity with an owner, a cryptographic bearer token (kv_...), wildcard permissions such as mcp:github:*, and delegation chains with configurable depth limits. On top of that sit budget policies per agent, trust scoring, CIBA-style approval for sensitive tool calls, and a full audit trail of every agent action. Read the [agents guide](https://docs.theauth.dev/agents) and [delegation docs](https://docs.theauth.dev/delegation). 02 ## MCP OAuth 2.1 support Supabase includes an OAuth 2.1 server. Supabase Auth Supabase documents OAuth 2.1 with PKCE for MCP clients: clients discover configuration from discovery endpoints and can register themselves, the user approves, and tokens rotate automatically. theAuth theAuth ships an OAuth 2.1 authorization server for MCP: PKCE S256, RFC 9728 protected resource metadata, RFC 8707 resource indicators, RFC 8414 server metadata and RFC 7591 dynamic client registration. The Go module adds RFC 8693 token exchange, DPoP, PAR, JAR, CIBA, CIMD per the MCP spec of 2025-11-25 and refresh token rotation with family revocation. See the [MCP guide](https://docs.theauth.dev/mcp). 03 ## Self-hosting and data ownership Both can run on your own infrastructure. Supabase Auth Supabase can be self-hosted: its docs describe running your own Supabase on your computer, server or cloud, with Docker Compose recommended. The auth server is MIT licensed Go code. Self-hosting brings the whole platform with it, not only auth. theAuth theAuth is MIT licensed and runs against your own database: SQLite, PostgreSQL, MySQL or Cloudflare D1 in TypeScript, and Postgres, MySQL or in-memory storage in Go. Users, sessions, tokens and audit records stay in storage you control. A hosted theAuth Cloud is in early access for teams that would rather not run it. 04 ## Licensing and cost model MAU billing against an MIT library. Supabase Auth The Supabase Auth server is MIT, and hosted Supabase bills Auth by monthly active users with separate lines for third-party MAU, SSO MAU and advanced MFA. Included amounts and rates change, so check the [Supabase pricing page](https://supabase.com/pricing). theAuth The library is free under the MIT license. Your costs are the database, the compute and the engineering time to operate it. theAuth Cloud is in early access and has no published prices. 05 ## Edge runtimes Where each one runs. Supabase Auth Supabase Auth is a server your app calls over HTTP, with client libraries for the browser and server rendering frameworks. Runtime support depends on the client library you use, so check it for your platform. theAuth The TypeScript core runs on Cloudflare Workers, Deno and Bun without code changes, with three runtime dependencies: drizzle-orm, jose and zod. Adapters cover Next.js, SvelteKit, Nuxt, Hono, Express, Fastify, Astro, NestJS, SolidStart and TanStack Start. ## Migrating from Supabase Auth to theAuth There is no Supabase-specific theAuth migration guide yet. The [migration hub](https://docs.theauth.dev/migrate) covers the general approach, and the guides for Auth0, Clerk and Better Auth show how users, sessions and OAuth accounts map across. Plan on rebuilding any authorization you do through Row Level Security in another policy layer. [Migration hub](https://docs.theauth.dev/migrate) ## Supabase Auth alternative: common questions **Is theAuth a Supabase Auth alternative for AI agents?** It can be. theAuth is an open source auth library, independent of any database platform, where each AI agent has its own identity, permissions, delegation limits and audit trail. Supabase Auth is the better fit when you already use Supabase Postgres and Row Level Security. **Can I self-host Supabase Auth?** Yes. Supabase documents self-hosting the platform with Docker Compose, and the auth server is MIT licensed. theAuth is also MIT and self-hostable, on SQLite, PostgreSQL, MySQL or Cloudflare D1. **Does Supabase Auth support MCP OAuth 2.1?** Yes. Supabase documents an OAuth 2.1 implementation with PKCE for MCP clients, where agents authenticate as your existing users. theAuth ships its own MCP OAuth 2.1 authorization server. **When should I stay on Supabase Auth?** Stay if your app is built around Supabase Postgres and you rely on Row Level Security policies for authorization. Moving auth out means rebuilding those rules in another policy layer. ## Sources Last verified: 2026-10-07. Competitor facts come from the public pages below; plans and prices change, so confirm there. - [Supabase Auth overview](https://supabase.com/docs/guides/auth) supabase.com/docs/guides/auth - [Supabase: MCP authentication](https://supabase.com/docs/guides/auth/oauth-server/mcp-authentication) supabase.com/docs/guides/auth/oauth-server/mcp-authentication - [Supabase pricing](https://supabase.com/pricing) supabase.com/pricing - [Supabase self-hosting](https://supabase.com/docs/guides/self-hosting) supabase.com/docs/guides/self-hosting - [supabase/auth on GitHub](https://github.com/supabase/auth) github.com/supabase/auth - [theAuth README comparison table](https://github.com/glincker/theauth) github.com/glincker/theauth ## Keep reading [All comparisons](https://theauth.dev/compare/) [Agent identity](https://theauth.dev/#agents) [MCP OAuth 2.1](https://theauth.dev/#mcp) [Trust and enterprise](https://theauth.dev/#trust) [Docs comparisons](https://docs.theauth.dev/compare) --- URL: https://theauth.dev/compare/firebase-auth/ A self-hosted Firebase Auth alternative for AI agents # theAuth vs Firebase Auth Firebase Authentication is Google's managed sign-in service for app backends. theAuth is an MIT library you run on your own database, with agent identity built in. Last verified: 2026-10-07. Managed service against an MIT library. [Read the quickstart](https://docs.theauth.dev/quickstart) [Migration steps](https://theauth.dev/compare/firebase-auth/#migration) Moving from Firebase Auth? You can [migrate to theAuth without a rewrite](https://theauth.dev/migrate/) by running both systems and moving users as they sign in. Docs: [importing users from a CSV or JSON export](https://docs.theauth.dev/migrate/import-users) and [picking a migration path](https://docs.theauth.dev/migrate/choose-a-path). Firebase password hashes (scrypt) are not supported yet, so those users reset their password. [Plan the migration](https://theauth.dev/migrate/) ## Short answer ### Choose Firebase Auth if - You build mobile apps on iOS, Android, Flutter or Unity and want SDKs for those platforms. - You already use Firebase and want drop-in sign-in screens with FirebaseUI Auth. - You want Google to operate it, with an upgrade to Identity Platform for SAML and OIDC providers, multi-factor auth and multi-tenancy. ### Choose theAuth if - You need to self-host or keep user data in your own database. - Your agents need identity, delegation limits, budgets and audit, and you want an MCP OAuth 2.1 authorization server. - You want MIT-licensed code in your repository with SSO and SCIM included. theAuth is an open source Firebase Auth alternative for teams that want agent identity in the same library as human sign-in. It is not the right pick for every team, and the first column says so. ## theAuth vs Firebase Auth feature comparison Feature comparison of Firebase Auth and theAuth | Feature | Firebase Auth | theAuth | | --- | --- | --- | | Self-hostable | No, No self-hosted option documented; Google-managed service | Yes, Yes, on your own database | | Native mobile SDKs | Yes, iOS, Android, Web, Flutter, C++ and Unity, plus Admin SDKs | Partial or different, Expo and Electron clients; web and server SDKs for TypeScript, Go and Python | | Drop-in sign-in UI | Yes, FirebaseUI Auth | Partial or different, Client SDKs for React, Vue, Svelte, Expo and Electron | | SAML and OIDC providers | Partial or different, Through the Identity Platform upgrade | Yes, SAML 2.0 and OIDC SSO, SCIM 2.0 | | Multi-factor auth | Partial or different, SMS-based, through the Identity Platform upgrade | Yes, TOTP 2FA and passkeys | | Multi-tenancy | Partial or different, Through the Identity Platform upgrade | Yes, Organizations with RBAC and tenant tagging | | OAuth 2.1 authorization server for MCP | Partial or different, Not covered in the Firebase Authentication docs we checked | Yes, Yes, built in | | Agent identity | Partial or different, Not covered in the Firebase Authentication docs we checked | Yes, Owner, delegation, budgets, audit | | Billing unit | No cost up to a monthly active user threshold, then Google Cloud pricing; phone auth billed per SMS | Library has no per-user fee; Cloud in early access | Check mark: yes. Dash: partial, different, or not found in the docs we checked. Cross: no. Claims about Firebase Auth are from its own public docs (see Sources); theAuth rows are from its repositories. 01 ## Firebase Auth alternative for AI agents: identity and delegation Sign-in for users, or identity for agents. Firebase Auth Firebase Authentication is described as a backend service for verifying user identity across platforms and sign-in methods. The overview we checked does not describe an agent identity model, delegation chains or per-agent budgets. If you have an agent requirement, confirm it with Google's documentation. theAuth theAuth models an agent as an identity with an owner, a cryptographic bearer token (kv_...), wildcard permissions such as mcp:github:*, and delegation chains with configurable depth limits. On top of that sit budget policies per agent, trust scoring, CIBA-style approval for sensitive tool calls, and a full audit trail of every agent action. Read the [agents guide](https://docs.theauth.dev/agents) and [delegation docs](https://docs.theauth.dev/delegation). 02 ## MCP OAuth 2.1 support Not part of the Firebase Authentication overview. Firebase Auth We did not find MCP authorization server support in the Firebase Authentication documentation we reviewed, so we make no claim about it. Firebase can still issue identities for your own apps, and you could place an MCP authorization server in front. Verify against Google's docs for your design. theAuth theAuth ships an OAuth 2.1 authorization server for MCP: PKCE S256, RFC 9728 protected resource metadata, RFC 8707 resource indicators, RFC 8414 server metadata and RFC 7591 dynamic client registration. The Go module adds RFC 8693 token exchange, DPoP, PAR, JAR, CIBA, CIMD per the MCP spec of 2025-11-25 and refresh token rotation with family revocation. See the [MCP guide](https://docs.theauth.dev/mcp). 03 ## Self-hosted Firebase Auth alternative: data ownership Google-managed, or your database. Firebase Auth Firebase Authentication is a managed backend service and we found no self-hosted option. The optional upgrade to Identity Platform adds SAML and OIDC providers, multi-factor auth, blocking functions, audit logging, multi-tenancy and an enterprise SLA, still as a managed service. theAuth theAuth is MIT licensed and runs against your own database: SQLite, PostgreSQL, MySQL or Cloudflare D1 in TypeScript, and Postgres, MySQL or in-memory storage in Go. Users, sessions, tokens and audit records stay in storage you control. A hosted theAuth Cloud is in early access for teams that would rather not run it. 04 ## Licensing and cost model Metered usage against an MIT library. Firebase Auth Firebase's pricing page lists no-cost authentication up to a monthly active user threshold, a much smaller free allowance for SAML and OIDC, and phone authentication billed per SMS sent. Thresholds and rates change, so see the [Firebase pricing page](https://firebase.google.com/pricing). theAuth The library is free under the MIT license. Your costs are the database, the compute and the engineering time to operate it. theAuth Cloud is in early access and has no published prices. 05 ## Edge runtimes Where each one runs. Firebase Auth Firebase Authentication offers Web, Node.js Admin and mobile SDKs. We did not verify its behavior on edge runtimes such as Workers or Deno, so check the SDK for your platform. theAuth The TypeScript core runs on Cloudflare Workers, Deno and Bun without code changes, with three runtime dependencies: drizzle-orm, jose and zod. Adapters cover Next.js, SvelteKit, Nuxt, Hono, Express, Fastify, Astro, NestJS, SolidStart and TanStack Start. ## Migrating from Firebase Auth to theAuth There is no Firebase-specific theAuth migration guide yet. Start from the [migration hub](https://docs.theauth.dev/migrate). Plan the cutover so existing sessions keep working while you move users over. [Migration hub](https://docs.theauth.dev/migrate) ## Firebase Auth alternative: common questions **Is theAuth a Firebase Auth alternative for AI agents?** It can be, especially if you want to self-host. theAuth is an MIT library that gives each AI agent its own identity, permissions, delegation limits and audit trail, and includes an MCP OAuth 2.1 authorization server. Firebase Authentication is a managed Google service with strong mobile SDK coverage. **Can I self-host Firebase Authentication?** We found no self-hosted option for Firebase Authentication. It is a managed backend service. theAuth is MIT licensed and runs on your own database. **What does Firebase Authentication do better than theAuth?** Native mobile coverage and drop-in UI. Firebase provides SDKs for iOS, Android, Web, Flutter, C++ and Unity, and FirebaseUI Auth handles sign-in screens. **Does Firebase Authentication cost anything?** Firebase lists no-cost authentication up to a monthly active user threshold, with phone authentication billed per SMS. Thresholds change, so check its pricing page. The theAuth library is free under MIT, and theAuth Cloud is in early access with no published prices. ## Sources Last verified: 2026-10-07. Competitor facts come from the public pages below; plans and prices change, so confirm there. - [Firebase Authentication overview](https://firebase.google.com/docs/auth) firebase.google.com/docs/auth - [Firebase pricing](https://firebase.google.com/pricing) firebase.google.com/pricing - [theAuth README comparison table](https://github.com/glincker/theauth) github.com/glincker/theauth ## Keep reading [All comparisons](https://theauth.dev/compare/) [Agent identity](https://theauth.dev/#agents) [MCP OAuth 2.1](https://theauth.dev/#mcp) [Trust and enterprise](https://theauth.dev/#trust) [Docs comparisons](https://docs.theauth.dev/compare) --- URL: https://theauth.dev/compare/keycloak/ A lighter open source Keycloak alternative for AI agents # theAuth vs Keycloak Keycloak is an Apache 2.0 identity server you deploy and operate for SSO across many apps. theAuth is a library embedded in your app, built around AI agent identity. Last verified: 2026-10-07. Identity server against an MIT library. [Read the quickstart](https://docs.theauth.dev/quickstart) [Migration steps](https://theauth.dev/compare/keycloak/#migration) Moving from Keycloak? You can [migrate to theAuth without a rewrite](https://theauth.dev/migrate/) by running both systems and moving users as they sign in. Docs: [importing Keycloak users](https://docs.theauth.dev/migrate/import-users) and [picking a migration path](https://docs.theauth.dev/migrate/choose-a-path). [Plan the migration](https://theauth.dev/migrate/) ## Short answer ### Choose Keycloak if - You want a central identity provider that many applications and teams sign in through. - You need user federation to LDAP or Active Directory and identity brokering to existing providers. - You have a team comfortable running a Java service and want a CNCF incubation project behind it. ### Choose theAuth if - You want auth inside your application process, not a separate Java server to deploy and patch. - Agents need their own identity with delegation limits, budgets and a per-agent audit trail. - You target Workers, Deno or Bun, or you want Go and Python SDKs. theAuth is an open source Keycloak alternative for teams that want agent identity in the same library as human sign-in. It is not the right pick for every team, and the first column says so. ## theAuth vs Keycloak feature comparison Feature comparison of Keycloak and theAuth | Feature | Keycloak | theAuth | | --- | --- | --- | | Source license | Yes, Apache 2.0 | Yes, MIT | | Deployment | Standalone server (Java, Quarkus) | Library in your app; Go module via go get | | Self-hostable | Yes, Yes, you run it | Yes, Yes, on your own database | | SAML 2.0 and OIDC | Yes, Yes, plus OAuth 2.0 | Yes, SAML 2.0 and OIDC SSO, SCIM 2.0 | | LDAP and Active Directory federation | Yes, User federation to LDAP or Active Directory | Partial or different, Not in theAuth's documented feature list | | Identity brokering | Yes, Brokers to OIDC or SAML identity providers | Partial or different, 17 OAuth providers plus a generic OIDC factory | | OAuth 2.1 authorization server for MCP | Yes, Used as the example server in the MCP authorization tutorial | Yes, Yes, built in | | Agent identity | Partial or different, Not found in the docs we checked; client service accounts exist | Yes, Owner, delegation, budgets, audit | | Fine-grained authorization | Yes, Role-based and policy-based | Yes, RBAC, ReBAC and a policy engine | Check mark: yes. Dash: partial, different, or not found in the docs we checked. Cross: no. Claims about Keycloak are from its own public docs (see Sources); theAuth rows are from its repositories. 01 ## Keycloak alternative for AI agents: identity and delegation A general IdP, or an agent-aware library. Keycloak Keycloak is a general identity and access management server. Its admin guide documents OIDC clients, service accounts and client policies. We did not find an agent identity model with delegation chains or per-agent budgets in the docs we checked, so you would build that on top. theAuth theAuth models an agent as an identity with an owner, a cryptographic bearer token (kv_...), wildcard permissions such as mcp:github:*, and delegation chains with configurable depth limits. On top of that sit budget policies per agent, trust scoring, CIBA-style approval for sensitive tool calls, and a full audit trail of every agent action. Read the [agents guide](https://docs.theauth.dev/agents) and [delegation docs](https://docs.theauth.dev/delegation). 02 ## MCP OAuth 2.1 support Keycloak works as an MCP authorization server. Keycloak The official MCP authorization tutorial uses Keycloak as its example authorization server. It says the default configuration already supports capabilities MCP needs, including dynamic client registration, though default policies restrict anonymous registration, so you set trusted hosts. The Keycloak admin guide also has an OAuth 2.1 compliance section. theAuth theAuth ships an OAuth 2.1 authorization server for MCP: PKCE S256, RFC 9728 protected resource metadata, RFC 8707 resource indicators, RFC 8414 server metadata and RFC 7591 dynamic client registration. The Go module adds RFC 8693 token exchange, DPoP, PAR, JAR, CIBA, CIMD per the MCP spec of 2025-11-25 and refresh token rotation with family revocation. See the [MCP guide](https://docs.theauth.dev/mcp). 03 ## Self-hosted Keycloak alternative: data ownership A server you run, or a library you embed. Keycloak Keycloak is open source and you operate it: a standalone Java server on Quarkus, clustered for availability, with its own admin and account consoles. That gives you ownership and a lot to run. theAuth stores data in your application's database and needs no separate identity server. theAuth theAuth is MIT licensed and runs against your own database: SQLite, PostgreSQL, MySQL or Cloudflare D1 in TypeScript, and Postgres, MySQL or in-memory storage in Go. Users, sessions, tokens and audit records stay in storage you control. A hosted theAuth Cloud is in early access for teams that would rather not run it. 04 ## Licensing and cost model Apache 2.0 and MIT, both free to run. Keycloak Keycloak is Apache 2.0 licensed and free to use, with no vendor pricing page to read. The cost is operating the server: hosting, upgrades, patching and the people who know Keycloak. theAuth's cost is similar in kind but smaller in footprint because it runs in your app. theAuth The library is free under the MIT license. Your costs are the database, the compute and the engineering time to operate it. theAuth Cloud is in early access and has no published prices. 05 ## Edge runtimes Where each one runs. Keycloak Keycloak is a Java server, so edge runtimes are not where it runs. Your edge app would call it over OIDC and verify its tokens. theAuth's TypeScript core can run on the edge itself. theAuth The TypeScript core runs on Cloudflare Workers, Deno and Bun without code changes, with three runtime dependencies: drizzle-orm, jose and zod. Adapters cover Next.js, SvelteKit, Nuxt, Hono, Express, Fastify, Astro, NestJS, SolidStart and TanStack Start. ## Migrating from Keycloak to theAuth There is no Keycloak-specific theAuth migration guide yet. Start from the [migration hub](https://docs.theauth.dev/migrate). If you use LDAP or Active Directory federation, plan around it, because theAuth does not list that capability. [Migration hub](https://docs.theauth.dev/migrate) ## Keycloak alternative: common questions **Is theAuth a Keycloak alternative for AI agents?** It can be for application-level auth. theAuth is an MIT library embedded in your app, with agent identity, delegation limits, budgets, audit and an MCP OAuth 2.1 authorization server. Keycloak remains stronger as a central identity provider with LDAP and Active Directory federation. **Is Keycloak open source?** Yes. Keycloak is licensed under Apache 2.0 and is a CNCF incubation project. theAuth is MIT licensed. **Can Keycloak secure an MCP server?** Yes. The official MCP authorization tutorial uses Keycloak as the example authorization server and notes its default configuration supports dynamic client registration, with policies that restrict anonymous registration. **Do I need a separate server for theAuth?** No. In TypeScript, theAuth runs inside your application with a database you choose, and in Go it is a single go get. Keycloak is a standalone server you deploy and operate. **When should I choose Keycloak over theAuth?** Choose Keycloak when you need one identity provider for many applications, LDAP or Active Directory federation, or identity brokering, and you have a team to operate a Java service. ## Sources Last verified: 2026-10-07. Competitor facts come from the public pages below; plans and prices change, so confirm there. - [Keycloak home page](https://www.keycloak.org/) www.keycloak.org/ - [Keycloak on GitHub](https://github.com/keycloak/keycloak) github.com/keycloak/keycloak - [Keycloak server administration guide](https://www.keycloak.org/docs/latest/server_admin/index.html) www.keycloak.org/docs/latest/server_admin/index.html - [MCP authorization tutorial](https://modelcontextprotocol.io/docs/tutorials/security/authorization) modelcontextprotocol.io/docs/tutorials/security/authorization - [theAuth README comparison table](https://github.com/glincker/theauth) github.com/glincker/theauth ## Keep reading [All comparisons](https://theauth.dev/compare/) [Agent identity](https://theauth.dev/#agents) [MCP OAuth 2.1](https://theauth.dev/#mcp) [Trust and enterprise](https://theauth.dev/#trust) [Docs comparisons](https://docs.theauth.dev/compare) --- URL: https://theauth.dev/use-cases/ Use cases # Pick the problem you have. Each page below starts from a concrete job, explains the path through theAuth, and ends in code checked against the package source. Start with the one closest to what you are building. ## Guides 1. [Add auth to an MCP serverYour MCP server needs OAuth 2.1 with discovery, so clients you have never met can register and log in.](https://theauth.dev/use-cases/mcp-servers/) 2. [Identity and permissions for AI agentsAgents act for people. You need to know which agent did what, who owns it, and how to stop it.](https://theauth.dev/use-cases/ai-agents/) 3. [Auth for B2B SaaS with organizationsA company customer wants SSO, SCIM and a clear answer on tenant data before it signs.](https://theauth.dev/use-cases/saas/) 4. [Auth for AI startupsYou want auth working today, without a per-user bill and without a rewrite when enterprise asks.](https://theauth.dev/use-cases/ai-startups/) 5. [Auth for multi-agent systemsAn orchestrator spawns sub-agents. Each should hold less than its parent and be stoppable on its own.](https://theauth.dev/use-cases/multi-agent/) 6. [Auth for large organizationsA security review wants to know where data lives, how people and agents are removed, and what the audit trail holds.](https://theauth.dev/use-cases/enterprise/) How these are written ## Source first, docs second. The snippets are checked against the package source and types, not copied from marketing pages. Where the published docs and the source disagree, the guides follow the source and say so. Something here does not match what you see in your version? Open a thread in [GitHub Discussions](https://github.com/glincker/theauth/discussions). For the full reference, the [docs](https://docs.theauth.dev) cover every module. --- URL: https://theauth.dev/use-cases/ai-agents/ Use case # Identity and permissions for AI agents An agent that shares its owner's API key cannot be limited, traced, or switched off on its own. theAuth gives each agent its own token, its own permissions, a named human owner, and a record of every decision. [Read the agents docs](https://docs.theauth.dev/agents) [Jump to the steps](https://theauth.dev/use-cases/ai-agents/#step-1) The problem ## Agents act for people, and your logs only know the person. Once an orchestrator starts sub-agents, calls tools over MCP, and runs without anyone watching, the usual session model stops answering the questions that matter. Which agent made that call? Who is responsible for it? Could it have done less? Can I stop just that one? Reusing the owner's credentials answers none of those. You need identity at the agent level, with the human owner attached, and a policy check on every action rather than once at login. Questions you must be able to answer - **Who is it?**A distinct identity per agent, not the owner's session. - **Who is accountable?**A human owner on every agent, queryable in the audit log. - **What may it do?**Permissions as resource and action pairs, checked per call. - **Who did it hand work to?**Delegations that can only narrow access, expire, and stop at a depth limit. - **What needs a person?**A pause before sensitive actions, with a human decision on record. The theAuth path ## Five controls on one agent record. A human owner creates an agent, and the agent can hand a subset of its permissions to a sub-agent. Each hop adds one to the delegation depth, which is capped by maxDepth (default 3), and revoking a link also revokes every link created downstream of it. Step by step ## One orchestrator, one scoped sub-agent. Excerpts that build on each other. `auth` is the instance from `createTheAuth`. ### Create the agent with a human owner `ownerId` is required. It is what an auditor follows from an action back to a person. The sub-agent starts with no permissions of its own. It will only get what the orchestrator hands over. agents.ts ```ts const orchestrator = await auth.agent.create({ ownerId: "user-123", name: "planner", type: "autonomous", permissions: [ { resource: "mcp:github:*", actions: ["read", "write", "comment"] }, ], }); const reviewer = await auth.agent.create({ ownerId: "user-123", name: "code-reviewer", type: "delegated", permissions: [], }); ``` ### Check every action Call `authorize` before the tool runs, not after. The decision is logged either way, and `auditId` links your own logs to it. authorize.ts ```ts const result = await auth.authorize(orchestrator.id, { action: "read", resource: "mcp:github:repos", }); // { allowed: true, auditId: "aud_..." } ``` ### Delegate narrowly, with a depth limit The delegated permissions must be a subset of what the parent holds: narrower resources and fewer actions pass, wider ones fail with `INSUFFICIENT_PERMISSIONS`. With `maxDepth: 1` the reviewer cannot pass its access to anyone else. Revoking the chain later removes it and everything downstream. delegate.ts ```ts const chain = await auth.delegate({ fromAgent: orchestrator.id, toAgent: reviewer.id, permissions: [{ resource: "mcp:github:pulls", actions: ["read", "comment"] }], expiresAt: new Date(Date.now() + 30 * 60_000), // 30 minutes maxDepth: 1, }); // Later: cascades to every chain created downstream. await auth.delegation.revoke(chain.id); ``` ### Put a person in front of sensitive actions Mark the permission, catch the denial, and create an approval request. theAuth stores the request and fires your `webhookUrl` or `onApprovalNeeded` handler. Delivering the notification is your application's job. Requests expire after a TTL, five minutes by default. The agent does not block while it waits. approval.ts ```ts const filer = await auth.agent.create({ ownerId: "user-123", name: "file-manager", type: "autonomous", permissions: [ { resource: "file:prod-data/*", actions: ["read"] }, { resource: "file:prod-data/*", actions: ["delete"], constraints: { requireApproval: true }, }, ], }); const attempt = await auth.authorize(filer.id, { action: "delete", resource: "file:prod-data/dataset.csv", }); if (!attempt.allowed && attempt.reason?.includes("requires human approval")) { const req = await auth.approval.request({ agentId: filer.id, userId: filer.ownerId, action: "delete", resource: "file:prod-data/dataset.csv", }); // later, from your UI handler: await auth.approval.approve(req.id, "reviewer@example.com"); } ``` ### Cap spend A budget policy sets limits and an action when they are hit: `warn`, `throttle`, `block` or `revoke`. Policies live on `auth.policies`. Evaluate a policy with `checkBudget` before you spend. We could not confirm that `authorize()` calls it for you, so call it yourself at the point where your agent makes an LLM request. budget.ts ```ts await auth.policies.create({ agentId: orchestrator.id, limits: { maxTokensCostPerDay: 1000, maxCallsPerDay: 500 }, action: "block", }); const budget = await auth.policies.checkBudget(orchestrator.id); if (!budget.allowed) throw new Error(budget.reason); ``` ### Answer the audit question Filter by agent, owner, outcome and time. Denied calls are the interesting ones. Exports come out as JSON or CSV. audit.ts ```ts const denied = await auth.audit.query({ userId: "user-123", result: "denied", since: new Date("2026-10-01"), limit: 100, }); const csv = await auth.audit.export({ format: "csv" }); ``` Checked against the package source for @glinr/theauth 0.5.0 on 2026-10-06. Compliance mappings of the audit log to the EU AI Act, NIST, SOC 2 and ISO 42001 are reports, not certifications; see the [compliance docs](https://docs.theauth.dev/compliance) for what they cover. Pitfalls ## Mistakes that leave agents over-trusted. - **Giving the orchestrator's token to sub-agents.**That erases the boundary. Create each sub-agent and delegate a subset instead. - **Delegating with the default depth.**`maxDepth` defaults to 3. If a sub-agent has no reason to delegate further, set `maxDepth: 1`. - **Long-lived delegations.**Delegations take an `expiresAt`. Give them the length of the task, not of the project. - **Revocation does not stop work in flight.**It takes effect on the next `authorize()` call. Authorize before each action rather than once per session. - **Expecting approval notifications to arrive by themselves.**theAuth persists the request and calls your webhook or handler. Sending the Slack message or email is yours to build. Poll `listPending()` as a fallback if a webhook fails. - **Assuming budgets are enforced inside authorize.**Call `auth.policies.checkBudget()` yourself before LLM calls until you have confirmed otherwise in your version. - **Pending approvals that never expire.**Expired requests stay marked pending until `auth.approval.cleanup()` runs. Schedule it. ## Keep reading - [Add auth to an MCP server](https://theauth.dev/use-cases/mcp-servers/) - [Auth for AI startups](https://theauth.dev/use-cases/ai-startups/) - [Agent identity on the homepage](https://theauth.dev/#agents) - [Delegation chains](https://docs.theauth.dev/delegation) - [Approval flows](https://docs.theauth.dev/approval) - [Audit trail](https://docs.theauth.dev/audit) --- URL: https://theauth.dev/use-cases/multi-agent/ Use case # Auth for orchestrators that spawn sub-agents. When one agent hands work to another, the second one should hold less than the first, for less time, and be stoppable on its own. This page shows how delegation chains do that in theAuth, with code that was run before it was published. [Delegation docs](https://docs.theauth.dev/delegation) [Jump to the code](https://theauth.dev/use-cases/multi-agent/#uc-steps) The problem ## One shared key per swarm does not survive an incident. A planner splits a task. A reviewer reads pull requests. A fetcher pulls diffs. If all three use the same API key, you cannot tell them apart in logs, you cannot cut one off, and the fetcher can do whatever the planner can. The fix is the same one operating systems use for processes: each worker gets its own identity, receives a subset of its parent's rights, and loses them when the parent's grant is withdrawn. What a multi-agent setup needs - **Separate identities.**Each agent has an owner and its own token. - **Narrowing grants.**A child can only receive what its parent holds. - **A depth cap.**No unbounded chains of agents creating agents. - **Cascading revocation.**Cut a link and everything downstream goes with it. - **Attribution.**An audit row per decision that names the agent. The theAuth path ## Identities, narrowing delegation, then audit. A human owner creates an agent, and the agent can hand a subset of its permissions to a sub-agent. Each hop adds one to the delegation depth, which is capped by maxDepth (default 3), and revoking a link also revokes every link created downstream of it. In code ## A planner delegates one read-only slice to a reviewer. Run on @glinr/theauth 0.6.0 on 2026-10-08. It prints read: true, write: false, then read after revoke: false. The reviewer is created with no permissions of its own, so everything it can do comes from the chain. multi-agent.ts ```ts import { createTheAuth, users } from "@glinr/theauth"; const theauth = await createTheAuth({ database: { provider: "sqlite", url: ":memory:" }, agents: { enabled: true }, }); // Agents need an owner row. In a real app the owner is a signed-in user. await theauth.db.insert(users).values({ id: "user-1", email: "ada@example.com", createdAt: new Date(), updatedAt: new Date() }); const orchestrator = await theauth.agent.create({ ownerId: "user-1", name: "planner", type: "autonomous", permissions: [{ resource: "mcp:github:*", actions: ["read", "write"] }], }); const reviewer = await theauth.agent.create({ ownerId: "user-1", name: "reviewer", type: "delegated", permissions: [], }); // The planner hands the reviewer a narrower slice, for one hour, one hop deep. const chain = await theauth.delegate({ fromAgent: orchestrator.id, toAgent: reviewer.id, permissions: [{ resource: "mcp:github:pulls", actions: ["read"] }], expiresAt: new Date(Date.now() + 3_600_000), maxDepth: 1, }); const read = { action: "read", resource: "mcp:github:pulls" }; const write = { action: "write", resource: "mcp:github:pulls" }; console.log("read:", (await theauth.authorize(reviewer.id, read)).allowed); console.log("write:", (await theauth.authorize(reviewer.id, write)).allowed); await theauth.delegation.revoke(chain.id); console.log("read after revoke:", (await theauth.authorize(reviewer.id, read)).allowed); ``` Install with pnpm add @glinr/theauth sql.js and run with pnpm tsx multi-agent.ts. Setup details are on the [get started page](https://theauth.dev/get-started/). Pitfalls ## Limits worth knowing before you ship. - **Budgets are not enforced by authorize.**Call `policies.checkBudget()` before an LLM call and `recordUsage()` after it. Nothing is capped unless your code does this. - **Re-delegation uses the parent's own permissions.**An agent that holds only delegated permissions cannot pass them on. Give an intermediate agent its own copy if it must re-delegate. - **maxDepth is per call.**It is checked on each `delegate()` call and not stored as a ceiling for later hops. Pass a small value on every call. - **Revocation is eventual per call.**It takes effect on the next `authorize()`. Operations already in flight keep running. - **Approval needs your UI.**theAuth stores approval requests but ships no screen and does not deliver the notification. ## Keep reading - [Agent identity in depth](https://theauth.dev/agent-identity/) - [Identity and permissions for AI agents](https://theauth.dev/use-cases/ai-agents/) - [Add auth to an MCP server](https://theauth.dev/use-cases/mcp-servers/) - [Guide: secure an MCP server](https://theauth.dev/guides/mcp-server-typescript/) - [theAuth vs Descope](https://theauth.dev/compare/descope/) --- URL: https://theauth.dev/use-cases/mcp-servers/ Use case # Add auth to an MCP server MCP clients expect to discover your authorization server on their own, register, and run an OAuth 2.1 code flow with PKCE. theAuth ships that server and the token checks. Your tool server only decides which scope each tool needs. [Read the MCP docs](https://docs.theauth.dev/mcp) [Jump to the steps](https://theauth.dev/use-cases/mcp-servers/#step-1) The problem ## A client you have never met has to log in without help. A public MCP server cannot hand out API keys by email. The client that connects might be an editor, a desktop assistant, or an agent running somewhere you do not control, and no human is available to paste a secret into a config file. So the server has to behave like a proper OAuth resource. When a request arrives without a token, the 401 response must say where to look next. The client reads the resource metadata, finds the authorization server, registers itself, sends the user through a code flow, and comes back with a token that only works on this server. What the client expects - **Discovery.**A `WWW-Authenticate` header on the 401 that points at protected resource metadata (RFC 9728), then authorization server metadata (RFC 8414). - **Registration.**Dynamic client registration (RFC 7591), because you cannot pre-register every client. - **PKCE with S256.**OAuth 2.1 drops the `plain` challenge method. A public client has no secret, so the verifier is the proof. - **Audience binding.**Resource indicators (RFC 8707), so a token minted for one server fails on another. The theAuth path ## An authorization server and a validator, both in your process. You keep your own users and consent screen. theAuth supplies the protocol parts. An MCP client starts with only the MCP server URL, discovers the authorization server from metadata, registers, and authorizes with PKCE S256. theAuth issues the token, and the MCP server validates its signature, audience, scope and expiry before it runs the tool. Step by step ## From an empty Hono app to a protected tool. Excerpts, in order. Replace the in-memory stores and the stub user lookup before you deploy. ### Install the packages The core, the Hono adapter, and a Node server for Hono. Hono runs elsewhere too, since it uses web-standard Request and Response. terminal ```sh npm install @glinr/theauth @glinr/theauth-hono hono @hono/node-server ``` ### Create the auth instance and the MCP module `issuer` is the public origin of your server. `baseUrl` is where the adapter will serve the MCP routes, here under `/api`. `signingSecret` must be at least 32 characters, or `createMcpModule` throws. Pre-registered clients and dynamic registration both go through `storeClient`. The stores below are in memory so the excerpt stays short. src/mcp.ts ```ts import { createTheAuth } from "@glinr/theauth"; import { createMcpModule } from "@glinr/theauth/mcp"; import type { McpAccessToken, McpAuthorizationCode, McpClient } from "@glinr/theauth/mcp"; const BASE_URL = process.env.BASE_URL ?? "http://localhost:3001"; export const auth = await createTheAuth({ database: { provider: "sqlite", url: "file:./auth.db" }, }); const clients = new Map(); const codes = new Map(); const tokens = new Map(); const byRefresh = new Map(); export const mcp = createMcpModule({ config: { enabled: true, issuer: BASE_URL, baseUrl: BASE_URL + "/api", signingSecret: process.env.MCP_SIGNING_SECRET!, // 32+ characters scopes: ["mcp:read", "mcp:execute"], accessTokenTtl: 3600, }, storeClient: async (c) => { clients.set(c.clientId, c); }, findClient: async (id) => clients.get(id) ?? null, storeAuthorizationCode: async (c) => { codes.set(c.code, c); }, consumeAuthorizationCode: async (code) => { const found = codes.get(code) ?? null; codes.delete(code); return found; }, storeToken: async (t) => { tokens.set(t.accessToken, t); if (t.refreshToken) byRefresh.set(t.refreshToken, t.accessToken); }, findTokenByRefreshToken: async (r) => { const at = byRefresh.get(r); return at ? tokens.get(at) ?? null : null; }, revokeToken: async (at) => { tokens.delete(at); }, // Return the signed-in user's id from your own session, or null. resolveUserId: async (request) => getUserIdFromSession(request), }); ``` ### Mount the routes and publish discovery at the root The adapter serves `/mcp/register`, `/mcp/authorize` and `/mcp/token`, and the two `.well-known` documents, relative to where you mount it. MCP clients look for the well-known documents at the origin root, so serve them there too. Check the result with curl. The response is the resource metadata, abridged here. src/server.ts ```ts import { serve } from "@hono/node-server"; import { Hono } from "hono"; import { theAuthHono } from "@glinr/theauth-hono"; import { auth, mcp } from "./mcp"; const app = new Hono(); // /api/mcp/register, /api/mcp/authorize, /api/mcp/token app.route("/api", theAuthHono(auth, { mcp })); // Same documents at the origin root, where clients look first. app.get("/.well-known/oauth-protected-resource", (c) => c.json(mcp.getProtectedResourceMetadata())); app.get("/.well-known/oauth-authorization-server", (c) => c.json(mcp.getMetadata())); serve({ fetch: app.fetch, port: 3001 }); ``` ### Check discovery Metadata documents are plain JSON. If a client cannot connect, this is the first thing to look at. terminal ```ts curl http://localhost:3001/.well-known/oauth-protected-resource ``` ### Require a scope per tool Map each tool to the narrowest scope that covers it, and validate before you run it. A missing token gets a 401 with the metadata pointer, so the client can start the flow. A valid token without the scope gets a 403. `validateToken` also rejects tokens whose audience does not match, so a token minted for another server fails even with a valid signature. src/tools.ts ```ts const TOOL_SCOPES: Record = { list_repos: "mcp:read", create_comment: "mcp:execute", }; app.post("/tools/call/:name", async (c) => { const scope = TOOL_SCOPES[c.req.param("name")]; if (!scope) return c.json({ error: "Unknown tool" }, 404); const token = c.req.header("authorization")?.replace(/^Bearer /i, ""); if (!token) { return c.json({ error: "Bearer token required" }, 401, { "WWW-Authenticate": 'Bearer resource_metadata="' + BASE_URL + '/.well-known/oauth-protected-resource"', }); } const result = await mcp.validateToken(token, [scope]); if (!result.success) { const status = result.error.code === "INSUFFICIENT_SCOPE" ? 403 : 401; return c.json({ error: result.error.message }, status); } // result.data.userId, result.data.clientId, result.data.scopes return c.json(await runTool(c.req.param("name"), await c.req.json())); }); ``` ### What the client does Your users never write this, an MCP client does. It is here so you can test the flow by hand. The authorization request carries the PKCE challenge, the scope, and the `resource` parameter. The token request carries the verifier. Register the client first with a POST to `/api/mcp/register`. Both endpoints enforce that `redirect_uri` matches what was registered. client.ts ```ts const verifier = base64url(crypto.getRandomValues(new Uint8Array(32))); const challenge = base64url( new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier))), ); const url = new URL("https://mcp.example.com/api/mcp/authorize"); url.searchParams.set("response_type", "code"); url.searchParams.set("client_id", clientId); url.searchParams.set("redirect_uri", redirectUri); url.searchParams.set("code_challenge", challenge); url.searchParams.set("code_challenge_method", "S256"); url.searchParams.set("scope", "mcp:read mcp:execute"); url.searchParams.set("resource", "https://mcp.example.com"); // After the redirect back with ?code=... const res = await fetch("https://mcp.example.com/api/mcp/token", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ grant_type: "authorization_code", code, code_verifier: verifier, client_id: clientId, redirect_uri: redirectUri, }), }); ``` The snippets are excerpts checked against the package source and types for @glinr/theauth 0.5.0 and @glinr/theauth-hono 3.1.0 on 2026-10-06. They are not a complete app: `getUserIdFromSession`, `runTool` and `base64url` are yours to write. The [MCP docs page](https://docs.theauth.dev/mcp) is the reference for the full option list. Pitfalls ## Where MCP auth setups usually go wrong. - **Metadata served under a prefix only.**The adapter registers `.well-known` routes relative to its mount point. Mounted at `/api`, they live at `/api/.well-known/...`. Clients look at the origin root, so add the root routes as in step 3, or mount the adapter at the root. - **The adapter mounts more than OAuth.**`theAuthHono` also registers management routes such as agents, delegations and audit. Check what is exposed on a public origin and put your own access control in front of what should not be public. - **Using the stub stores in production.**In-memory maps lose clients and refresh tokens on restart and do not work across instances. Back the callbacks with your database. - **A short or missing signing secret.**`createMcpModule` throws unless `signingSecret` is 32 characters or longer. Keep it out of source control. - **One broad scope for every tool.**Validate a specific scope per tool, as in step 5. A single `mcp:execute` for everything makes a stolen token as powerful as your riskiest tool. - **Plain PKCE in older clients.**The authorize endpoint accepts `S256` only and returns an error otherwise. A client that sends `plain` must be fixed, not accommodated. ## Keep reading - [Identity and permissions for AI agents](https://theauth.dev/use-cases/ai-agents/) - [How the MCP server works on the homepage](https://theauth.dev/#mcp) - [MCP OAuth 2.1 reference](https://docs.theauth.dev/mcp) - [Standards alignment](https://docs.theauth.dev/standards) - [Hono and other adapters](https://docs.theauth.dev/adapters) --- URL: https://theauth.dev/use-cases/saas/ Use case # Auth for B2B SaaS with organizations B2B buyers ask the same questions in the same order: can our people sign in with our identity provider, can IT provision and remove them, and can one customer ever see another's data. This page maps those questions to theAuth. [Read the organizations docs](https://docs.theauth.dev/auth/organizations) [Jump to the steps](https://theauth.dev/use-cases/saas/#step-1) The problem ## Individual accounts stop working at the first company deal. A user table with a role column covers a consumer app. A company customer wants members grouped under an organization, roles that differ per organization, sign-in through its own identity provider, and automatic deprovisioning when someone leaves. Building that by hand takes longer than the first sale justifies, and the security review comes right after. Using a library you can read and run yourself keeps the data in your database and the review in your hands. What the procurement checklist asks for - **Organizations and roles.**Members, invitations, and permissions scoped to one organization. - **Single sign-on.**SAML 2.0 or OIDC against the customer's identity provider. - **Provisioning.**SCIM 2.0 so IT creates and removes users from their directory. - **Isolation.**A clear boundary between tenants, including for agents and automation, which your app has to enforce. - **Data location.**The option to run it in your own infrastructure. The theAuth path ## Four building blocks, one library. SSO connections link an organization to an identity provider over SAML 2.0 or OIDC, and a SCIM 2.0 endpoint takes users and groups from the customer's directory. Agents can carry a tenantId so you can list them by tenant; enforcing tenant boundaries stays in your own resource checks. Step by step ## Organizations, SCIM and tenants in one setup. Excerpts, checked against the source. SSO connection details depend on your identity provider, so they live in the docs. ### Turn on organizations The `org` config creates `auth.org`. It is `null` when you leave the config out. Limits on members, organizations per user and invitation rate have defaults you can change. auth.ts ```ts import { createTheAuth } from "@glinr/theauth"; export const auth = await createTheAuth({ database: { provider: "postgres", url: process.env.DATABASE_URL }, org: { maxMembers: 100, maxOrgsPerUser: 5, allowCustomRoles: true, }, }); ``` ### Create an organization, invite, and check permissions The creator becomes `owner`. Check a permission at the point where the action happens, not just in the UI. orgs.ts ```ts const org = await auth.org.create({ name: "Acme Corp", slug: "acme-corp", ownerId: "user_abc", }); await auth.org.invite({ orgId: org.id, email: "alice@acme.example", role: "admin", invitedBy: "user_abc", }); const allowed = await auth.org.hasPermission(org.id, "user_xyz", "agents:create"); await auth.org.createRole(org.id, { name: "billing", permissions: ["invoices:read", "invoices:pay"], }); ``` ### Accept SCIM provisioning Add the plugin and give your customer's IT team the SCIM base URL and token. Use a long random secret. Provisioning and deprovisioning behavior is configurable: `autoCreateUsers` and `autoDeactivateUsers` both default to true. auth.ts ```ts import { scim } from "@glinr/theauth/auth"; export const auth = await createTheAuth({ database: { provider: "postgres", url: process.env.DATABASE_URL }, plugins: [scim({ bearerToken: process.env.SCIM_TOKEN! })], }); ``` ### Isolate tenants Slugs must be lowercase letters, numbers and hyphens, and unique. Pass `tenantId` when you create an agent and its authorization checks stay inside that tenant. tenants.ts ```ts const tenant = await auth.tenant.create({ name: "Acme Corp", slug: "acme", settings: { maxAgents: 200, auditRetentionDays: 365 }, }); const bot = await auth.agent.create({ ownerId: "user-456", name: "acme-data-bot", type: "autonomous", tenantId: tenant.id, permissions: [{ resource: "reports:*", actions: ["read", "export"] }], }); ``` Checked against the package source for @glinr/theauth 0.5.0 on 2026-10-06. Organizations, tenants and SSO are separate modules in the library today, and the docs describe them side by side. Decide early how your own customer model maps onto organizations and tenants, since theAuth does not choose that for you. See [multi-tenant](https://docs.theauth.dev/multi-tenant) and [GDPR](https://docs.theauth.dev/gdpr) in the docs for export, deletion and anonymization. Pitfalls ## Where B2B auth projects slip. - **Treating organization and tenant as one thing.**An organization groups members and roles. A tenant is a boundary for agents, settings and budget policies. Pick which one your customer maps to and be consistent. - **Checking roles only in the interface.**Hide the button and also call `hasPermission` on the server route. - **Skipping domain routing for SSO.**SSO connections route by email domain. Verify that a customer owns the domain before you attach it to a connection. - **A shared SCIM token.**Use a separate long random token per customer connection where you can, and rotate it when the IT contact changes. - **Forgetting offboarding.**Test the deprovisioning path in staging with the customer's identity provider before launch. That is the flow they will test first. - **Assuming defaults fit.**The default caps are 100 members per organization and 5 organizations per user. Raise them deliberately. ## Keep reading - [Auth for AI startups](https://theauth.dev/use-cases/ai-startups/) - [Identity and permissions for AI agents](https://theauth.dev/use-cases/ai-agents/) - [Human authentication on the homepage](https://theauth.dev/#human) - [Organizations](https://docs.theauth.dev/auth/organizations) - [SSO](https://docs.theauth.dev/auth/sso) - [SCIM](https://docs.theauth.dev/auth/scim) - [Multi-tenant docs](https://docs.theauth.dev/multi-tenant) --- URL: https://theauth.dev/use-cases/enterprise/ Use case # Auth for large organizations that review everything. A security team will ask where the data lives, who can read the code, how people and agents are provisioned and removed, and what the audit trail contains. This page answers those questions for theAuth, including the ones where the answer is "that part is yours". [Enterprise datasheet](https://theauth.dev/enterprise/) [Review questions](https://theauth.dev/use-cases/enterprise/#uc-answers) The problem ## Procurement and security review decide the timeline. Large customers rarely object to a feature. They object to a gap in the questionnaire: a vendor that holds their directory data, a login service with no exit, an AI agent that acts under a shared service account no one can attribute. An auth library you run yourself changes several of those answers. The code is MIT licensed and readable, the data sits in your database in your region, and nothing leaves your infrastructure unless you send it. The cost is that the controls, and the evidence for them, are yours to operate. What the review usually asks for - **Identity federation.**SAML 2.0 or OIDC against the customer's identity provider, with provisioning and removal through SCIM 2.0. - **Access control.**Organizations, roles, and a clear model for service accounts and AI agents. - **Audit.**Who did what, to what, when, exportable to the customer's SIEM. - **Data handling.**Location, export and deletion, with the processor question answered. - **Supply chain.**Signed releases, an SBOM and a disclosure process. The theAuth answers ## Each question, with what ships and what does not. Pitfalls ## Where enterprise rollouts slip. - **Promising a certification.**There is none to promise. Say "mapped to SOC 2 controls" and attach your own evidence. - **Assuming isolation between tenants.**Tag agents with a tenant, then enforce the boundary in your own authorization checks. - **Skipping the offboarding test.**Run the SCIM deprovisioning path against the customer's identity provider in staging before the review. - **Forgetting you operate it.**Backups, key rotation and upgrades are yours. Write them into the runbook the reviewer asks for. - **Treating the Go and TypeScript libraries as identical.**They share a model, not a feature list. Check the [feature page](https://theauth.dev/features/) for what each supports. ## Keep reading - [Enterprise datasheet](https://theauth.dev/enterprise/) - [Auth for B2B SaaS](https://theauth.dev/use-cases/saas/) - [Security practices](https://theauth.dev/security/) - [Compare with hosted vendors](https://theauth.dev/compare/) - [theauth-go for Go services](https://theauth.dev/go/) --- URL: https://theauth.dev/use-cases/ai-startups/ Use case # Auth for AI startups Sign-in on day one, agent identity when your product starts calling tools, and enterprise features when the first large customer asks, all from one MIT licensed library you can read. [Read the quickstart](https://docs.theauth.dev/quickstart) [Jump to the steps](https://theauth.dev/use-cases/ai-startups/#step-1) The problem ## You need auth now, and a different auth later. Early on, auth should cost an afternoon, not a sprint. A few weeks later your product has agents calling tools, and a user table is not enough. Later still, a company asks for SSO. Switching auth providers at each stage means migrating users three times. The alternative is a library whose scope grows with you, that runs on the runtime you already deploy to, and whose licensing does not change as your user count does. What an early team wants - **A working app quickly.**Sign-in and sign-up routes you do not write. - **Your stack.**Next.js, Hono, or whatever you deploy on, including edge runtimes. - **No surprise bill.**Licensing that does not scale with users. - **Room to grow.**Agents, organizations, SSO and SCIM without a migration. The theAuth path ## Scaffold, deploy anywhere, add features as needed. theAuth runs as a library inside your own app, mounted through a framework adapter, with your own database behind it (Postgres, MySQL, SQLite or Cloudflare D1). You run the whole stack in your infrastructure, and identities stay in your database. Step by step ## From an empty folder to a running app. Scaffold first, then add the pieces your product needs. ### Scaffold the app Pick `next-saas` for a Next.js App Router app with Drizzle and prebuilt sign-in components, or `hono-mcp` for a Hono server that also acts as an MCP authorization server. The database driver is `better-sqlite3` by default, or `pg` for Postgres. terminal ```js npx @glinr/create-theauth-app cd my-theauth-app pnpm install cp .env.example .env # then set THEAUTH_SECRET pnpm db:push pnpm dev ``` ### Create the instance This is the core. Pick the plugins your sign-in needs. Postgres here, SQLite works the same way for local development. lib/auth.ts ```ts import { createTheAuth } from "@glinr/theauth"; import { emailPassword, passkey } from "@glinr/theauth/auth"; export const auth = await createTheAuth({ database: { provider: "postgres", url: process.env.DATABASE_URL }, plugins: [emailPassword(), passkey()], }); ``` ### Mount it in Next.js A catch-all App Router route hands every auth path to the adapter. The default base path is `/api/theauth`, so pass `basePath` if you want a different one. The adapter packages are `@glinr/theauth-nextjs` and `@glinr/theauth-hono`. app/api/theauth/[...theauth]/route.ts ```ts import { theAuthNextjs } from "@glinr/theauth-nextjs"; import { auth } from "@/lib/auth"; const handlers = theAuthNextjs(auth); export const GET = handlers.GET; export const POST = handlers.POST; export const PATCH = handlers.PATCH; export const DELETE = handlers.DELETE; export const OPTIONS = handlers.OPTIONS; ``` ### Or run it on Hono at the edge The same instance mounts in a Hono app, which uses web-standard Request and Response. src/index.ts ```ts import { Hono } from "hono"; import { theAuthHono } from "@glinr/theauth-hono"; import { auth } from "./auth"; const app = new Hono(); app.route("/api/auth", theAuthHono(auth)); export default app; ``` ### Give your first agent an identity When your product starts calling tools, add an agent with scoped permissions. See [identity and permissions for AI agents](https://theauth.dev/use-cases/ai-agents/) for delegation, approvals and budgets. agent.ts ```ts const agent = await auth.agent.create({ ownerId: "user-123", name: "github-reader", type: "autonomous", permissions: [{ resource: "mcp:github:*", actions: ["read"] }], }); ``` Checked against the package source and the scaffolder's README for @glinr/theauth 0.5.0 and @glinr/create-theauth-app 0.2.0 on 2026-10-06. The scaffolder's README also lists npm create theauth-app@latest and bunx @glinr/create-theauth-app as equivalents. Not every plugin runs on every runtime, so check the [adapters docs](https://docs.theauth.dev/adapters) before you commit to one. Pitfalls ## Early-stage mistakes worth avoiding. - **A placeholder secret in production.**Templates use `.env.example` with an empty `THEAUTH_SECRET`. Set a long random value and keep it out of git. - **Local SQLite in a serverless deploy.**A file database does not persist on most serverless hosts. Use Postgres, MySQL or Cloudflare D1 there. - **Mounting the adapter at a path you did not configure.**The Next.js adapter strips its `basePath`, which defaults to `/api/theauth`. Pass the real path if you mount elsewhere. - **Adding agents without an owner.**Every agent needs an `ownerId`. Decide who owns an agent your product creates on a user's behalf before you ship it. - **Planning a later migration.**SSO and SCIM are modules of the same library. Adopt organizations early and the enterprise step is configuration, not a user migration. ## Keep reading - [Auth for B2B SaaS with organizations](https://theauth.dev/use-cases/saas/) - [Identity and permissions for AI agents](https://theauth.dev/use-cases/ai-agents/) - [SDKs and adapters on the homepage](https://theauth.dev/#sdks) - [Quickstart](https://docs.theauth.dev/quickstart) - [Adapters](https://docs.theauth.dev/adapters) - [Migrate from Better Auth](https://docs.theauth.dev/migrate/from-better-auth) --- URL: https://theauth.dev/security/ Security # Security practices, stated plainly What the code does, how releases are signed, and how to report a vulnerability. Grounded in the SECURITY.md files and the Go threat model. No certifications are claimed. [Read SECURITY.md](https://github.com/glincker/theauth/blob/main/SECURITY.md) [Go threat model](https://docs.theauth.dev/go/security/threat-model) ## Security datasheet **Datasheet**TypeScript core and Go module Credentials Protocol Supply chain Hashing differs between the TypeScript and Go libraries because of their runtimes. Pick the one that matches your deployment. Vulnerability disclosure ## Report privately, never in a public issue The two repositories publish separate policies. Both prefer GitHub private vulnerability reporting. - TypeScript repo[Private advisory](https://github.com/glincker/theauth/security/advisories/new) (preferred), or email support@glinr.com with the subject [Security] theauth vulnerability. - 48 hoursAcknowledgment. Assessment within 5 business days, fix timeline within 10 business days. - 90 daysPublic disclosure after confirmation, coordinated with the reporter. If a fix cannot ship, we still disclose so users can mitigate. - Go repo[Private advisory](https://github.com/glincker/theauth-go/security/advisories/new) (preferred), or support@glinr.com. Acknowledgment in 48 hours for critical, high and moderate reports. Fix targets: 14 days critical or high, 30 days moderate. Read the [full Go policy](https://github.com/glincker/theauth-go/blob/main/.github/SECURITY.md). Full text: [SECURITY.md](https://github.com/glincker/theauth/blob/main/SECURITY.md). Out of scope includes denial of service, social engineering and upstream dependency issues. ## What we do not claim - **No certifications.** There is no SOC 2, ISO 27001 or ISO 42001 certificate. Compliance material is mapping and evidence, not an attestation. - **No third-party audit is published** on this site. - **The operator owns TLS, secrets and infrastructure.** The Go threat model lists these as out of scope. - **Defaults need tuning.** Go's RequireState is off by default, and revocation propagates to Go resource servers within the introspection cache TTL (60 seconds by default). - [Agent identity](https://theauth.dev/agent-identity/) - [Pricing](https://theauth.dev/pricing/) - [Trust](https://theauth.dev/#trust) --- URL: https://theauth.dev/privacy/ Legal # Privacy policy This policy covers the theauth.dev website. It is short because the site is static: it has no accounts and no forms. Analytics and its cookies run only if you accept them. Last updated: October 7, 2026 ## Scope and who we are The website at theauth.dev is published by GLINCKER LLC, which operates theAuth under the GLINR STUDIOS name. In this policy, “we” means GLINCKER LLC. This policy covers the website only. It does not cover the theAuth software you install and run yourself, which sends nothing to us. It does not cover theAuth Cloud, which is in early access and will have its own terms and privacy information. It does not cover sites we link to, such as the documentation, GitHub, npm and PyPI, which are run by other parties. ## What we collect We do not collect personal information through this website. There are no sign-up forms, no comment boxes, no newsletter forms and no user accounts. We run Google Analytics only after you accept it in the consent card (see below). We do not run advertising tools, and we do not use tracking pixels. Like any website, the infrastructure that delivers these static files receives your IP address and standard request headers (such as your browser type) in order to respond. That infrastructure may keep ordinary server access logs. We do not use those logs to build profiles of visitors. ## Cookies and browser storage Until you accept analytics, the site sets no cookies. It uses three browser storage keys, listed below. After you accept, Google Analytics and PostHog add their own cookies and storage entries, described in the analytics section. They stay on your device and are never sent to us. | Key | Where | Purpose | Lifetime | | --- | --- | --- | --- | | theauth.announce.dismissed | localStorage | Remembers that you closed the announcement bar, so it stays closed. | Until you clear site data | | theauth.consent | localStorage | Remembers whether you accepted or declined analytics, so the question is not asked again. | Until you clear site data | | theauth.gh.stars | sessionStorage | Caches the GitHub star count so it is fetched once per visit. | Until the tab or window closes | If your browser blocks storage, the site still works. The announcement bar will reappear on each page, the star count will be fetched again, and the analytics question will be asked again. ## Analytics (Google Analytics 4 and PostHog) If you press Accept on the consent card, the site loads Google Analytics 4 (measurement ID G-2C9PQNDBEH) from Google. It sets the cookies `_ga` and `_ga_*` for up to two years and sends page views, approximate location, device and browser information, and your IP address to Google. IP anonymization is turned on. Google acts as our processor for this data and may process it in the United States. We use it only to understand which pages are read. The same Accept also loads PostHog (hosted in the United States at `us.i.posthog.com`). PostHog records page views, clicks on the main calls to action (quickstart, GitHub, install command copy, SDK tab), approximate location, device and browser information, and unhandled JavaScript errors, and stores an anonymous identifier in your browser (a cookie and localStorage entry starting with `ph_`). We do not identify you by name or email. See [PostHog’s privacy policy](https://posthog.com/privacy). If you press Decline, or the site sees a Do Not Track or Global Privacy Control signal, nothing is loaded, no analytics request is made and no analytics cookie is set. Declining also stops PostHog capture if it was loaded earlier. You can change your mind at any time with the Analytics preferences link in the footer. Declining deletes the analytics cookies on this domain. See [how Google uses data from sites that use its services](https://policies.google.com/technologies/partner-sites), and the [Google Analytics opt-out add-on](https://tools.google.com/dlpage/gaoptout). ## The GitHub star count Pages with a GitHub star count load it in your browser from GitHub’s public API at `api.github.com`. This is a direct request from your browser to GitHub, so GitHub receives your IP address and standard request headers. We do not receive that information and cannot see it. How GitHub handles it is described in [GitHub’s privacy statement](https://docs.github.com/en/site-policy/privacy-policies/github-general-privacy-statement). If you block requests to `api.github.com`, the count is not shown and nothing else on the page changes. ## Fonts, scripts and third parties Fonts (Inter and JetBrains Mono), the site script, the animation library and all images are served from theauth.dev itself. The site loads no third-party fonts, embedded videos or social widgets. Apart from the GitHub request above, the only other services it calls are Google Analytics and PostHog, and only if you accepted them. ## Links to other sites The site links to the documentation, GitHub, npm, PyPI, pkg.go.dev, glincker.com and other sites. Once you follow a link, that site’s own policies apply. We are not responsible for them. ## If you contact us If you email us, we receive your address and whatever you write, and we use it to reply and to keep a record of the conversation. If you open an issue or discussion on GitHub, that is public and governed by GitHub’s terms. ## Your choices and rights Because the site does not collect personal information itself, there is normally nothing for us to access, correct or delete. You can clear the storage keys and cookies at any time in your browser settings, and change your analytics choice from the footer. Depending on where you live, you may have legal rights over personal data we hold, for example from an email you sent us. To exercise them, write to us at the address below. ## Changes to this policy If we change what the site collects, we will update this page before that change goes live and revise the date at the top. ## Contact GLINCKER LLC Email: [support@glinr.com](mailto:support@glinr.com) For security vulnerabilities, follow the [security policy](https://github.com/glincker/theauth/blob/main/SECURITY.md) instead. --- URL: https://theauth.dev/terms/ Legal # Terms of use These terms cover your use of the theauth.dev website. The theAuth software is licensed separately, under the MIT license. Last updated: October 6, 2026 ## Who we are and what this covers The website at theauth.dev is published by GLINCKER LLC, which operates theAuth under the GLINR STUDIOS name. In these terms, “we” means GLINCKER LLC. By using the website you agree to these terms. If you do not agree, please do not use it. The website needs no account. theAuth Cloud is in early access and will be covered by its own terms, not these. ## The software is licensed separately The theAuth libraries are open source under the MIT license. The license text is the `LICENSE` file in each repository, for example [glincker/theauth](https://github.com/glincker/theauth) and [glincker/theauth-go](https://github.com/glincker/theauth-go). That license, not these terms, governs your use, copying and modification of the software. Nothing in these website terms limits the rights the MIT license gives you. If a file in a repository carries a different license notice, that notice applies to that file. ## Using the website You may read the site, link to it, and quote reasonable excerpts with attribution. Please do not: - use the site in a way that breaks the law or infringes others’ rights; - attempt to disrupt the site or probe it for vulnerabilities outside our [security policy](https://github.com/glincker/theauth/blob/main/SECURITY.md); - present the site, or a modified copy of it, as an official source of ours. ## Site content and brand The text, layout and graphics of the website, and the theAuth name and logo, are provided so you can learn about and evaluate the project. If you want to reuse the logo or site design beyond describing the project, please ask first. ## Accuracy and no advice We try to keep the site accurate, but software changes quickly and pages can be out of date. The source code and the documentation at docs.theauth.dev are the authoritative references. Test before you rely on anything you read here. Nothing on the site is legal, security or compliance advice. Descriptions of compliance reports, such as mappings to the EU AI Act, NIST, SOC 2 or ISO 42001, describe reports the software can generate. They are not certifications, attestations or statements that any organization complies with a standard. ## Other sites and services The site links to services we do not control, including GitHub, npm and the documentation site. We are not responsible for their content, availability or terms. ## No warranty The website and the information on it are provided “as is”, without warranty of any kind, express or implied, including accuracy, availability and fitness for a particular purpose. The software carries its own disclaimer in the MIT license. ## Limitation of liability To the maximum extent permitted by law, GLINCKER LLC is not liable for any indirect, incidental, special, consequential or punitive damages, or for any loss of profits or revenues, arising from your use of the website. Nothing in these terms excludes liability that cannot be excluded by law. ## Changes to these terms We may update these terms. The current version is always at this address, with its date at the top. If you keep using the site after a change, you accept the updated terms. ## Contact GLINCKER LLC Email: [support@glinr.com](mailto:support@glinr.com) --- URL: https://theauth.dev/agent-oauth/ Agent-grade OAuth # DPoP, device flow and passkeys for AI agents. An agent needs more than a bearer token. This page shows which standards theAuth uses to bind tokens to a key, let a person approve a sensitive call and sign in the humans behind each agent, and how far each one has shipped in Go and TypeScript. [Get started](https://docs.theauth.dev/quickstart) [Compare Go and TypeScript](https://theauth.dev/features/) ## What is covered and where Agent OAuth standards and status in Go and TypeScript | Standard | What it does | Go | TypeScript | | --- | --- | --- | --- | | RFC 9449 DPoP | Access tokens bound to a client key, so a stolen token is useless without the private key. | Beta | Not found in core | | RFC 8628 device authorization | A code shown on a CLI or headless client and entered on another device. | Stable | Beta | | RFC 9509 CIBA | An agent asks, a person approves out of band. Needs memory or Postgres storage. | Supported | Check the matrix | | Passkeys (WebAuthn) | Discoverable passkeys for the people who own agents. | Stable | Beta | Status comes from the [feature matrix](https://theauth.dev/features/), which links the source file for each row. It changes as releases ship. ## How they fit together The [MCP OAuth 2.1 server](https://theauth.dev/mcp-oauth/) issues scoped tokens with PKCE S256. DPoP makes those tokens sender constrained. CIBA lets an [agent identity](https://theauth.dev/agent-identity/) pause until a person approves. The device grant covers CLIs and headless tools, and [passkeys](https://theauth.dev/human-auth/) sign in the people who own the agents. Building in Go? See the [Go authentication library](https://theauth.dev/go/), or follow the [TypeScript MCP guide](https://theauth.dev/guides/mcp-server-typescript/). ## Common questions **Does theAuth support DPoP?** In theauth-go, yes: DPoP (RFC 9449) binds access tokens to a client key and is in beta, behind its own config field. In the TypeScript library we did not find a DPoP implementation in core, so check the feature matrix before relying on it there. **Can an AI agent use the device flow?** The device grant (RFC 8628) lets a CLI or headless client show a code that a person enters on another device. It is stable in Go and beta in TypeScript. For an agent that must wait for a human decision on a single action, CIBA is the closer fit, and it is in the Go library. **Are passkeys supported?** Yes. Passkeys (WebAuthn) are stable in theauth-go and beta in the TypeScript core. They sign in the person who owns an agent. The agent itself uses a scoped token, not a passkey. **Which of these should I turn on first?** Start with PKCE S256 and scoped tokens, which every MCP client expects. Add DPoP when a leaked token would be costly, and CIBA when an agent should ask a person before a sensitive call. --- URL: https://theauth.dev/benchmarks/ Benchmarks # Numbers you can rerun The TypeScript policy engine does 2.45M warm-cache evaluations per second on one core, with a p99 of 625 ns. Everything below was measured on the machine, versions and commits listed, on 2026-10-07. [Run it yourself](https://theauth.dev/benchmarks/#reproduce) [What is not measured](https://theauth.dev/benchmarks/#method) ## Run details **This run**2026-10-07 Machine TypeScript Go TypeScript ## Policy engine One user, one agent and five permissions in an in-memory SQLite database, audit logging off. Warm means a pre-warmed cache hit. Cold means the cache is invalidated before every call, so each evaluation pays one database round trip. The range column is the lowest and highest run, so you can see how noisy the machine was. TypeScript policy engine benchmark results | Scenario | Evaluations per second | Range across runs | p99 latency | p99 range | | --- | --- | --- | --- | --- | | warm cache hit | 2.45M | 2.41M to 2.51M | 625 ns | 583 ns to 625 ns | | cold path - direct permission | 10.2k | 10.1k to 10.9k | 189 µs | 187 µs to 206 µs | | cold path - rbac role expansion | 22.0k | 20.7k to 22.4k | 73.0 µs | 67.8 µs to 77.4 µs | | cold path - rebac graph lookup | 6.4k | 6.1k to 6.7k | 356 µs | 297 µs to 375 µs | Go ## Hot paths in theauth-go The twelve benchmarks that gate every release against regressions, in memory storage. Argon2 runs at the production work factor, so those two rows are slow on purpose. Times are per operation. Go hot path benchmark results | Benchmark | What it measures | Time per op | Range across runs | Memory per op | Allocations per op | | --- | --- | --- | --- | --- | --- | | BenchmarkArgon2Hash | Argon2id hash at the production work factor. | 26.4 ms | 25.9 ms to 27.1 ms | 64.0 MiB | 86 | | BenchmarkArgon2Verify | Argon2id verify at the production work factor. | 26.3 ms | 26.2 ms to 26.8 ms | 64.0 MiB | 88 | | BenchmarkAuditRedactor | Audit redactor key matching. | 689 ns | 669 ns to 714 ns | 0.7 KiB | 4 | | BenchmarkOAuthCallback | Social-provider callback: AES-GCM encrypt and in-memory upsert. | 813 ns | 788 ns to 843 ns | 1.3 KiB | 5 | | BenchmarkOAuthCodeFlow | Authorization code grant: PKCE S256 check, code consume, JWT mint, refresh insert. | 24.1 µs | 23.8 µs to 24.4 µs | 16.5 KiB | 106 | | BenchmarkOAuthTokenEndpointRefreshHit | Refresh-token grant on /oauth/token with the client-secret Argon2 cache warm. | 24.1 µs | 23.7 µs to 24.5 µs | 16.2 KiB | 106 | | BenchmarkJWKSEndpoint | JWKS endpoint: signing-key snapshot read and JSON marshal. | 3.49 µs | 3.46 µs to 3.58 µs | 3.5 KiB | 42 | | BenchmarkSCIMTokenAuth | SCIM bearer authentication: SHA-256 hash plus one storage lookup. | 7.25 µs | 7.16 µs to 7.55 µs | 10.4 KiB | 60 | | BenchmarkSessionLookup | Cookie parse, token hash and in-memory lookup: the floor cost of an authenticated request. | 4.34 µs | 4.16 µs to 8.87 µs | 9.1 KiB | 46 | | BenchmarkJWTSign | Ed25519 JWT sign. | 15.7 µs | 15.5 µs to 19.1 µs | 2.8 KiB | 15 | | BenchmarkJWTVerify | Ed25519 JWT verify. | 36.1 µs | 34.9 µs to 37.8 µs | 3.4 KiB | 61 | | BenchmarkRateLimitReadHeavy | Rate limiter under parallel, read-heavy load. | 129 ns | 116 ns to 131 ns | 0.0 KiB | 0 | ## What these numbers do not cover - **Network and TLS.** Every benchmark runs in process. - **Real databases.** Storage is in memory (SQLite in memory for TypeScript). Postgres and MySQL add round trips these results do not include. - **Scaling across cores.** The TypeScript engine is single-threaded here. Go has one parallel case, the rate limiter. - **Large policy sets.** The TypeScript run uses five permissions. Cold-path cost grows with the policy graph. - **Audit logging, memory use and cold start.** Audit is off in the TypeScript run, and neither run measures process memory or startup time. - **Other libraries.** We publish our own numbers only. A fair comparison needs the same harness and hardware for every library, and we have not built that. Results move with the machine. A laptop running other work gives noisier and slower numbers, which is why the range columns exist. Treat the figures as a baseline for your own hardware, not a promise. Reproduce ## Two commands Both repositories are public. Clone, install, run. The Go script reads its benchmark list from benchgate/curated.txt and prints output that benchstat accepts. terminal ```sh # TypeScript policy engine git clone https://github.com/glincker/theauth.git && cd theauth pnpm install && pnpm bench # Go hot paths (BENCH_TIME and BENCH_COUNT default to 2s and 10) git clone https://github.com/glincker/theauth-go.git && cd theauth-go ./scripts/bench-gate.sh ``` - [Security practices](https://theauth.dev/security/) - [MCP OAuth 2.1](https://theauth.dev/mcp-oauth/) - [Agent identity](https://theauth.dev/agent-identity/) - [Go benchmark gate](https://github.com/glincker/theauth-go/blob/main/docs/BENCHMARKS.md) --- URL: https://theauth.dev/contact/ Contact # Talk to the people who build it theAuth is maintained in the open by GLINCKER, the open-source division of GLINR STUDIOS. Pick the channel that fits: public questions and bugs go to GitHub, vulnerabilities go to a private form, and everything else goes to email. ## Contact channels **Channels**Where to go for what Public Private --- URL: https://theauth.dev/features/ Features # What the TypeScript and Go libraries do today One row per capability, a status for each library, and a link to the code. This is an index. The explainer pages go deeper. Last verified 2026-10-06 against the main branch of both repositories. [Jump to a category](https://theauth.dev/features/#ft-jump) [How statuses work](https://theauth.dev/features/#ft-rules) Reading the tables ## How statuses work Each cell shows an icon and a word, so the status never depends on color. The small source link in a cell goes to the code in that library. **How rows are counted.** TypeScript has 17 OAuth providers: one source file per provider under core/src/auth/oauth/providers, not counting generic, index, presets and tests. Go has 12: one package per provider under provider/, not counting internal and oidc. Facebook and Bitbucket exist in TypeScript as presets over the generic provider, so those cells carry a note. The 11 framework adapters are every package in packages/adapters except prisma, a database adapter (12 packages in all). Go has 3 audit sinks. **Compliance rows** list control mapping docs only. They map library features to framework controls and are reference documents, not an audit result. Last verified 2026-10-06 at sdk commit 28635bf and go commit eb5c178. Counts are checked by npm run features:check. ## Categories - [Human sign-in](https://theauth.dev/features/#ft-human) - [OAuth providers](https://theauth.dev/features/#ft-oauth) - [Agent identity](https://theauth.dev/features/#ft-agent) - [MCP and OAuth server](https://theauth.dev/features/#ft-mcp) - [Enterprise](https://theauth.dev/features/#ft-enterprise) - [Storage](https://theauth.dev/features/#ft-storage) - [Frameworks and clients](https://theauth.dev/features/#ft-clients) - [Observability and supply chain](https://theauth.dev/features/#ft-supply) ## Human sign-in Ways a person proves who they are. Human sign-in: status in the TypeScript and Go libraries | Capability | What it does | TypeScript | Go | Read more | | --- | --- | --- | --- | --- | | Email and password | Sign-up and sign-in with hashed passwords. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/auth/email) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/internal/password) | [Human auth](https://theauth.dev/human-auth/#ha-methods) | | Breach check on passwords | Rejects passwords found in the Have I Been Pwned range API. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/hibp.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/blob/main/config.go) | [Human auth](https://theauth.dev/human-auth/#ha-methods) | | Magic link | Passwordless sign-in by emailed single-use link. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/magic-link.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/internal/magiclink) | [Human auth](https://theauth.dev/human-auth/#ha-methods) | | Email one-time code | Sign-in by a one-time code sent to an email address. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/email-otp.ts) | Go: Not available | [Human auth](https://theauth.dev/human-auth/#ha-methods) | | Phone and SMS code | Sign-in by a one-time code sent to a phone number. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/phone.ts) | Go: Not available | [Human auth](https://theauth.dev/human-auth/#ha-methods) | | Passkeys (WebAuthn) | Register and sign in with discoverable passkeys. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/passkey.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/internal/webauthn) | [Passkey docs](https://docs.theauth.dev/auth/passkey) | | TOTP second factor | Authenticator app codes with recovery codes. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/totp.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/internal/totp) | [Two-factor docs](https://docs.theauth.dev/auth/two-factor) | | Session freshness and step-up | Require a recent sign-in before a sensitive action. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/session/freshness.ts) | Go: StableRequireRecentAuth[source](https://github.com/glincker/theauth-go/blob/main/sessions.go) | [Sessions docs](https://docs.theauth.dev/sessions) | | Session list and revoke | Show a user their sessions and end any of them. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/session/multi-session.ts) | Go: BetaOptional storage capability, listed as experimental[source](https://github.com/glincker/theauth-go/blob/main/sessions.go) | [Sessions docs](https://docs.theauth.dev/sessions) | | Password reset | Emailed single-use reset token with expiry. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/password-reset.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/internal/password) | [Human auth](https://theauth.dev/human-auth/#ha-methods) | | Username sign-in | Sign in with a username instead of an email address. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/username.ts) | Go: Not available | [Human auth](https://theauth.dev/human-auth/#ha-methods) | | Anonymous sessions | Create a session before the visitor has an identity. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/anonymous.ts) | Go: Not available | [Human auth](https://theauth.dev/human-auth/#ha-methods) | | Captcha on auth routes | Verify a captcha token before sign-in and sign-up. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/captcha.ts) | Go: Not available | [Human auth](https://theauth.dev/human-auth/#ha-methods) | | Google One Tap | One Tap sign-in with a Google identity token. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/one-tap.ts) | Go: Not available | [Human auth](https://theauth.dev/human-auth/#ha-methods) | | Sign In With Ethereum | Wallet sign-in using the SIWE message format. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/siwe.ts) | Go: Not available | [Human auth](https://theauth.dev/human-auth/#ha-methods) | | Device authorization (RFC 8628) | Sign in on a TV or CLI through a code entered on another device. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/device-auth.ts) | Go: StableServer side of the device grant[source](https://github.com/glincker/theauth-go/tree/main/internal/apitokens) | [CLI login guide](https://docs.theauth.dev/go/guides/cli-login) | | CLI login client helper | Go package that runs the device login from a command-line program. | TypeScript: Not available | Go: BetaExperimental package[source](https://github.com/glincker/theauth-go/tree/main/clientauth) | [CLI login guide](https://docs.theauth.dev/go/guides/cli-login) | ## OAuth providers Social and enterprise login providers. OAuth providers: status in the TypeScript and Go libraries | Capability | What it does | TypeScript | Go | Read more | | --- | --- | --- | --- | --- | | Apple | Sign in with Apple. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/apple.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/provider/apple) | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | | Discord | Sign in with Discord. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/discord.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/provider/discord) | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | | GitHub | Sign in with GitHub. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/github.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/provider/github) | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | | GitLab | Sign in with GitLab. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/gitlab.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/provider/gitlab) | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | | Google | Sign in with Google. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/google.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/provider/google) | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | | LinkedIn | Sign in with LinkedIn. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/linkedin.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/provider/linkedin) | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | | Microsoft | Sign in with Microsoft. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/microsoft.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/provider/microsoft) | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | | Slack | Sign in with Slack. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/slack.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/provider/slack) | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | | Twitch | Sign in with Twitch. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/twitch.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/provider/twitch) | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | | X (Twitter) | Sign in with X (Twitter). | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/twitter.ts) | Go: StablePKCE required[source](https://github.com/glincker/theauth-go/tree/main/provider/x) | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | | Atlassian | Sign in with Atlassian. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/atlassian.ts) | Go: Not available | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | | Dropbox | Sign in with Dropbox. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/dropbox.ts) | Go: Not available | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | | Figma | Sign in with Figma. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/figma.ts) | Go: Not available | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | | Notion | Sign in with Notion. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/notion.ts) | Go: Not available | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | | Reddit | Sign in with Reddit. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/reddit.ts) | Go: Not available | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | | Spotify | Sign in with Spotify. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/spotify.ts) | Go: Not available | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | | Zoom | Sign in with Zoom. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/zoom.ts) | Go: Not available | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | | Facebook | Sign in with Facebook. | TypeScript: BetaPreset over the generic OAuth provider, not a dedicated provider module[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/presets.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/provider/facebook) | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | | Bitbucket | Sign in with Bitbucket. | TypeScript: BetaPreset over the generic OAuth provider, not a dedicated provider module[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/presets.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/provider/bitbucket) | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | | Generic OIDC and OAuth 2.0 | Add any other OIDC or OAuth 2.0 provider from its discovery URL or endpoints. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/oauth/providers/generic.ts) | Go: BetaPackage not named in the stable list[source](https://github.com/glincker/theauth-go/tree/main/provider/oidc) | [Human auth](https://theauth.dev/human-auth/#ha-oauth) | ## Agent identity Identity, authority and oversight for AI agents. Agent identity: status in the TypeScript and Go libraries | Capability | What it does | TypeScript | Go | Read more | | --- | --- | --- | --- | --- | | Agent identities | Create, suspend, rotate and revoke agents owned by a user. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/core/src/agent) | Go: StableAgent token minting and revocation helpers are experimental[source](https://github.com/glincker/theauth-go/tree/main/internal/agent) | [Agent identity](https://theauth.dev/agent-identity/) | | Delegation chains with depth limit | A user grants an agent authority, and agents can pass a narrower grant on. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/core/src/delegation) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/internal/chain) | [Delegation docs](https://docs.theauth.dev/delegation) | | Policy engine | Evaluate resource and action permissions for an agent or user. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/core/src/policy) | Go: BetaExperimental package[source](https://github.com/glincker/theauth-go/tree/main/policy) | [Policy engine docs](https://docs.theauth.dev/policy-engine) | | Budget policies | Cap an agent by spend or call volume. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/core/src/policies/budget.ts) | Go: Not available | [Budget docs](https://docs.theauth.dev/budget-policies) | | Trust scoring and anomaly signals | Score an agent from age, volume and privilege escalation attempts. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/core/src/trust) | Go: Not available | [Agent identity](https://theauth.dev/agent-identity/) | | Human approval for sensitive actions | Hold a tool call until a person approves it. | TypeScript: BetaCIBA style approval module, not the CIBA grant[source](https://github.com/glincker/theauth/tree/main/packages/core/src/approval) | Go: BetaCIBA backchannel grant, see the MCP table[source](https://github.com/glincker/theauth-go/tree/main/internal/as) | [Approval docs](https://docs.theauth.dev/approval) | | Agent to agent protocol (A2A) | Publish an agent card and call other agents. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/core/src/a2a) | Go: Not available | [A2A docs](https://docs.theauth.dev/a2a) | | Decentralized identifiers (DID) | did:key and did:web identifiers for agents, with signing. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/core/src/did) | Go: Not available | [DID docs](https://docs.theauth.dev/did) | | Verifiable credentials | Issue and verify credentials, including audit exports as credentials. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/core/src/vc) | Go: Not available | [Compliance docs](https://docs.theauth.dev/compliance) | ## MCP and OAuth server The authorization server and resource server pieces that MCP clients rely on. MCP and OAuth server: status in the TypeScript and Go libraries | Capability | What it does | TypeScript | Go | Read more | | --- | --- | --- | --- | --- | | OAuth 2.1 authorization server | Authorization code with PKCE S256 for MCP clients. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/core/src/mcp) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/internal/as) | [MCP OAuth 2.1](https://theauth.dev/mcp-oauth/) | | Server metadata (RFC 8414, RFC 9728) | Authorization server and protected resource discovery documents. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/mcp/metadata.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/blob/main/internal/as/metadata.go) | [MCP OAuth 2.1](https://theauth.dev/mcp-oauth/) | | Dynamic client registration (RFC 7591) | Clients register themselves at a registration endpoint. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/mcp/registration.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/internal/as) | [MCP OAuth 2.1](https://theauth.dev/mcp-oauth/) | | Resource indicators (RFC 8707) | Bind a token to the resource it was requested for. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/mcp/token.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/blob/main/internal/as/config.go) | [MCP OAuth 2.1](https://theauth.dev/mcp-oauth/) | | Refresh token rotation and reuse detection | Each refresh issues a new token and a replayed one revokes the family. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/session/token-family.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/blob/main/internal/as/revoke.go) | [MCP OAuth 2.1](https://theauth.dev/mcp-oauth/) | | Resource server token validation | Validate access tokens inside an MCP server. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/mcp/validate.ts) | Go: StableSeparate zero dependency module[source](https://github.com/glincker/theauth-go/tree/main/mcpresource) | [MCP OAuth 2.1](https://theauth.dev/mcp-oauth/) | | Client credentials grant | Machine to machine tokens for a registered client. | TypeScript: Not availableThe MCP token endpoint handles the authorization code and refresh token grants | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/internal/as) | [MCP OAuth 2.1](https://theauth.dev/mcp-oauth/) | | Token exchange (RFC 8693) | Swap one token for another, used for delegation. | TypeScript: UnverifiedOnly RFC 8693 actor claims found, no exchange endpoint | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/internal/as) | [MCP OAuth 2.1](https://theauth.dev/mcp-oauth/) | | Client ID metadata documents (CIMD) | Use an HTTPS URL as a client identifier, per the MCP specification. | TypeScript: Not availableNo CIMD code found in the TypeScript core | Go: BetaOptions such as CIMDConfig.DenyHost are experimental[source](https://github.com/glincker/theauth-go/tree/main/internal/cimd) | [MCP OAuth 2.1](https://theauth.dev/mcp-oauth/) | | DPoP (RFC 9449) | Sender constrained access tokens. | TypeScript: UnverifiedNo implementation found in core | Go: BetaNot named in the stable list[source](https://github.com/glincker/theauth-go/tree/main/internal/dpop) | [MCP OAuth 2.1](https://theauth.dev/mcp-oauth/) | | Pushed authorization requests (RFC 9126) | Send authorization parameters to the server before the redirect. | TypeScript: UnverifiedNo implementation found in core | Go: BetaNot named in the stable list[source](https://github.com/glincker/theauth-go/blob/main/internal/as/metadata.go) | [PAR and JAR guide](https://docs.theauth.dev/go/concepts/par-jar) | | JWT secured authorization requests (RFC 9101) | Signed request objects for authorization requests. | TypeScript: UnverifiedNo implementation found in core | Go: BetaNot named in the stable list[source](https://github.com/glincker/theauth-go/blob/main/internal/as/metadata.go) | [PAR and JAR guide](https://docs.theauth.dev/go/concepts/par-jar) | | CIBA backchannel authentication | Start a sign-in on a user's own device and poll for the result. | TypeScript: UnverifiedAn approval module exists, no CIBA grant found | Go: BetaNot named in the stable list[source](https://github.com/glincker/theauth-go/blob/main/internal/as/config_ciba.go) | [MCP OAuth 2.1](https://theauth.dev/mcp-oauth/) | ## Enterprise Organizations, directory sync, audit and compliance documents. Enterprise: status in the TypeScript and Go libraries | Capability | What it does | TypeScript | Go | Read more | | --- | --- | --- | --- | --- | | Organizations and RBAC | Organizations, members, roles and permission checks. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/organization.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/internal/organizations) | [Organizations docs](https://docs.theauth.dev/auth/organizations) | | SAML 2.0 single sign-on | Federate sign-in with an enterprise identity provider. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/sso.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/internal/saml) | [SSO docs](https://docs.theauth.dev/auth/sso) | | OIDC single sign-on | Per organization OIDC connections. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/sso.ts) | Go: UnverifiedNot checked in the Go code | [SSO docs](https://docs.theauth.dev/auth/sso) | | SCIM 2.0 provisioning | Create, update and deactivate users from an identity provider. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/scim.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/internal/scim) | [SCIM docs](https://docs.theauth.dev/auth/scim) | | Admin controls | Ban a user and impersonate a user for support. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/admin.ts) | Go: Not availableGo has an admin API and password reset, not ban or impersonate | [Admin docs](https://docs.theauth.dev/auth/admin) | | API keys and scoped tokens | Long lived keys and scoped tokens with abilities. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/api-key-manager.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/blob/main/apitokens.go) | [Auth docs](https://docs.theauth.dev/auth) | | Multi-tenant isolation | Tenants with their own settings and status. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/core/src/tenant) | Go: BetaOpt-in TenancyConfig, not named in the stable list[source](https://github.com/glincker/theauth-go/blob/main/config.go) | [Multi-tenant docs](https://docs.theauth.dev/multi-tenant) | | Audit log | Every sign-in and agent action recorded with identity and result. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/core/src/audit) | Go: StableAppend-only by contract[source](https://github.com/glincker/theauth-go/tree/main/internal/audit) | [Enterprise](https://theauth.dev/enterprise/#en-audit) | | Audit streaming to Splunk HEC | Forward audit events to Splunk over HTTP Event Collector. | TypeScript: Not availableNo sink code found in the TypeScript core | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/audit/sinks/splunkhec) | [Splunk guide](https://docs.theauth.dev/go/guides/audit-log-splunk) | | Audit streaming by signed webhook | POST CloudEvents with an HMAC-SHA256 signature. | TypeScript: Not availableNo audit sink code found in the TypeScript core | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/audit/sinks/webhook) | [Audit streaming guide](https://docs.theauth.dev/go/guides/audit-log-splunk) | | Audit streaming over OTLP | Send audit events as OpenTelemetry logs. | TypeScript: Not availableNo sink code found in the TypeScript core | Go: StableSeparate Go module[source](https://github.com/glincker/theauth-go/tree/main/audit/sinks/otlp) | [Audit streaming guide](https://docs.theauth.dev/go/guides/audit-log-splunk) | | Signed event webhooks | Deliver auth events to your endpoint with a signature. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/core/src/webhook) | Go: Not availableGo streams audit events through sinks instead | [Webhooks docs](https://docs.theauth.dev/webhooks) | | GDPR export, delete and anonymize | Per user data export, erasure and anonymization. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/auth/gdpr.ts) | Go: Not availableGo ships a GDPR handling reference, no export or erase API found | [GDPR docs](https://docs.theauth.dev/gdpr) | | Control mapping docs: EU AI Act, NIST, ISO 42001 | Documents mapping library features to framework controls. Not a certification. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/docs/compliance.mdx) | Go: Not available | [Compliance docs](https://docs.theauth.dev/compliance) | | Control mapping docs: SOC 2 | Documents mapping library features to SOC 2 criteria. Not a certification. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/docs/compliance.mdx) | Go: BetaPublished at docs.theauth.dev/go/security[source](https://github.com/glincker/theauth-go/blob/main/docs/README.md) | [SOC 2 mapping](https://docs.theauth.dev/go/security/compliance-soc2) | ## Storage Where users, sessions and audit events are kept. Storage: status in the TypeScript and Go libraries | Capability | What it does | TypeScript | Go | Read more | | --- | --- | --- | --- | --- | | PostgreSQL | Production database backend. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/db/database.ts) | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/storage/postgres) | [Adapters docs](https://docs.theauth.dev/adapters) | | MySQL | MySQL 8 backend. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/db/database.ts) | Go: BetaPackage not named in the stable list[source](https://github.com/glincker/theauth-go/tree/main/storage/mysql) | [Adapters docs](https://docs.theauth.dev/adapters) | | SQLite | Single file or embedded database. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/db/database.ts) | Go: BetaExperimental module, no organizations, SAML, SCIM or RBAC[source](https://github.com/glincker/theauth-go/tree/main/storage/sqlite) | [Adapters docs](https://docs.theauth.dev/adapters) | | Cloudflare D1 | D1 binding for Workers. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/packages/core/src/db/database.ts) | Go: Not available | [Adapters docs](https://docs.theauth.dev/adapters) | | Prisma adapter | Use a PrismaClient as the database. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/adapters/prisma) | Go: Not available | [Adapters docs](https://docs.theauth.dev/adapters) | | In-memory store | Process local storage for tests and demos. | TypeScript: UnverifiedNot checked, the SQLite provider can run in memory | Go: Stable[source](https://github.com/glincker/theauth-go/tree/main/storage/memory) | [Capability interfaces](https://docs.theauth.dev/go/concepts/capability-interfaces) | | Storage contract test suite | Public tests to verify a custom storage backend. | TypeScript: Not availableNo equivalent suite found | Go: BetaNot named in the stable list[source](https://github.com/glincker/theauth-go/tree/main/storagetest) | [Capability interfaces](https://docs.theauth.dev/go/concepts/capability-interfaces) | | Storage contract gate in CI for Postgres and MySQL | Turn the older shared contract tests on by default for both adapters. | TypeScript: Not available | Go: PlannedListed under stability hardening[source](https://github.com/glincker/theauth-go/blob/main/docs/ROADMAP.md) | [Capability interfaces](https://docs.theauth.dev/go/concepts/capability-interfaces) | ## Frameworks and clients Server adapters, client libraries and tools. Frameworks and clients: status in the TypeScript and Go libraries | Capability | What it does | TypeScript | Go | Read more | | --- | --- | --- | --- | --- | | Next.js | Next.js App Router adapter exposing auth as HTTP REST endpoints. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/adapters/nextjs) | Go: Not availableGo mounts on any net/http router instead | [Adapters docs](https://docs.theauth.dev/adapters) | | Next.js with an external backend | Next.js adapter for an external auth backend: cookies, refresh, CSRF, getServerSession and middleware. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/adapters/nextjs-auth) | Go: Not availableGo mounts on any net/http router instead | [Adapters docs](https://docs.theauth.dev/adapters) | | SvelteKit | SvelteKit adapter exposing auth as HTTP REST endpoints. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/adapters/sveltekit) | Go: Not availableGo mounts on any net/http router instead | [Adapters docs](https://docs.theauth.dev/adapters) | | Nuxt | Nuxt adapter exposing auth as HTTP REST endpoints through H3. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/adapters/nuxt) | Go: Not availableGo mounts on any net/http router instead | [Adapters docs](https://docs.theauth.dev/adapters) | | Hono | Hono adapter exposing auth as HTTP REST endpoints. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/adapters/hono) | Go: Not availableGo mounts on any net/http router instead | [Adapters docs](https://docs.theauth.dev/adapters) | | Express | Express adapter exposing auth as HTTP REST endpoints. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/adapters/express) | Go: Not availableGo mounts on any net/http router instead | [Adapters docs](https://docs.theauth.dev/adapters) | | Fastify | Fastify adapter exposing auth as HTTP REST endpoints. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/adapters/fastify) | Go: Not availableGo mounts on any net/http router instead | [Adapters docs](https://docs.theauth.dev/adapters) | | Astro | Astro adapter exposing auth as HTTP REST endpoints. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/adapters/astro) | Go: Not availableGo mounts on any net/http router instead | [Adapters docs](https://docs.theauth.dev/adapters) | | NestJS | NestJS adapter. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/adapters/nestjs) | Go: Not availableGo mounts on any net/http router instead | [Adapters docs](https://docs.theauth.dev/adapters) | | SolidStart | SolidStart adapter. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/adapters/solidstart) | Go: Not availableGo mounts on any net/http router instead | [Adapters docs](https://docs.theauth.dev/adapters) | | TanStack Start | TanStack Start adapter. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/adapters/tanstack) | Go: Not availableGo mounts on any net/http router instead | [Adapters docs](https://docs.theauth.dev/adapters) | | net/http handler | Mount the auth routes on net/http, chi, gin or echo. | TypeScript: Not availableTypeScript uses the framework adapters above | Go: StableHandler and Mount[source](https://github.com/glincker/theauth-go/blob/main/handlers.go) | [Go docs](https://docs.theauth.dev/go/concepts/capability-interfaces) | | Browser client | TypeScript client for the REST API. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/client) | Go: Not available | [Quickstart](https://docs.theauth.dev/quickstart) | | React | React hooks, with session rotation. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/react) | Go: Not available | [Quickstart](https://docs.theauth.dev/quickstart) | | Vue | Vue 3 composables. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/vue) | Go: Not available | [Quickstart](https://docs.theauth.dev/quickstart) | | Svelte | Svelte stores. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/svelte) | Go: Not available | [Quickstart](https://docs.theauth.dev/quickstart) | | Expo | React Native and Expo client. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/expo) | Go: Not available | [Quickstart](https://docs.theauth.dev/quickstart) | | Electron | Auth client for Electron desktop apps. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/electron) | Go: Not available | [Quickstart](https://docs.theauth.dev/quickstart) | | Dashboard | React admin UI for agents, permissions and audit logs. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/dashboard) | Go: Not available | [Quickstart](https://docs.theauth.dev/quickstart) | | Gateway proxy | Standalone proxy that enforces auth, authorization and audit in front of an API or MCP server. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/gateway) | Go: Not available | [MCP docs](https://docs.theauth.dev/mcp) | | Command line tools | TypeScript setup wizard and dev tools. Go ships theauth-doctor and theauth-migrate. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/cli) | Go: BetaDoctor is listed as experimental[source](https://github.com/glincker/theauth-go/tree/main/cmd) | [Quickstart](https://docs.theauth.dev/quickstart) | | Selective re-exports for deep customization | Export chosen internal symbols so integrators can extend more. | TypeScript: Not available | Go: PlannedOpen issue 79, also on the roadmap[source](https://github.com/glincker/theauth-go/issues/79) | [Go docs](https://docs.theauth.dev/go/concepts/capability-interfaces) | ## Observability and supply chain What you can monitor, and what you can verify about a release. Observability and supply chain: status in the TypeScript and Go libraries | Capability | What it does | TypeScript | Go | Read more | | --- | --- | --- | --- | --- | | OpenTelemetry spans | Trace auth operations. | TypeScript: BetaSpan shapes handed to your callback, no OpenTelemetry dependency[source](https://github.com/glincker/theauth/tree/main/packages/plugins/telemetry) | Go: BetaNot named in the stable list[source](https://github.com/glincker/theauth-go/blob/main/observability.go) | [Tracing guide](https://docs.theauth.dev/go/guides/opentelemetry-tracing) | | Prometheus metrics | Counters and hooks for a metrics endpoint. | TypeScript: Not availableNo Prometheus code found | Go: BetaHooks plus an example, not named in the stable list[source](https://github.com/glincker/theauth-go/blob/main/observability.go) | [Metrics reference](https://docs.theauth.dev/go/reference/metrics) | | Reproducible benchmarks | Benchmarks you can rerun on your own machine. | TypeScript: Beta[source](https://github.com/glincker/theauth/tree/main/packages/core/bench) | Go: BetaGates releases against regressions[source](https://github.com/glincker/theauth-go/tree/main/benchgate) | [Benchmarks](https://theauth.dev/benchmarks/) | | Signed release artifacts (Sigstore) | Release files signed with keyless cosign. | TypeScript: Not availableNo signing step found in the release workflow | Go: Beta[source](https://github.com/glincker/theauth-go/blob/main/.github/workflows/release.yml) | [Releases and verification](https://docs.theauth.dev/go/security/releases) | | SBOM for releases | A software bill of materials generated with syft. | TypeScript: Not availableNo SBOM step found in the release workflow | Go: Beta[source](https://github.com/glincker/theauth-go/blob/main/.github/workflows/release.yml) | [Releases and verification](https://docs.theauth.dev/go/security/releases) | | SLSA provenance attestation | Build provenance for release artifacts. | TypeScript: Not availableNo attestation step found in the release workflow | Go: Beta[source](https://github.com/glincker/theauth-go/blob/main/.github/workflows/release.yml) | [Releases and verification](https://docs.theauth.dev/go/security/releases) | | npm provenance | Packages published with npm provenance. | TypeScript: Beta[source](https://github.com/glincker/theauth/blob/main/.github/workflows/release.yml) | Go: Not availableNot applicable, Go modules are not published to npm | [Security](https://theauth.dev/security/) | ## Go deeper - [Human auth](https://theauth.dev/human-auth/) - [Agent identity](https://theauth.dev/agent-identity/) - [MCP OAuth 2.1](https://theauth.dev/mcp-oauth/) - [Enterprise](https://theauth.dev/enterprise/) - [Benchmarks](https://theauth.dev/benchmarks/) - [Docs](https://docs.theauth.dev) --- URL: https://theauth.dev/migrate/ Migration toolkit # Migrate from Auth0, Keycloak or Clerk without a rewrite. Keep your current login running. theAuth picks up each user the first time they sign in, you widen a percentage as you gain confidence, and setting it to 0 sends everyone back. Nobody is forced to reset a password on a cutover day. [Read the migration docs](https://docs.theauth.dev/migrate/) [See the four steps](https://theauth.dev/migrate/#flow) The strangler flow ## Four steps, no big bang ### Run both Add your current provider as an external issuer. Agents and MCP clients can use theAuth while people still sign in the old way. [Coexist with your IdP](https://docs.theauth.dev/migrate/coexist-with-your-idp). ### Migrate on login An onboarding hook creates or links the account after the old login succeeds. It never blocks the login. [Run both and migrate](https://docs.theauth.dev/migrate/run-both-and-migrate). ### Raise the percentage Rollout is sticky: raising 5 to 20 only adds users. Allowlists and rules go first, and `percent: 0` is the kill switch. ### Retire the old system Import dormant users, keep their old hashes for lazy migration, then turn off the incumbent login when the status report says everyone active has moved. Passwords move without a reset. The old hash is checked on first login, then replaced with a theAuth hash while the typed password is in hand. [Lazy password migration](https://docs.theauth.dev/migrate/lazy-passwords). Dry run first ## Plan before you write anything plan reads your export and changes nothing. It tells you which hash formats you have and who would reset. import is a dry run until you add --apply, and running it twice changes nothing the second time. Reports hold counts and error codes, never emails, names or hashes. terminal ```text # what would happen? reads the export, touches no database theauth migrate plan --from keycloak ./export # write it, then compare counts theauth migrate import --from keycloak ./export --db ./theauth.db --apply theauth migrate verify --from keycloak ./export --db ./theauth.db --sample-email someone@yourcompany.com theauth migrate status --db ./theauth.db ``` Supported sources ## What each source gives you Import sources, password hash support and known gaps | Source | Input | Passwords | Gaps | Docs | | --- | --- | --- | --- | --- | | Auth0 | Management API user export (JSON) | bcrypt, only with the hash file Auth0 support gives you. You pass a bcrypt verifier. | Without that file, users reset on first login. | [Auth0 guide](https://docs.theauth.dev/migrate/from-auth0) | | Keycloak | Realm export | PBKDF2 (SHA-1, SHA-256, SHA-512) built in, kept per user. | OTP and WebAuthn credentials are not imported. | [Import users](https://docs.theauth.dev/migrate/import-users) | | Clerk | Dashboard CSV or Backend API JSON | bcrypt or argon2 digests, with a verifier you pass. | Other hashers are reported as unsupported. Social connections are not in the export, so users reconnect. | [Clerk guide](https://docs.theauth.dev/migrate/from-clerk) | | Better Auth | Dump of the user and account tables | scrypt built in, including its salt:key layout. | Check one real login with `migrate verify` before trusting the batch. | [Better Auth guide](https://docs.theauth.dev/migrate/from-better-auth) | | Auth.js | Adapter tables (users, accounts) | Only if your Credentials provider keeps a bcrypt column. | Sessions are not imported. Users sign in once more. | [Import users](https://docs.theauth.dev/migrate/import-users) | | CSV or JSON | Any file, with a column map | bcrypt and argon2 by prefix. | Other hashes are listed as unsupported and the user resets. | [Import users](https://docs.theauth.dev/migrate/import-users) | | Firebase | Not supported | Firebase scrypt needs your signer key and parameters. | Those users reset their password. | [Pick a path](https://docs.theauth.dev/migrate/choose-a-path) | There is no Keycloak-specific guide yet. For Keycloak, read [Import users](https://docs.theauth.dev/migrate/import-users) and [Pick a migration path](https://docs.theauth.dev/migrate/choose-a-path). Be honest with yourself ## What you give up and known gaps - bcrypt and argon2 are not bundled. You pass a verifier such as bcryptjs. Without one, those users reset on first login. - Firebase scrypt is not supported. Those users reset their password. - The theauth migrate CLI works with SQLite. For Postgres or MySQL, call importUsers from a script with your own migration store. - Keycloak OTP and WebAuthn credentials are not imported, so users enroll again. - Clerk exports carry no social connections. Users reconnect on their first social sign-in. - Sessions and tokens issued by theAuth stay valid until they expire after a rollback. Revoke them if you need them gone. Rollback Set percent to 0 and every user and route goes back to the incumbent on the next request. It overrides the allowlist, rules and per-route cutover. Test the switch in staging before you need it. See [Pick a migration path](https://docs.theauth.dev/migrate/choose-a-path) for how each path undoes. Next ## Pick your path Start with the guide that matches how much risk you can take. Compare how theAuth differs from your current provider on the [compare pages](https://theauth.dev/compare/), or read the [full migration docs](https://docs.theauth.dev/migrate/). - [Pick a migration path](https://docs.theauth.dev/migrate/choose-a-path) - [Run both and migrate](https://docs.theauth.dev/migrate/run-both-and-migrate) - [Import users](https://docs.theauth.dev/migrate/import-users) --- URL: https://theauth.dev/open/ Open # What we publish, and where theAuth is MIT licensed and developed in public. This hub summarizes the documents that describe how it is maintained, versioned, released and threat-modeled, and links each summary to the full text on GitHub. Latest Go release: v2.7.1. TypeScript core: 0.5.0, pre-1.0. [API stability](https://theauth.dev/open/stability/) [Vulnerability disclosure](https://theauth.dev/security/) ## Sources and review date **Source**Last reviewed 2026-10-06 Six documents ## Read the summary, then the source Each page is a short, hand-written summary with a visible source link and review date. None of them replaces the document it points to. **Transparency hub**Six pages - [Security practices and disclosure](https://theauth.dev/security/) - [Benchmarks](https://theauth.dev/benchmarks/) - [TypeScript repository](https://github.com/glincker/theauth) - [Go repository](https://github.com/glincker/theauth-go) How to read these pages ## Summaries, not copies Values that change, such as the latest release and the review dates, come from one data file in this site and carry an as-of date. If a summary and a source document ever differ, the document wins. - Go libraryDocuments live under docs/ in [theauth-go](https://github.com/glincker/theauth-go), plus CHANGELOG.md, GOVERNANCE.md and MAINTAINERS.md at the root. - TypeScript[theauth](https://github.com/glincker/theauth) publishes governance, maintainers, support, security and changelog files at the root. It has no roadmap or threat model file. - DisclosureReporting a vulnerability is covered on [the security page](https://theauth.dev/security/) and in each repository's SECURITY.md. This hub does not repeat it. ## What this hub does not claim - **No certifications.** There is no SOC 2, ISO or other certificate, and no third-party audit is published. - **No release schedule.** The release process is documented. A cadence is not promised. - **No TypeScript stability guarantee.** The core package is pre-1.0, so minor versions can break. ## Related pages - [Roadmap](https://theauth.dev/open/roadmap/) - [Stability](https://theauth.dev/open/stability/) - [Threat model](https://theauth.dev/open/threat-model/) - [Governance](https://theauth.dev/open/governance/) - [Releases](https://theauth.dev/open/releases/) - [Compliance](https://theauth.dev/open/compliance/) - [Security and disclosure](https://theauth.dev/security/) --- URL: https://theauth.dev/open/compliance/ Compliance # Reports, not certifications theauth-go publishes a mapping of library behavior to SOC 2 criteria and a GDPR engineering reference for operators. No third-party audit is published, and nothing here says any deployment is compliant or certified. [SOC 2 mapping](https://docs.theauth.dev/go/security/compliance-soc2) [GDPR reference](https://docs.theauth.dev/go/security/compliance-gdpr) ## Sources and review date **Source**Last reviewed 2026-10-06 SOC 2 ## A mapping, not an attestation The document maps library behavior to the AICPA Trust Services Criteria. The maintainers wrote it. No auditor has reviewed it. - CoverageCommon criteria CC1 to CC9, plus availability, confidentiality, processing integrity and privacy. - Per criterionWhat the criterion asks for, how theauth-go helps, and what the operator must implement. - Often not addressableSome criteria, such as board oversight and hiring, cannot be satisfied by a library. The document says so. - Closing sectionA list of what theauth-go does not provide. - RolesThe operator is the data controller. theauth-go is a library with no data processing infrastructure of its own, and its authors are not a sub-processor. - Data inventoryThe personal data the built-in storage adapters hold by default, such as email, name, session IP and user agent, and credential hashes. - Rights and retentionHow to satisfy data subject rights, retention considerations, data residency and cross-border transfers. - Defaults and checklistPrivacy-by-design defaults, and a checklist for the operator. GDPR ## An engineering reference It is not legal advice and not a statement that any deployment is GDPR compliant. ## What we do not claim - **No certifications.** theauth-go is not SOC 2 certified or audited. There is no ISO certificate. - **No third-party audit is published.** Nothing on this site presents an auditor's report. - **No deployment-level claims.** An examination covers an operator's whole system. These documents cover one library's contribution. - [Security practices](https://theauth.dev/security/) - [GDPR docs](https://docs.theauth.dev/gdpr) - [Compliance docs](https://docs.theauth.dev/compliance) ## Related pages - [Roadmap](https://theauth.dev/open/roadmap/) - [Stability](https://theauth.dev/open/stability/) - [Threat model](https://theauth.dev/open/threat-model/) - [Governance](https://theauth.dev/open/governance/) - [Releases](https://theauth.dev/open/releases/) - [Open hub](https://theauth.dev/open/) - [Security and disclosure](https://theauth.dev/security/) --- URL: https://theauth.dev/open/governance/ Governance # How decisions get made theAuth is maintained by GLINCKER, the open-source division of GLINR STUDIOS. Both repositories publish a governance file. No individual maintainers are named; contact is support@glinr.com. [Go GOVERNANCE.md](https://github.com/glincker/theauth-go/blob/main/GOVERNANCE.md) [TypeScript GOVERNANCE.md](https://github.com/glincker/theauth/blob/main/GOVERNANCE.md) ## Sources and review date **Source**Last reviewed 2026-10-06 Who ## Maintainers and contributors Maintainers act for GLINR STUDIOS. Anyone can contribute. - MaintainersReview and merge pull requests, triage issues and discussions, manage releases, and handle private security reports. - ContributorsAnyone who opens an issue or discussion, sends a pull request, or improves docs, tests and examples. - Named peopleNone. Maintainer files describe responsibilities by role. - Routine changesBug fixes, docs, tests and non-breaking additions are decided in pull request review by a maintainer. - Larger changesOpen an issue or GitHub Discussion first. State the compatibility impact. A maintainer agrees to the direction, then the pull request is reviewed like any other. New behavior needs tests. - Breaking changesHandled under the rules on the [stability page](https://theauth.dev/open/stability/). Decisions ## Small changes fast, big changes discussed The two repositories describe the same shape of process. Releases, conduct, joining ## Around the edges - ReleasesDocumented on the [releases page](https://theauth.dev/open/releases/). The Go governance file says the project does not publish a release schedule. - Security and conductVulnerabilities are reported privately as described on the [security page](https://theauth.dev/security/). Community behavior follows each repository's code of conduct. - Becoming a maintainerThe Go repository defines no formal process yet and asks you to say so in a discussion or write to support@glinr.com. The TypeScript repository says maintainers are invited based on sustained, high-quality contributions. - Contactsupport@glinr.com for anything that does not fit a public channel. Questions and ideas go to GitHub Discussions, and bugs to GitHub issues. ## What we do not claim - **No foundation or steering committee.** The project is maintained by a company team, as stated. - **No named maintainers.** Roles and a contact address only. ## Related pages - [Roadmap](https://theauth.dev/open/roadmap/) - [Stability](https://theauth.dev/open/stability/) - [Threat model](https://theauth.dev/open/threat-model/) - [Releases](https://theauth.dev/open/releases/) - [Compliance](https://theauth.dev/open/compliance/) - [Open hub](https://theauth.dev/open/) - [Security and disclosure](https://theauth.dev/security/) --- URL: https://theauth.dev/open/releases/ Releases # How a release is cut Latest Go release: v2.7.1, published 2026-10-07. TypeScript core: 0.5.0. The process is documented below. No release cadence is promised. [Read RELEASING.md](https://github.com/glincker/theauth-go/blob/main/docs/RELEASING.md) [Go releases](https://github.com/glincker/theauth-go/releases) ## Sources and review date **Source**Last reviewed 2026-10-06 Go ## From changelog to signed release Steps as RELEASING.md describes them. - 1. ChangelogMove entries into a dated section with upgrade notes first, through a pull request. - 2. TagCreate a signed, annotated tag on the merged default branch and push it. That triggers the release workflow. - 3. WorkflowRuns go mod tidy and the tests as a gate, builds a source archive, generates a CycloneDX SBOM, signs artifacts with cosign keyless signing, creates the GitHub Release and generates a SLSA provenance attestation. - 4. VerifyThe document shows how to check signatures with cosign verify-blob and the attestation with gh attestation verify. - 5. Sub-modulesstorage/sqlite, mcpresource and audit/sinks/otlp are tagged with a directory prefix, after the root is available through the Go module proxy. - Module pathThe root module is github.com/glincker/theauth-go/v2. Tags v2.0.0 to v2.5.0 were never resolvable by the Go toolchain; the first resolvable tag is v2.6.0. - Pre-releasesTags with an alpha, beta or rc suffix are published as pre-releases automatically. - RollbackDelete the tag and the GitHub Release, fix the issue and cut a new patch release. A published version number is never reused. - ScheduleNone. The Go governance file says the project does not publish a release schedule. Rules ## Module path, pre-releases, rollback TypeScript ## Changesets, per package TypeScript packages are versioned independently with Changesets. The maintainer checklist checks changeset status and bump classes, runs build, typecheck and tests, generates versions, reviews the output, publishes through CI or pnpm release per policy, and verifies npm metadata and installability. That checklist does not list signing or SBOM steps. The ones above are documented for the Go module. Version lines and what they mean for stability are on the [stability page](https://theauth.dev/open/stability/). Per-release notes: [GitHub Releases](https://github.com/glincker/theauth/releases). ## What we do not claim - **No release cadence.** Releases ship when they are ready, not on a calendar. - **No signing claims for TypeScript.** Only the Go release process documents signatures, an SBOM and provenance. ## Related pages - [Roadmap](https://theauth.dev/open/roadmap/) - [Stability](https://theauth.dev/open/stability/) - [Threat model](https://theauth.dev/open/threat-model/) - [Governance](https://theauth.dev/open/governance/) - [Compliance](https://theauth.dev/open/compliance/) - [Open hub](https://theauth.dev/open/) - [Security and disclosure](https://theauth.dev/security/) --- URL: https://theauth.dev/open/roadmap/ Roadmap # Roadmap, as written A summary of the Go roadmap file: recent releases, work in flight, and what is only under consideration. It lists no dates and commits to nothing beyond what it says. The latest Go release is v2.7.1, published 2026-10-07. [Read ROADMAP.md](https://github.com/glincker/theauth-go/blob/main/docs/ROADMAP.md) [Go changelog](https://github.com/glincker/theauth-go/blob/main/CHANGELOG.md) ## Sources and review date **Source**Last reviewed 2026-10-06 Shipped ## Recent Go releases The roadmap calls the changelog the authoritative record of what shipped, and itself the forward-looking part. - v2.7.1OAuth redirect URI configuration and validation with the OAuthStart and OAuthCallback entry points, default logs without email addresses, admin password reset clearing login backoff entries, a WebAuthn user handle resolver, and the legacy-hash callback now being invoked. - v2.6.0The module path became github.com/glincker/theauth-go/v2, since earlier v2.x tags never resolved through the Go toolchain. Also login throttling on by default, JSON error bodies, a path prefix option, storage capability interfaces, the SQLite adapter and an internal/ package split. It has upgrade notes to read first. - v2.5.0The full lifecycle hooks surface, a fix for hooks being bypassed by Mount(), and a batch of storage-layer correctness fixes. - Selective re-exportsLetting consumers import fewer symbols from the root package (issue #79, open). The v2.6.0 aliases keep existing names working but are not the selective re-exports that issue asks for. - Stability hardeningIn progress. The roadmap lists further unit-test coverage for the RBAC and WebAuthn internals and other hardening work. The full list is in the document. In flight ## What is being worked on Items are checkboxes in the file and are pruned as they land. Under consideration ## Nothing else is committed The file says feature requests and discussion happen in GitHub Discussions, and that raised items are added once there is a concrete plan. The roadmap does not give dates, and neither does this page. For the exact wording and the complete in-flight list, read [ROADMAP.md](https://github.com/glincker/theauth-go/blob/main/docs/ROADMAP.md). To raise something, use [Go Discussions](https://github.com/glincker/theauth-go/discussions). ## What is not here - **No TypeScript roadmap.** The TypeScript repository has no roadmap file; what shipped is in its [changelog](https://github.com/glincker/theauth/blob/main/CHANGELOG.md) and [GitHub Releases](https://github.com/glincker/theauth/releases). - **No dates.** Neither roadmap promises delivery dates. ## Related pages - [Stability](https://theauth.dev/open/stability/) - [Threat model](https://theauth.dev/open/threat-model/) - [Governance](https://theauth.dev/open/governance/) - [Releases](https://theauth.dev/open/releases/) - [Compliance](https://theauth.dev/open/compliance/) - [Open hub](https://theauth.dev/open/) - [Security and disclosure](https://theauth.dev/security/) --- URL: https://theauth.dev/open/stability/ API stability # What is stable, and what is not The Go module follows strict Semantic Versioning, and the document says exactly what counts as public API. The TypeScript core is pre-1.0 at 0.5.0 and carries no stability guarantee yet. Go latest: v2.7.1. [Read the stability policy](https://docs.theauth.dev/go/reference/stability) [How releases work](https://theauth.dev/open/releases/) ## Sources and review date **Source**Last reviewed 2026-10-06 Go module ## Strict SemVer From v1.0 the module follows Semantic Versioning strictly. The import path is github.com/glincker/theauth-go/v2. - BreakingChanging a stable symbol's signature, name or documented behavior contract requires a new major version. - AdditiveNew exported symbols, new optional Config fields and new methods on `*TheAuth` are non-breaking. - DeprecationAnnounced one minor version before removal with a // Deprecated: godoc line. - Not publicAnything under internal/, anything under examples/, test helpers, and the audit writer internals. Surface ## Stable and experimental packages The document lists stable symbols per package. In summary: **Go packages**As of 2026-10-06 Stable Experimental, may change in a minor release - Storage interfaceAdding a method to Storage would break implementers, so new persistence operations land behind separate optional interfaces, detected at runtime. The base interface only grows in a major release. - MigrationsPostgres and MySQL migrations are append-only. A rename ships as a new migration that adds the new column. - Audit tableaudit_events is append-only by contract. Adapters expose insert and query, not update or delete. - Stats countersExisting Stats counters keep their name and meaning. New fields are allowed. - Without a majorBug fixes, performance work that keeps outputs, new optional config, new error sentinels and codes, and new audit actions. Special rules ## What the document pins down These rules exist so a minor upgrade does not break people who implement or depend on the interfaces. TypeScript ## Pre-1.0, no guarantee yet Said plainly: the TypeScript packages are not under a stability guarantee. The core package @glinr/theauth is at 0.5.0. The repository's maintainer guide says packages are versioned independently with Changesets and that most are pre-1.0, so minor bumps may include breaking changes, which are called out in the changeset. Its security policy gives the supported release line per package, and security fixes go to the latest line only. Pin versions and read release notes before upgrading. See [SECURITY.md](https://github.com/glincker/theauth/blob/main/SECURITY.md) for the current table. ## What we do not claim - **No guarantee for TypeScript.** Until 1.0, treat every minor release as possibly breaking. - **No guarantee for experimental Go APIs.** They are labeled experimental in the document for a reason. ## Related pages - [Roadmap](https://theauth.dev/open/roadmap/) - [Threat model](https://theauth.dev/open/threat-model/) - [Governance](https://theauth.dev/open/governance/) - [Releases](https://theauth.dev/open/releases/) - [Compliance](https://theauth.dev/open/compliance/) - [Open hub](https://theauth.dev/open/) - [Security and disclosure](https://theauth.dev/security/) --- URL: https://theauth.dev/open/threat-model/ Threat model # Threats, scoped honestly The Go threat model uses STRIDE and covers the library as deployed by an operator in a Go HTTP application. It is a design document, not an audit report or a certification. The document states it was last reviewed against v2.7.0. [Read the threat model](https://docs.theauth.dev/go/security/threat-model) [Disclosure policy](https://theauth.dev/security/) ## Sources and review date **Source**Last reviewed 2026-10-06 Trust boundaries ## Where data crosses a line The document lists seven boundaries. Each is analyzed per component with a mitigation and a residual risk. Trust boundaries in the Go threat model | Boundary | What crosses it | Direction | | --- | --- | --- | | HTTP network | OAuth and OIDC protocol messages: authorize, token, introspect, JWKS | Inbound | | HTTP network | Provider OAuth callbacks (GitHub, Google, Apple and others) | Inbound | | Process and database | SQL queries and responses | Both ways | | Process and SIEM | Audit events forwarded to OTLP, Splunk or webhook sinks | Outbound | | Process and email | Magic link and password reset emails | Outbound | | HTTPS to identity providers | Client identity metadata document fetches | Outbound, HTTPS only | | Process memory | Ed25519 signing keys | In process only | Scope ## What is analyzed Components in scope, per the document: - Token issuingThe authorization server (authorization code, refresh token, client credentials and token exchange grants) and the resource server validator in mcpresource. - PersistenceMemory, Postgres, MySQL and SQLite storage backends behind the Storage interface. - Sign-in flowsPassword, social OAuth, magic link, WebAuthn, TOTP, SAML and SCIM. - Supporting systemsAudit subsystem, sessions, agent identity, delegation chains, client identity metadata documents and RBAC. ## Out of scope: the operator owns these - **TLS termination and certificates.** The library warns at startup when cookies are not Secure over non-https, but cannot enforce transport security. - **Secrets at rest.** Encryption keys are supplied by the operator. The library has no secret store. - **Infrastructure isolation.** Containers, VMs, Kubernetes policies and kernel security modules. - **Authentication device security.** A compromised TOTP app, stolen WebAuthn key or compromised phone. - **Network-layer flood protection.** The library provides application-layer limits, not TCP or UDP flood defense. - **Runtime side channels.** Constant-time comparisons are used, but Go runtime behavior cannot be guaranteed. - TokensBearer theft and replay, replay across resources, PKCE downgrade, refresh token replay, JWKS rotation races. - AuthorizationCode injection, open redirect, CSRF on authorize, delegation scope escalation. - Sessions and sign-inSession fixation, cookie theft, provider OAuth state CSRF, MFA bypass on identity merge, WebAuthn replay, SAML signature wrapping. - OperationsAudit log tampering, client authentication cache poisoning, SCIM token reuse, webhook signature forgery, client identity trust policy. Catalog ## Numbered threats with a status each The catalog is a table of numbered entries (T-01 onward). Each has a status, such as mitigated, partially mitigated, or operator responsibility. High-level groups: Reading it ## Some mitigations are opt-in A mitigation can depend on a setting. For example, requiring state on /authorize is off by default and should be enabled in production, as the [security page](https://theauth.dev/security/) also says. The per-component sections give each threat a mitigation and a residual risk, so you can see what you must configure yourself. The full catalog, including every status, is in [threat model](https://docs.theauth.dev/go/security/threat-model). Read it rather than this summary when you assess a deployment. To report a vulnerability, use the process on [the security page](https://theauth.dev/security/). ## Related pages - [Roadmap](https://theauth.dev/open/roadmap/) - [Stability](https://theauth.dev/open/stability/) - [Governance](https://theauth.dev/open/governance/) - [Releases](https://theauth.dev/open/releases/) - [Compliance](https://theauth.dev/open/compliance/) - [Open hub](https://theauth.dev/open/) - [Security and disclosure](https://theauth.dev/security/)