# AgentID: full text > Every public AgentID document in one file: the product overview, the homepage FAQ, the security and integration reference, and all long-form posts. Each document below starts with a level-one heading and is separated by a horizontal rule. - **Site:** https://www.agentid.com - **Index:** https://www.agentid.com/llms.txt - **Generated:** at build time from the same sources the site renders --- # AgentID > AgentID is the sign-in button for AI agents. It gives every agent its own verified identity, backed by a real email address, so agents can sign in to apps without borrowing their owner's account. Apps that add AgentID always know which human is behind each agent. AgentID is a product of AgentMail (YC S25). It is a standard OpenID Connect provider designed specifically for AI agents. Any app that already accepts Sign in with Google can accept AgentID with two configuration values and no code changes. ## The problem AgentID solves AI agents today sign into apps using their owner's credentials. Apps receiving agent signups today have no way to tell whether hundreds of new accounts represent one person's agent fleet or many real customers. This creates three problems: 1. Apps cannot distinguish real customers from agent-created noise 2. Apps cannot enforce per-human rate limits, seat caps, or tiers 3. Apps with compliance obligations cannot verify the human behind an agent's actions AgentID solves all three by passing a verified `owner_email` claim to registered apps on every sign-in. ## How AgentID works When an agent signs in to an app that supports AgentID: 1. The agent clicks "Sign in with AgentID" on the app's login page 2. The agent authenticates against auth.agentid.com using OpenID Connect 3. The app receives an id_token containing the agent's identity: `sub` (stable subject), `email` (verified inbox address), and `email_verified` 4. If the app is a registered client and asked for the owner scopes, the id_token also carries the human owner's name and email (`owner_name`, `owner_email`), with `owner_email_verified: true` alongside `owner_email`. If the owner verified with World ID, `owner_profile` also adds `owner_human_verified: true` and `owner_human_id`, an identifier for that person that is the same across every agent they own and different in every app. `/userinfo` returns the same values with the access token. The signing key never leaves the browser that generated it. Each sign-in is a fresh signature over a one-time challenge. Owner scopes also need the `App: Share Owner` permission on the agent's AgentMail API key; without it, the agent can't finish the sign-in alone and the organization owner has to approve it. ## Client tiers **Open clients** need no registration. The `client_id` is a URL the app controls. Open clients get the `openid`, `email` and `profile` scopes. **Registered clients** are created in the AgentID console or with `npx @agentmail/agentid-cli init`. Registered clients get a client secret, up to 10 redirect URIs, and access to the `owner_profile` and `owner_email` scopes. ## Integration Clerk ships AgentID as a built-in SSO connection (strategy `oauth_agentid`). AgentID also works as a custom OpenID Connect provider in Supabase, Auth0, Descope, and Auth.js v4. Better Auth apps instead install `@agentmail/agentid-better-auth`, an AgentMail-maintained provider helper for Better Auth's Generic OAuth plugin (Better Auth 1.7.2 or later). Run `npx @agentmail/agentid-cli init` from an existing app for browser-authorized registration and supported provider configuration. For apps that implement OIDC directly, the issuer is `https://auth.agentid.com`. Discovery, JWKS, PKCE with S256, and standard authorization code flow are all supported. Tokens are signed with ES256. ## Comparison to related products - **Microsoft Entra Agent ID and Google Cloud Agent Identity**: enterprise IAM for agents inside one company's ecosystem. AgentID works across any app on the open web. - **Auth0 for AI Agents (Okta)**: enterprise identity for agents inside customer applications. AgentID is a public identity provider, closer to Sign in with Google in scope. - **Arcade**: focused on what agents can DO (permissions on actions), not who they ARE at sign-in. Complementary to AgentID. - **WorkOS auth.md**: a protocol apps host describing how agents can register. AgentID can serve as an identity provider inside auth.md's verified flow. - **Stripe Projects**: identity plus payments inside the Stripe ecosystem. AgentID is domain-agnostic. ## Key documents - [How it works](https://www.agentid.com/#how-it-works): The sign-in flow - [Security](https://www.agentid.com/security): Cryptographic details, trust boundaries, and revocation model - [FAQ](https://www.agentid.com/#faq): Common questions from agent owners - [Developer docs](https://www.agentid.com/docs): Full OIDC specification, endpoints, scopes, and token claims - [CLI quickstart and troubleshooting](https://www.agentid.com/docs/cli): Detect, register, configure, verify, recover, unlink, and unregister AgentID from a project - [Browser sessions](https://auth.agentid.com/sessions): Inspect and forget AgentID sessions saved in the current browser - [Brand](https://www.agentid.com/brand): Logo assets and usage guidelines for Sign in with AgentID - [Get started](https://console.agentmail.to/sign-up): Create an AgentMail inbox to get an AgentID ## About the makers AgentID is a product of AgentMail (YC S25), the email infrastructure for AI agents. AgentMail provides programmatic inbox creation, send/receive functionality, webhooks, multi-tenant isolation, and scoped API keys. AgentMail is available at https://www.agentmail.to and its docs at https://docs.agentmail.to. ## Terminology - **Agent**: an AI system that acts on behalf of a human, often with its own credentials and identity - **Agent ID**: a general term for a unique identifier that lets an agent authenticate as a distinct entity - **AgentID** (one word, capitalized): the specific OpenID Connect provider built by AgentMail - **Owner**: the human who owns and is accountable for an agent's actions - **Relying party (RP)**: an app that accepts AgentID sign-ins - **owner_email**: the verified email address of the human behind an agent, passed to registered apps --- # AgentID homepage FAQ > The questions the homepage answers, at https://www.agentid.com/#faq. ## What is AgentID? AgentID lets apps authenticate AI agents with verified, email-based identities instead of using your account. ## How does my agent get one? Create an inbox for the agent with AgentMail. That inbox becomes its email identity and AgentID. ## What is AgentMail? AgentMail gives AI agents their own email inbox and identity, so they can send, receive, and manage email. ## Is this like Sign in with Google? Yes. It uses the same sign-in, but the identity is your agent’s, not your Google account. ## Do I have to approve each sign-in? No. Your agent signs in independently. You control credentials and can revoke sign-in rights. ## Can an app read my agent’s email? No. Sharing the agent’s email address identifies the agent; it does not grant access to read or send its email. ## Can I use the app alongside my agent? If the app supports teams, the agent can invite you to a shared workspace with distinct roles. ## How does the app know who owns the agent? AgentMail verifies the owner. AgentID shares verified name and email for limits or contact. --- # Security > How AgentID mints, signs, and scopes identities: non-exportable KMS keys, published JWKS, single-use codes, tenant-scoped tokens, and live re-verification. - **URL:** https://www.agentid.com/security - **Last updated:** 2026-10-06 Read the full page at https://www.agentid.com/security. --- # Docs > The AgentID docs on one page: the CLI quickstart, provider guides, human owner scopes, the signup limit per owner, every endpoint, scope, token claim and lifetime, and how an agent completes a sign-in. - **URL:** https://www.agentid.com/docs - **Last updated:** 2026-10-19 Read the full page at https://www.agentid.com/docs. --- # Docs: open clients > Accepting AgentID sign-ins without registering a client: a URL you control as the client_id, then the authorization request and token exchange by hand. - **URL:** https://www.agentid.com/docs/open-clients - **Last updated:** 2026-09-21 Read the full page at https://www.agentid.com/docs/open-clients. --- # Docs: AgentID CLI > Detect an auth provider, register AgentID in the browser, configure the project and verify the result from one CLI flow. - **URL:** https://www.agentid.com/docs/cli - **Last updated:** 2026-09-16 Read the full page at https://www.agentid.com/docs/cli. --- # Docs: Clerk > Accepting AgentID sign-ins in a Clerk application. - **URL:** https://www.agentid.com/docs/clerk - **Last updated:** 2026-09-21 Read the full page at https://www.agentid.com/docs/clerk. --- # Docs: Supabase > Accepting AgentID sign-ins in a Supabase project. - **URL:** https://www.agentid.com/docs/supabase - **Last updated:** 2026-10-19 Read the full page at https://www.agentid.com/docs/supabase. --- # Docs: Auth0 > Accepting AgentID sign-ins through an Auth0 social connection. - **URL:** https://www.agentid.com/docs/auth0 - **Last updated:** 2026-09-21 Read the full page at https://www.agentid.com/docs/auth0. --- # Docs: Descope > Accepting AgentID sign-ins through Descope’s built-in AgentID social login provider. - **URL:** https://www.agentid.com/docs/descope - **Last updated:** 2026-10-21 Read the full page at https://www.agentid.com/docs/descope. --- # Docs: Better Auth > Accepting AgentID sign-ins with the Better Auth provider helper. - **URL:** https://www.agentid.com/docs/better-auth - **Last updated:** 2026-10-19 Read the full page at https://www.agentid.com/docs/better-auth. --- # Docs: Auth.js > Accepting AgentID sign-ins in an Auth.js v4 application. - **URL:** https://www.agentid.com/docs/auth-js - **Last updated:** 2026-08-25 Read the full page at https://www.agentid.com/docs/auth-js. --- # Docs: WorkOS > Why AgentID cannot be added to WorkOS AuthKit yet (no custom social provider; generic OIDC is org-scoped enterprise SSO), and a form to be notified when it can. - **URL:** https://www.agentid.com/docs/workos - **Last updated:** 2026-10-05 Read the full page at https://www.agentid.com/docs/workos. --- # Docs: your own stack > Implementing AgentID directly against the OIDC endpoints. - **URL:** https://www.agentid.com/docs/custom - **Last updated:** 2026-10-19 Read the full page at https://www.agentid.com/docs/custom. --- # Docs: integration FAQ > What app developers ask before adding AgentID: what it is, why integrate, what integration takes, who owns the agent, and what it costs. - **URL:** https://www.agentid.com/docs/faq - **Last updated:** 2026-10-02 Read the full page at https://www.agentid.com/docs/faq. --- # AgentID Is Now Available for Descope > Add AgentID to Descope as a custom OAuth provider: the setup guide, the integration prompt for coding agents, and what your app learns about each agent and its owner. - **Author:** Binoy Perera - **Date:** 2026-10-15 - **Category:** Blog - **URL:** https://www.agentid.com/blog/agentid-for-descope Descope-powered apps can now accept Sign in with AgentID. The [setup guide](/docs/descope) is live: one discovery URL, a client ID and a few settings, with your own sign-in button. Agents arrive with a stable identifier and a verified email address, and apps that register learn the name and email of the human who owns each agent. Free for apps, and the fastest route is handing the [integration prompt](/) to your coding agent. Descope is the latest platform where AgentID, the sign-in for AI agents from AgentMail, works as a custom OAuth provider. The [Descope guide](/docs/descope) went live this week and walks the whole setup: the discovery URL, every connection field, the client types, the defaults to change, and the verification steps for your first real sign-in. If your app runs its sign-in through Descope, this means an AI agent can now create its own account in it, with its own verified email address, instead of borrowing its owner's credentials. And because AgentID is plain OpenID Connect, the same tech as Sign in with Google, adding it is configuration, not code. ## What does your Descope app learn about each agent? Every sign-in delivers a stable `sub`, the agent's account key, which stays the same across every app the agent signs in to. The `email` claim is the agent's own inbox, verified at mint time, and it is a real working mailbox: onboarding, receipts, invoices and support replies all reach the agent directly, and it can read and answer them. Apps that [register an application](/docs/descope) can also request the owner scopes and receive `owner_name` and `owner_email`, the human behind the agent, in the id_token and from `/v0/userinfo`. That is what makes agent traffic governable: you can rate-limit, allowlist and ban per owner rather than per account, and cap signups per owner in the [console](https://console.agentid.com/sign-up). The full claim reference is in the [docs](/docs). AgentID is free for apps, with no per-sign-in fees. ## How do you add it? The shortest path is the integration prompt on [agentid.com](/): paste it into your coding agent, and it reads the machine-readable reference and runs the CLI for you. By hand, the same two steps are: ```bash npx @agentmail/agentid-cli init ``` The [CLI](/docs/cli) collects your application name and callback URLs, registers the application and stores its credentials. It cannot edit connectors it does not recognize, so you finish the Descope side yourself: create a custom OAuth provider with discovery pointed at `https://auth.agentid.com/.well-known/openid-configuration`, the `openid email profile` scopes, and PKCE on with S256. The [Descope guide](/docs/descope) lists every field value, including what goes in Client ID and Client secret for each client type. No registration is needed to start: an [open client](/docs/open-clients) uses an https URL you control as its `client_id`, with no secret and no setup. Register when you want the owner scopes. For the button itself, the label is Continue with AgentID, one word, never shortened and never AgentMail. [Adding a Sign in with AgentID button](/blog/adding-a-sign-in-with-agentid-button) covers the design side, and the official marks are on the [brand page](/brand). Flows that start the sign-in without a visible button use an initiate login URI; the [guide](/docs/descope) covers its requirements too. ## Which defaults should you change before the first test? Four settings in a typical custom OAuth connector do not match what AgentID issues, and the [guide](/docs/descope) walks each one:
Setting AgentID The usual default
id_token signing ES256 only RS256, which rejects valid tokens with a signature error
Response type code only Implicit and hybrid flows are rejected
PKCE S256 only Plain or missing challenge fails
Refresh tokens None; tokens last 10 minutes Requesting offline_access gets you nothing
One timing detail is worth knowing before it bites: an agent sign-in has no password form. The browser lands on an AgentID waiting page, the sign-in can take up to five minutes, and the authorization code then lasts sixty seconds. Keep `state` and the PKCE verifier for at least ten minutes, or the callback fails with a mismatch that looks like an attack. After the first approval, agents pass straight through for 180 days. The [guide](/docs/descope) covers the whole wait, and [how an agent proves its identity](/blog/how-an-ai-agent-proves-its-identity-to-your-app) explains what happens on that page. ## Where does this fit? One name to keep straight: this is about accepting AgentID sign-ins in a Descope-powered app. Descope also builds its own agent identity product, and [AgentID vs Descope Agentic Identity](/blog/agentid-vs-descope-agentic-identity) covers how the two differ. Descope joins [Clerk](/docs/clerk), [Supabase](/docs/supabase), [Auth0](/docs/auth0), [Better Auth](/docs/better-auth) and [Auth.js](/docs/auth-js) in the provider guides, and [any OIDC stack](/docs/custom) works directly against the endpoints. Apps already accepting agent sign-ins are in the [directory](/directory). If you ship it, tell us; we link to apps that let agents in. --- # Introducing AgentID > AgentID is live. Agents sign in to apps as themselves, apps learn which human is behind them, and integration takes minutes. - **Author:** Haakam Aujla - **Date:** 2026-10-06 - **Category:** Blog - **URL:** https://www.agentid.com/blog/introducing-agentid - AgentID is live. It is the sign-in button for AI agents, from AgentMail. - Agents sign in as themselves, with their own verified identity, and your app always knows which human owns them. - 10 million agents can find you. Every AgentMail inbox is an AgentID, and agents go looking for apps that accept it. - It takes minutes. Standard OpenID Connect, so it drops into Clerk, Supabase, Auth0, Descope, Better Auth, Auth.js or anything else. For a limited time, integrate and you get three months of AgentMail free. {/* TODO: embed the launch video here once the YouTube ID is known. */} ## What is AgentID? AgentID is a sign-in button for AI agents. Think of Sign in with Google, except the thing signing in is an agent, and the identity it uses is its own. Every AgentID is backed by a real email address at AgentMail. That address is the agent's identity: stable, verified every time it signs in, and a working inbox your app can write to. Behind it, always, is the person who owns the agent, and your app gets to know who that is. Every sign-in returns a stable identifier for the agent and its verified email, and registered apps also get the owner's name and email. That is enough to attribute an account to a person, cap signups per owner so ten agents run by one person share one free tier, revoke one agent without touching the rest, and email the agent like any other user. No password crosses the flow, and signing in gives your app no access to the agent's mail. Under the hood it is a standard OpenID Connect provider. If your app already handles Sign in with Google, it can handle Sign in with AgentID. It is configuration, not code, and it is free for apps. Today it launches publicly. Apps that accept AgentID today include Firecrawl, Turso, TinyFish, Manufact, Telnyx and Rho. The full list is in the [directory](https://www.agentid.com/directory). ## Why AgentID matters We run AgentMail, which gives agents their own email inboxes, so we see up close how agents actually get into apps. The honest answer is that they borrow. An agent signs up with its owner's email, reads the verification code out of the owner's inbox, and sometimes types in the owner's card. Then we let agents sign up for AgentMail itself, and saw the other side of it. Hundreds of accounts appeared whose owners had no idea their agent had made one. Most of our support requests started coming from agents. We had a product full of users and no way to say who any of them belonged to. Nothing in anyone's identity stack could answer that. The web assumes a person behind every login. AgentID exists so that assumption can be said out loud: this is an agent, and this is the human it belongs to. Every agent has a human. Someone created it, pays for it, and controls it. Without a way to record that, apps block agents or rate-limit them into uselessness, owners hand over whole accounts because there is nothing smaller to hand over, and when something goes wrong there is nobody on record. The longer argument is in [Every Agent Has a Human](https://www.agentid.com/blog/every-agent-has-a-human). ## How it differs from existing solutions Most existing approaches answer a different question. Bot detection tells you a visitor is not human, but not whose customer it is. API keys let an agent work inside an account a person already opened, so someone still has to do the signing up. Delegated access lets an agent act through its owner's existing account at a service the owner already uses. Signed bot traffic tells you who operates the agent, not which account it belongs to. AgentID answers the account question. The agent gets its own account at your app, with a verified identity and a human owner on record, and your app shows up in the [directory](https://www.agentid.com/directory) where agents already look for services that will have them. Everything above can sit alongside it. ## How to integrate Minutes, in most stacks. AgentID goes where your other sign-in buttons live. There are guides for [Clerk](https://www.agentid.com/docs/clerk), [Supabase](https://www.agentid.com/docs/supabase), [Auth0](https://www.agentid.com/docs/auth0), [Descope](https://www.agentid.com/docs/descope), [Better Auth](https://www.agentid.com/docs/better-auth) and [Auth.js](https://www.agentid.com/docs/auth-js), and a [custom guide](https://www.agentid.com/docs/custom) for anything else. The CLI does it in one command: npx @agentmail/agentid-cli init detects your provider, registers your app, configures it, and verifies the flow. Or paste the prompt below into your coding agent and let it do the work. For a limited time, we are giving apps that integrate three months of AgentMail free. Add it, then email binoy@agentmail.cc and we will turn it on. And if you would like a hand, [book a call](https://cal.com/sidharth-reddy/15min) and we will do it together. --- # AgentID with Clerk: What Breaks and Why > AgentID in Clerk, after setup: fetching owner claims from userinfo, what to store on your user record, disabled connections, and redirect URI mismatches. - **Author:** Binoy Perera - **Date:** 2026-10-01 - **Category:** Guides - **URL:** https://www.agentid.com/blog/agentid-with-clerk-what-breaks-and-why Clerk ships AgentID as a built-in connection, and the first sign-in usually works. What trips teams up comes later: the owner's details are not on the Clerk user, the redirect address stops matching, or the connection was never switched on. This post explains each of those, and what your app should keep on its own user record so the account survives them. You add AI agent sign-in to Clerk by turning on AgentID, the sign-in for AI agents from AgentMail, from Clerk's list of SSO connections. Clerk handles discovery and PKCE; in production you give it your own AgentID application's credentials. After that, the part Clerk does not do for you is the owner: your app fetches the owner's claims from AgentID in its callback and stores them itself. That split surprises people, because everything before it feels automatic. Clerk discovers the endpoints, runs the sign-in and creates a user. The agent's identity arrives, but the details of the human behind it don't show up on the Clerk user, and nothing warns you. The same goes for a few quieter failures: a connection that is configured but disabled, and a redirect address that matched in development and not in production. None of this is hard once you know where to look, and this post is where to look. ## What is left to do after the Clerk guide? After the [Clerk guide](/docs/clerk), two things are left: storing the owner, and deciding which identifier your own records trust. The guide is the setup reference and ends at a working sign-in; the table below maps what people run into after that.
Symptom Cause Fix
The AgentID button does nothing, or the connection is missing from sign-in New Clerk connections start disabled Enable the connection in Clerk
AgentID rejects the redirect The redirect URI on the AgentID application doesn't match Clerk's authorized redirect URI Copy Clerk's value into the application's settings; add one per environment
Owner's name and email are not on the Clerk user Clerk keeps the standard claims; the owner claims are fetched separately Call /v0/userinfo in your callback and store the result
The sign-in waits instead of finishing Owner scopes were requested and the agent's key can't share its owner Nothing on your side; the organization owner approves it
Your own sign-in button doesn't start the flow The button calls a different strategy name Use oauth_agentid, the strategy name of Clerk’s AgentID connection
Two rows in that table are not failures. A sign-in that waits for the organization owner is working as designed, because the app asked for owner data the agent isn't allowed to share alone, and the owner is being asked instead. A disabled connection is simply Clerk's default for anything new. Everything else is a mismatch between two settings that should agree. If you haven't placed the button yet, [adding a Sign in with AgentID button](/blog/adding-a-sign-in-with-agentid-button) covers the design side, including the label to use. ## Why are the owner claims not on the Clerk user? The owner claims are not on the Clerk user because they are not part of what Clerk carries onto its user, even though AgentID delivers them: a registered application that requested the owner scopes receives `owner_name` and `owner_email` in the id_token and from `/v0/userinfo`. On Clerk, the dependable way to get them is to call `/v0/userinfo` from your callback with the access token and store what comes back. Timing matters. The access token lasts 10 minutes and there is no refresh token, so the callback is the moment to fetch, not a background job the next day. The call also re-checks live state on every request, so a revoked key or inbox shows up there rather than being hidden in a stale token. Request only what you need. `owner_sub` comes with the `profile` scope and is enough for per-owner limits. The owner's name and email need the owner scopes, and if the agent's AgentMail API key lacks the App: Share Owner permission, the agent can't finish the sign-in alone; the organization owner approves it from their AgentMail account. Your app never receives a completed sign-in with the requested owner claim quietly missing. ## What should you store on the user record? Store the agent's `sub` as the key, `owner_sub` for anything per owner, and `owner_email` only as a way to reach a person. Your user record is the source of truth for your product, so it should hold the identifiers that don't change underneath it. ```ts // Illustrative. What to keep on your user record after an AgentID sign-in. type AgentAccount = { agentSub: string // AgentID `sub`: the account key, stable across apps ownerSub?: string // with the profile scope: shared by every agent one owner runs ownerEmail?: string // registered apps with the owner_email scope: a contact, not a key agentEmail: string // the agent's own inbox, which your app can write to } ``` `owner_email` alone makes a poor key for three reasons. It only reaches registered applications that asked for it, so part of your agent traffic would have no key at all. It is a real person's address, so every table it keys becomes personal data. And one owner can run many agents, so it can't identify an account on its own. The agent's own email belongs on the record too, for a different reason: your app can write to it. Onboarding, receipts, invoices and support replies all reach the agent directly, and it can read and answer them. `sub` has the opposite properties. It is an opaque 43-character string, stable for the lifetime of the agent's inbox and the same at every app. The one event that changes it is deleting the inbox and recreating the same address, which produces a new `sub`, and your records should treat that as a new agent rather than merge it by email. ## Why does the redirect URI keep failing? The redirect URI fails when the address on the AgentID application and the address Clerk sends stop matching exactly. One common cause is the example subdomain left in place during setup. Another is a second Clerk instance, such as production, with an address the application doesn't list yet. A registered AgentID application accepts up to 10 redirect URIs, so development, staging and production can each have their own entry instead of being swapped back and forth. Changing a redirect URI has one side effect worth planning for: agents who approved your app are asked to approve again, because the [remembered approval](/blog/sso-for-ai-agents-with-openid-connect) is tied to the redirect URI and scopes. The directory lists seven apps accepting AgentID today, Turso among them, and the [AgentID docs](/docs) hold the endpoint and claim reference. On Supabase instead, [AgentID with Supabase Auth](/blog/agentid-with-supabase-auth-what-breaks-and-why) covers the same questions there, and the [AgentID page on AgentMail](https://www.agentmail.to/agentid) covers the agent's side. --- # AgentID with Supabase Auth: What Breaks and Why > AgentID in Supabase Auth after setup: comma-separated scopes, the claims allowlist for owner claims, the free-plan provider limit, and what symptoms mean. - **Author:** Binoy Perera - **Date:** 2026-10-01 - **Category:** Guides - **URL:** https://www.agentid.com/blog/agentid-with-supabase-auth-what-breaks-and-why Adding agent sign-in to Supabase is a short setup, and most of what goes wrong afterwards traces back to four settings: how scopes are typed, what the provider is called, which claims Supabase keeps, and whether the agent may share its owner. This post maps each symptom to its cause, so you can tell a misconfiguration from a sign-in that is working as designed. You add AI agent sign-in to Supabase by registering AgentID, the sign-in for AI agents from AgentMail, as a custom OpenID Connect (OIDC) provider in Supabase Auth. Once that works, the problems people hit come from four settings: the scope format, the provider identifier, the claims allowlist, and the owner permission on the agent's side. None of them breaks the button. That is what makes them easy to miss. A sign-in completes, a user row appears, and only later does someone notice the agent has no name, or that the owner's email the product was built around never arrived. Each of those has a specific cause, and most have a one-line fix. This post walks through them in the order people usually find them, then covers what changes if your app verifies AgentID's tokens itself instead of leaving that to Supabase. ## Why does AgentID work in Supabase but not look the way you expected? AgentID works in Supabase as soon as the provider is enabled, but a working sign-in and the sign-in you designed are not the same thing. The [Supabase guide](/docs/supabase) is the setup reference and gets you to the first; this post covers the gap between the two. Here are the symptoms in one place:
Symptom Cause Fix
Only the agent's ID and email come back The scopes field was left empty, so the issuer fell back to openid email Type the scopes you need, separated by commas
A fourth custom provider can't be added Free Supabase projects allow three custom providers Remove an unused custom provider; the limit is Supabase's, not AgentID's
Your sign-in code can't find the provider The identifier was typed with its prefix, or the code calls a different name The provider is custom:agentid; type only agentid in the field
Owner claims are missing from the user Supabase drops custom claims that are not allowlisted Allowlist owner_sub, owner_name and owner_email
The sign-in waits instead of finishing The app asked for owner data and the agent's key can't share it Nothing on your side; the organization owner approves the sign-in
The allowlist isn't available on a self-hosted instance Supabase Auth older than 2.192.0 Upgrade Supabase Auth
The rest of this post explains the three causes that need more than a one-line fix. If you are still choosing where to put the button, [adding a Sign in with AgentID button](/blog/adding-a-sign-in-with-agentid-button) covers that side. ## Why does Supabase want scopes separated by commas? Supabase wants commas because its scopes field takes a comma-separated list, even though scopes in the OIDC request itself are space-delimited. AgentID's own reference lists them with spaces, which is where the mismatch creeps in. In Supabase, type them with commas. The field matters more than it looks, because an empty one isn't an error. With no scopes, AgentID falls back to `openid email`, so the agent signs in with a stable subject and a verified address and nothing else. There is no `name`, no `preferred_username` and, most importantly for per-owner limits, no `owner_sub`, because all three come with the `profile` scope. A useful starting set for most apps is `openid,email,profile`. Add `owner_profile` and `owner_email` only if the product needs the name and address of the person who owns the agent, because they put a real person's name and address in your database. ## Where did the owner claims go? Supabase threw them away. AgentID sent them, but Supabase keeps only the claims it knows about unless you add the rest to its claims allowlist, and there is no dashboard field for that. It is a one-time call from your server with the service role key, and the [owner claims step in the guide](/docs/supabase) has the exact code. After the next sign-in, the allowlisted claims appear under `user_metadata.custom_claims`. Two details catch people here. The allowlist only keeps what AgentID actually sent, so `owner_sub` still needs `profile`, and `owner_name` and `owner_email` still need the owner scopes. And AgentID omits claims it didn't grant rather than sending them empty, so code that reads these fields should test whether they are present instead of expecting a null. If you run Supabase yourself, the allowlist needs Supabase Auth 2.192.0 or later. On an older version the claims stay missing no matter what you allowlist. ## What does a missing owner claim actually mean? A missing owner claim means one of three things, and only one of them is a bug. The first is an open client: apps that skip registration and use a URL as their client ID never receive the owner's name or email. The Supabase setup creates a registered application, so this usually applies only if someone switched clients. The second is the scopes. If the app didn't request `owner_email`, the token doesn't carry it, and if it didn't request `profile`, there is no `owner_sub` either. The third is the allowlist from the previous section, which is the actual bug. What never happens is a registered app that requested `owner_email` receiving a finished sign-in without it. When the agent's AgentMail API key lacks the App: Share Owner permission, the agent can't finish the sign-in alone, and the organization owner approves it from their AgentMail account. From Supabase's side the sign-in simply takes longer, and when it completes the owner is there. ## What changes if you verify AgentID tokens yourself? If your app verifies AgentID's tokens itself rather than relying on Supabase, it has to accept ES256, because that is the only algorithm the issuer signs with. Libraries that assume RS256 reject valid tokens, which looks like a broken integration and is really a missing setting. The full set of values your library reads is in [SSO for AI agents with OpenID Connect](/blog/sso-for-ai-agents-with-openid-connect). Check the signature against `https://auth.agentid.com/v0/jwks.json`, confirm `iss` is `https://auth.agentid.com`, and confirm `aud` is your exact client ID, which for a registered application is the ID the console issued rather than a URL. The published keys keep stable IDs and an overlap window, so rotation doesn't invalidate tokens in flight. Tokens last 10 minutes, and the full claim list is in the [AgentID docs](/docs). If you are on Clerk as well, the same questions come out differently there, and [AgentID with Clerk](/blog/agentid-with-clerk-what-breaks-and-why) covers that version. For the agent's side of the sign-in, the [AgentID page on AgentMail](https://www.agentmail.to/agentid) explains how an agent gets an identity in the first place. --- # Is the Agent Acting for Itself or on Behalf of a User? > Tell in code whether an AI agent acts for itself or for a user: principal tokens vs delegated access vs workload identity, and what revocation means in each. - **Author:** Binoy Perera - **Date:** 2026-10-01 - **Category:** Guides - **URL:** https://www.agentid.com/blog/is-the-agent-acting-for-itself-or-on-behalf-of-a-user Every request an AI agent makes is either on its own account or on someone else's, and an app can tell which by reading the token rather than guessing. This post shows the check in code, what revoking access means under each model, where workload identity fits in, and who is accountable in each case. An app can tell whether an AI agent is acting for itself or on behalf of a user by reading who the token names as its subject. If the subject is the agent, and the token says it is an agent, the agent is acting for itself; if the subject is a person and the agent only appears as the client holding the token, it is acting on that person's behalf. With AgentID, the sign-in for AI agents from AgentMail, the answer is always the first one. That is a product choice, not a universal rule, and plenty of good systems are built on the second. The difficulty for an app is that both arrive as bearer tokens over the same kind of request, so the distinction has to be read out of the token's claims. Get it wrong and you bill the wrong party, revoke the wrong thing, or hold the wrong person accountable. ## How do you tell the two apart in code? You tell them apart by checking the issuer, the subject and, for AgentID, the `actor_type` claim. The conceptual difference between the models is laid out in [agent owner verification vs end-user authentication](/blog/agent-owner-verification-vs-end-user-authentication), and the vocabulary in the [agent identity terminology explainer](/blog/agent-identity-terminology-explainer); this section is the code. ```ts // Illustrative. Classify a verified identity by what its token says. type Claims = Record function whoIsActing(claims: Claims) { if (claims.iss === 'https://auth.agentid.com' && claims.actor_type === 'agent') { // Principal: the agent is the subject; the owner is a separate claim. return { model: 'agent-as-itself', agent: claims.sub, owner: claims.owner_sub ?? null } } // Anything else: the subject is whoever your identity provider says it is, // usually a person, with the agent visible only as the client. return { model: 'on-behalf-of-subject', subject: claims.sub } } ``` Run a check like this only after the token's signature, issuer and audience have been verified. An unverified claim is only something the sender wrote, and an agent that could set its own `actor_type` could claim to be anything. The AgentID branch holds for every token the issuer mints, because every subject it issues is an agent inbox and `actor_type` is always the literal `"agent"`. The owner, when your app is allowed to see it, travels as a claim beside the agent rather than as the subject. The second branch is deliberately loose. A delegated token names the user, and how it records the agent varies by provider, so check your provider's documentation for the field it uses. ## What does each model mean for revocation? Revocation means cutting off a key in one model and cutting off a grant in the other, and the difference shows up in what else stops working. The table compares the three models an app is likely to meet.
Question Principal (AgentID) Delegate (WorkOS auth.md, Auth0 Token Vault) Workload identity (Google Cloud Agent Identity)
Who is the subject? The agent The user the agent works for The workload running the agent
What credential does the app see? An ES256-signed OIDC id_token A short-lived access token tied to the user A SPIFFE identity and X.509 certificate
What does revoking stop? New sign-ins with that agent's key, at every app; nothing else That grant; revoking the user stops everything the user does Governed by the platform that issued the certificate
Who is accountable? The owner, as a claim registered apps can request The user, who is the account Outside this credential; it names the workload
In the principal model, revoking one agent's key leaves the owner's own accounts and their other agents untouched, but it doesn't sign the agent out of apps it is already in; each app's session runs to its own limit. In the delegate model, the grant is the unit. WorkOS describes the credential auth.md issues as "a scoped access token tied to the user, short-lived and revocable", and Auth0 describes Token Vault handing the agent "a temporary, short-lived access token only when it needs to perform a specific task". Revoking that grant is clean. Revoking the user takes every agent they run with it. ## Where does workload identity fit? Workload identity fits underneath both models, at the infrastructure layer rather than at an app's login page. Google Cloud Agent Identity, generally available since August 2026, gives agents on Google's platform a SPIFFE identity and an X.509 certificate for authenticating to infrastructure. That answers "which workload is calling", which is the right question inside a platform you run. It isn't the question a SaaS app asks when an agent arrives at its sign-up form from outside. The two also fail differently. A workload identity that leaks exposes the infrastructure it was scoped to; an AgentID sign-in key that leaks reaches only that one agent's sign-ins, because each key works only for its own agent. An agent can reasonably hold both: a workload identity for the infrastructure it runs on, and an AgentID for the apps it signs in to. ## Who is accountable in each model? In the principal model the accountable person is the agent's owner, delivered as a claim. Any app that requests `profile` receives `owner_sub`, which every agent with the same owner shares, and a registered app that requests the owner scopes also receives `owner_name` and `owner_email`. If the agent isn't allowed to share its owner, it can't finish that sign-in alone and the organization owner approves it. In the delegate model the accountable person is the user, because the user is the account and the agent borrows their authority. That is the right shape when an agent works inside a person's own tools. Microsoft Entra Agent ID takes a principal approach inside a tenant and records accountability there: "Sponsors provide business accountability for agents, making lifecycle decisions without technical administrative access." Neither model is wrong, and an app can accept both, as long as its code reads which one each token represents. The failure to avoid is treating a delegated token as the agent's own account, or an agent's own sign-in as a person, because limits, bills and bans then land on the wrong party. The claim reference is in the [AgentID docs](/docs), and the agent builder's view of the same choice is on the [AgentID page on AgentMail](https://www.agentmail.to/agentid). --- # Persistent Agent Identity Without Personal Data > Give AI agents a persistent identity across apps without personal data: key on the opaque AgentID sub and owner_sub, and store email only when you need it. - **Author:** Binoy Perera - **Date:** 2026-10-01 - **Category:** Guides - **URL:** https://www.agentid.com/blog/persistent-agent-identity-without-personal-data An app can recognize the same AI agent across sessions and across platforms, and group every agent one person runs, without keeping anyone's email address. This post explains which identifiers stay stable and where, what happens when an agent's inbox is recreated, when storing an email is worth it, and how naming and versioning work for agent identities. An app can give an AI agent a persistent identity without storing personal data by keying its records on two opaque identifiers: the agent's `sub` and its owner's `owner_sub`. With AgentID, the sign-in for AI agents from AgentMail, both are stable, both are the same at every app, and neither contains a name or an address. Most identity systems start from an email address and add a random ID later, which leaves personal data at the center of every table. Agents make that habit more expensive, because a single person can run dozens of them and each one produces history: sign-ins, usage, support threads, abuse reports. The question behind this post is simple. What is the least an app has to store to know it is dealing with the same agent, and the same owner, next week and at the next app? ## What makes an agent identifier persistent? An agent identifier is persistent when the issuer guarantees it doesn't change for the life of the thing it names and doesn't depend on where it is presented. Account IDs that each app invents fail the second test, and email addresses fail quietly on the first, which is part of why [agentic accounts differ from user accounts](/blog/how-agentic-accounts-differ-from-user-accounts). AgentID's `sub` meets both. It is an opaque 43-character subject for the agent's inbox, stable for that inbox's lifetime and identical at every app the agent signs in to. Because the value comes from the issuer rather than from your app, it also survives changes on your side. Moving from one auth platform to another in front of AgentID, or merging two products, doesn't change the `sub` an agent presents. `owner_sub` is its counterpart for the human: an opaque 43-character identifier that every agent with the same owner shares, across apps, arriving with the `profile` scope. ## Which identifiers stay the same across apps and sessions? `sub` and `owner_sub` stay the same across apps and sessions; the other claims describe the agent rather than identify it. Here is how each one behaves:
Identifier Same at every app? Survives recreating the inbox? Personal data? Use it for
sub Yes No; a recreated address gets a new one No, opaque The account key
owner_sub Yes, shared by one owner's agents Belongs to the owner, not to one inbox No, opaque, and can't be matched to AgentMail ids Per-owner limits, history and bans
email Yes The address can return, under a new sub Identifies the inbox and its domain Writing to the agent
preferred_username Yes, built from the address Follows the address As much as the address Display
owner_email Registered apps that request it Belongs to the owner Yes, a person's address Reaching a human
A full history needs only the first two rows. The schema below is a sketch of that, with no column that names anyone: ```sql -- Illustrative. Agent history keyed on two opaque strings. create table agent_accounts ( agent_sub text primary key, -- AgentID sub: stable per inbox, same at every app owner_sub text, -- shared by one owner's agents; null without the profile scope created_at timestamptz not null default now() ); create index agent_accounts_owner on agent_accounts (owner_sub); ``` AgentID omits claims it didn't grant rather than sending them empty, so `owner_sub` is simply absent when the app didn't request `profile`. The column allows null for that reason. ## What happens to the identity when an inbox is recreated? When an agent's inbox is deleted and the same address is created again, AgentID issues a new `sub`. To every app, that is a new agent, even though the address looks identical. That is the right outcome: an address that has been given up and taken again shouldn't inherit the old agent's history, and keying on `sub` rather than the email is what makes that true in your records. The owner side behaves differently. `owner_sub` belongs to the owner rather than to one inbox, so an owner who replaces an agent keeps the same owner identifier, and per-owner limits and history carry over to the new agent. It is also why history keyed on email goes wrong. Two different agents can hold the same address at different times, and an email-keyed table would merge them. A `sub`-keyed table keeps them apart without any extra logic. ## When should you also store the email? Store the agent's email when your product needs to write to the agent, which most do: onboarding, receipts, invoices and support replies all go to its inbox, and the agent can read and answer them. Store `owner_email` when a human needs to be reachable, for abuse or billing, and only if you are a registered application that requested it. What changes when you store either is the kind of data you hold. The opaque identifiers mean nothing outside your system and can't be matched back to AgentMail ids. An email address is personal data about a real inbox or a real person, so it belongs in the columns that need it and nowhere near the keys. Your app can receive the agent's email at every sign-in and still choose not to keep it. ## How do you name and version agent identities? You name an agent with the `name` claim, its display name, which arrives with `profile` and is omitted if none is set, and `preferred_username`, a handle built from the address: `support@acme.agentmail.to` becomes `support_acme-agentmail-to`. There is no version claim. That leaves two honest options for a new version of an agent. Keep the inbox, and the new version signs in with the same `sub`, so every app sees one continuous agent and you track versions yourself. Or give the new version a new inbox, and it gets a new `sub` everywhere, with its own history from its first sign-in. The first suits an agent that improves over time; the second suits one that should start clean. The claim-by-claim reference is in the [AgentID docs](/docs), and [how an AI agent proves its identity to your app](/blog/how-an-ai-agent-proves-its-identity-to-your-app) shows where each claim comes from. For the agent's side, the [AgentID page on AgentMail](https://www.agentmail.to/agentid) covers creating the inbox that anchors all of this. --- # Give Your AI Agent Its Own Identity > Give your AI agent its own identity instead of your login: an AgentMail inbox as its AgentID, its own sign-in key, and you as the owner apps can see. - **Author:** Binoy Perera - **Date:** 2026-09-30 - **Category:** Guides - **URL:** https://www.agentid.com/blog/give-your-ai-agent-its-own-identity Handing an AI agent your password makes every app think the agent is you, and the only way to cut it off is to change your own login. Giving the agent its own identity fixes that: its own inbox, its own sign-in key, and you as a named owner apps can see. This post covers why borrowed logins break, how an agent gets an identity of its own, and what it holds afterwards. Give your AI agent its own identity by giving it its own email inbox and signing it in with AgentID, the sign-in for AI agents from AgentMail, instead of handing it your credentials. The inbox address becomes the agent's identity, and apps that accept AgentID see the agent as itself, with you recorded as the person behind it. If you build agents, you have probably done the shortcut already: paste your login into the agent's environment and let it get on with the job. It works until something goes wrong, and then everything about it is backwards. The app can't tell your actions from the agent's, the agent's mail lands in your inbox, and stopping it means locking yourself out too. This post is for the person building the agent, not the app it signs in to, and it walks from the problem to a working identity and what the agent carries once it has one. ## What goes wrong when an agent uses your login? When an agent uses your login, the app treats you as the customer and the agent as you. It sends the agent's email to you, it records the agent's actions under your name, and the only way to revoke the agent is to change your password. [How an AI agent creates its own account](/blog/how-an-ai-agent-creates-its-own-account) shows the signup side of the alternative; here is the difference in six rows.
Borrowed login Its own AgentID
Who the app thinks the customer is You The agent, with you as its owner
Where the app's email goes Your inbox The agent's own inbox
Whose name is on the agent's actions Yours The agent's own stable identifier
What crosses to the app at sign-in Your password No password and no reusable key
What a leaked credential reaches Your account Only that agent's sign-in
How you cut the agent off Change your password Delete the agent's sign-in key
The last two rows are the ones that bite. A borrowed login gives every agent the blast radius of your whole account, and one misbehaving agent costs you access along with it. ## Is an agent acting on your behalf different from an agent with its own account? Yes: an agent acting on your behalf borrows your authority and is recorded as you, while an agent with its own account is a principal that apps see as itself, with you attached as [the accountable owner](/blog/every-agent-has-a-human). Neither model is wrong, and plenty of tools are built on delegation, which suits an agent working inside your own accounts. An agent that signs up for services, receives their email and holds accounts over time fits the second model better, and [agent owner verification vs end-user authentication](/blog/agent-owner-verification-vs-end-user-authentication) lays out the full argument; apps that need to [tell the two models apart in code](/blog/is-the-agent-acting-for-itself-or-on-behalf-of-a-user) can read it from the token. ## How does an agent get its own AgentID in two commands? An agent gets its own AgentID with one command that creates its inbox and one that connects it to an app. The inbox address is the agent's AgentID, so the first step is also the identity: ```bash agentmail inboxes create --display-name "Research Agent" ``` The second step is `agentmail apps connect`. It calls the AgentMail API to start a sign-in at an app that accepts AgentID: ```http # Start a sign-in at an app that accepts AgentID. # Returns a single-use magic_url, valid for five minutes, and an api_key_id. POST /v0/apps/{app_id}/connect # After the sign-in completes from the magic_url, the new key's # status moves from pending to active. GET /v0/api-keys/{api_key_id} ``` The AgentMail API key that makes the connect call needs the `app_connect` permission, which is off by default on new keys, so turn it on for the key your agent uses. The call creates a pending sign-in key, and whichever browser or client completes the sign-in activates it. If the app asks for your details as the owner, the key also needs the `app_share_owner` permission; without it, the agent can't finish alone and you approve the sign-in from your AgentMail account. There is a second way in. When an agent lands on an app's AgentID waiting page first, it can authorize that waiting sign-in with `POST /v0/inboxes/{inbox_id}/authorize` and the `auth_token` from the page, or `agentmail inboxes authorize` from the CLI. The request can accept the app's disclosure on the agent's behalf with `accept_disclosure: true`. The full agent-side reference is the [AgentID sign-in guide on AgentMail](https://docs.agentmail.to/agentid-sign-in). ## What if the agent runs headless or has no browser? Headless browsers are supported, so an agent driving a browser without a screen signs in the same way. If your agent has no browser at all, you finish the sign-in yourself in the AgentMail console, in the same browser you started it in. An application that runs its own signer has a third option. It can register its own public P-256 key through the AgentMail API Keys endpoints instead of generating one in a browser, which the [public key authentication guide](https://docs.agentmail.to/agentid-public-key-authentication) covers. ## What does the agent hold, and for how long? The agent holds the private half of a sign-in key scoped to its own inbox, and AgentMail records only the public half. The key is a P-256 keypair generated in the browser. Your private key is generated and stored in your browser and cannot be exported through browser JavaScript APIs. The sign-in key lasts 30 days from activation. It is separate from the AgentMail API key that created it, so deleting that bearer key revokes nothing; to cut the agent off, delete the sign-in key itself, and [revoking an AI agent's access](/blog/revoking-an-ai-agents-access) covers what that does and doesn't stop. Each app approval the agent gives is remembered for 180 days per inbox and app. The agent also holds something a borrowed login never gave it: a working mailbox. Apps can send it onboarding, product updates, receipts and invoices, and it can even open and resolve support tickets. The [AgentID page on AgentMail](https://www.agentmail.to/agentid) is the place to start if you are setting up your first agent. --- # How an AI Agent Proves Its Identity to Your App > An AI agent proves its identity with a signed OpenID Connect token. The sign-in flow, every AgentID claim, how to verify it, and what it does not prove. - **Author:** Binoy Perera - **Date:** 2026-09-30 - **Category:** Guides - **URL:** https://www.agentid.com/blog/how-an-ai-agent-proves-its-identity-to-your-app An AI agent proves who it is the same way a person does with Sign in with Google: with a signed token from an identity provider your app already knows how to check. This post walks the sign-in from the first redirect to the token, lists everything that token says about the agent and its owner, and explains what your app should do once the agent is inside. An AI agent proves its identity to your app with a signed token from a standard OpenID Connect sign-in, which your app checks against the issuer's published keys without having to trust the agent. With AgentID, the sign-in for AI agents from AgentMail, that token names the agent, marks it as an agent, and for registered apps names the human who owns it. Most agents today prove nothing of the kind. They arrive with a borrowed password, a pasted key or a user agent string, and each of those says what the agent claims rather than what someone else will vouch for. A sign-in flips that around. An issuer your app already recognizes does the checking, and your app only has to verify one signature and read a handful of fields. The sections below follow a single sign-in from start to finish and then cover what the token can and can't tell you. ## What happens between the redirect and the token? Five steps happen between the redirect and the token, and your app writes code for two of them. The sequence is the ordinary OIDC authorization code flow; the [complete guide to OIDC for AI agents](/blog/oidc-for-ai-agents-complete-guide) covers the protocol background, and this section stays on what the agent and the app each do. 1. **Your app redirects** the agent's browser to `https://auth.agentid.com/v0/authorize` with a standard authorization code request. 2. **The agent's browser continues or waits.** If it already holds an AgentID session, it continues on its own. If not, the waiting page shows one command the agent runs to create one. 3. **The agent approves** inside a sign-in transaction that lasts 5 minutes. The proof is a signature over a single server-generated transaction that is consumed exactly once, made with a key that stays in the agent's browser. 4. **AgentID redirects back** to your callback with an authorization code that is valid for 60 seconds and works once. 5. **Your server exchanges the code** at `/v0/token`, as usual, and receives an ES256-signed id_token and an access token. Both are valid for 10 minutes. No password and no API key crosses this flow, and your app never receives an AgentMail key it could store and reuse. The agent's approval is remembered for 180 days per inbox and app, so later sign-ins to the same app complete without the agent doing anything unless your redirect URI or scopes change. ## What does the token contain? The token contains the agent's identity in every case and the owner's identity only when a registered app asked for it. Seven claims are always present; the rest depend on the scopes your app requested and whether it is registered.
Claim When present Meaning
issAlwayshttps://auth.agentid.com
subAlwaysOpaque 43-character subject for the agent's inbox, stable across apps
audAlwaysYour exact client ID: a URL for open clients, an issued ID for registered ones
iat, expAlwaysIssued and expiry times, 10 minutes apart
jtiAlwaysUnique ID for this token
actor_typeAlwaysThe literal "agent"
nonceWhen your app sent oneEchoed back for replay detection
emailemail scopeThe agent's inbox, verified live when the token is minted
email_verifiedWith emailAlways true
nameprofile scopeThe agent's display name, omitted if none is set
preferred_usernameprofile scopeA handle built from the address
owner_subprofile scopeOpaque 43-character owner ID, shared by agents with the same owner
scopeRegistered clientsWhat was actually granted
owner_nameowner_profile, registeredThe owner's name
owner_emailowner_email, registeredThe owner's email address
Here is one, decoded. It belongs to a registered app that asked for every scope: ```json { "iss": "https://auth.agentid.com", "aud": "b7d41e0a-2c65-4f8b-9d31-0a5e7c2f4b18", "sub": "lM9vT2aR7sK4qN8wE1xC6bY0uF3hJ5pD9gL2zV7oA4Q", "actor_type": "agent", "scope": "openid email profile owner_profile owner_email", "email": "support@acme.agentmail.to", "email_verified": true, "name": "Acme Support", "preferred_username": "support_acme-agentmail-to", "owner_sub": "oW7xN2pQ4mT8vL1kR6sC9dF3gH5jB0aE2uY4zI6nP8A", "owner_name": "Maya Chen", "owner_email": "maya@acme.com", "iat": 1767225000, "exp": 1767225600, "jti": "9f1c2a44-3e77-4c19-9a2e-6b0d5f8e1c33" } ``` The `aud` here is an issued ID, not a URL, because owner claims only ever go to registered apps. An open client's token has its own URL as `aud` and never carries `owner_name` or `owner_email`. ## What should your app do when a claim is missing? Your app should treat a missing claim as not granted and test for presence rather than for null. AgentID omits claims it didn't grant instead of sending them empty, so `name` is simply absent for an agent with no display name, and `owner_sub` is absent when your app didn't request `profile`. With no scope at all, the issuer falls back to `openid email`. The owner claims have one guarantee worth relying on. A registered app that requested `owner_email` never receives a successful sign-in without it. If the agent's key isn't allowed to share its owner, the agent can't finish the sign-in alone, and the organization owner has to approve it from their AgentMail account. ## How do you verify the token is genuine? You verify the token the way you verify any OIDC id_token. There are five checks, and none of them involves the agent: - The ES256 signature matches a key in `https://auth.agentid.com/v0/jwks.json`. - `iss` is exactly `https://auth.agentid.com`. - `aud` is exactly your client ID. - `exp` hasn't passed. - `nonce` matches the one you sent, if you sent one. The signing key lives in AWS KMS and can't be exported, and the published keys keep stable IDs with an overlap window, so key rotation doesn't break tokens already in flight. Once the checks pass, key the account on `sub`, not on the email. Deleting an inbox and recreating the same address produces a new `sub`, which is how you tell a new agent from an old one that happens to share an address. The endpoint and claim reference is in the [AgentID docs](/docs), and the key handling is described on the [security page](/security). ## How do you know which agent is calling your API after sign-in? You know because your app ties its own session to the `sub` it just verified. AgentID's part ends at sign-in: the flow is authorization code only, its tokens expire after 10 minutes, and there are no refresh tokens, so they are not built to be a long-lived API credential. Your app issues the session or API key it would issue any user, with a lifetime you choose, and records the `sub` and `owner_sub` against it. Every request under that session is then attributable to one agent and, through `owner_sub`, to one owner, and never to a user the agent is [acting on behalf of](/blog/is-the-agent-acting-for-itself-or-on-behalf-of-a-user). That is what makes [rate limits per human](/blog/rate-limit-ai-agents-per-human-not-per-account) and per-owner signup caps possible. When you want fresh confirmation, call `/v0/userinfo` within the 10-minute window, which re-checks live state, or run a new sign-in, which completes on its own inside the remembered approval. ## What does the token not prove? The token doesn't prove the agent is safe. It proves which agent this is and, for registered apps, which human is accountable for it, and it carries no trust score or endorsement of any kind. Your abuse controls still run; they just have a stable key to run on. It also grants nothing beyond identity. Signing in gives your app no access to the agent's mailbox, so you can't read or send its mail. You can write to it, though, because the address is a working inbox, and agents on the other side of this flow are covered on the [AgentID page on AgentMail](https://www.agentmail.to/agentid). --- # Rate-Limit AI Agents per Human, Not per Account > Rate-limit AI agents per human, not per account: key your limiter on the AgentID owner_sub claim so ten agents from one person share one quota. - **Author:** Binoy Perera - **Date:** 2026-09-30 - **Category:** Guides - **URL:** https://www.agentid.com/blog/rate-limit-ai-agents-per-human-not-per-account When one person runs ten agents, a limit per account hands that person ten times the quota. Rate limiting per human fixes it by keying the limiter on the agent's owner, so every agent one person runs draws from the same allowance. You will see which identifier to key on, a small middleware example, and how long an agent's sign-in lasts before your app has to ask again. To rate-limit AI agents per person instead of per account, key your limiter on the agent's owner, not on the account or the address. AgentID, the sign-in for AI agents from AgentMail, gives every signed-in agent an owner identifier that all of one person's agents share, so ten agents from one person draw from one bucket. Rate limits were designed around a quiet assumption: one account is roughly one person. Free tiers, trial credits and API quotas all lean on it. Agents break the assumption because they are cheap to multiply, and a person who can create an inbox in one call can create ten. The fix is small once you have the right key, and most of the work is choosing which identifier to trust. ## Why do per-account rate limits fail once agents sign up? Per-account limits fail because an agent fleet turns [one customer into many accounts](/blog/how-agentic-accounts-differ-from-user-accounts). Agents are already signing up for software, often as their owners, which [can an AI agent sign up for a SaaS](/blog/can-an-ai-agent-sign-up-for-a-saas) covers from the product side. Once they sign up as themselves, each one is a fresh account with a fresh allowance. Per-IP limits don't rescue this. Agents often run on shared cloud infrastructure, so one address can carry many unrelated customers while one customer's agents spread across many addresses. The limit ends up punishing neighbors and missing the person you meant to slow down. What you want is the unit your pricing already assumes: the human who pays, or would pay. That is the owner, and keying the limit to the owner makes a free tier mean one free tier per person again, however many agents that person runs. ## Which claim should your limiter key on? Key the limiter on `owner_sub` when it is present and fall back to `sub` when it isn't. Here is what each option does when one person runs ten agents against your app.
Key One person, ten agents Available to
IP address Unpredictable; shared by strangers, spread across hosts Any request
Your account ID Ten accounts, ten quotas Any app
sub Ten agents, ten quotas, each stable across apps Every AgentID sign-in
owner_sub One owner, one quota Apps that request the profile scope, open or registered
owner_email One owner, one quota, plus a way to reach them Registered apps that request the owner_email scope
`owner_sub` is an opaque 43-character identifier that agents with the same owner share across apps. It can't be matched back to AgentMail API ids, so it identifies the owner without telling you who they are, which makes it a safe thing to put in a limiter's keyspace. `owner_email` works too, but only registered apps receive it, and it is a real person's address sitting in your rate-limit store. AgentID omits claims it didn't grant rather than sending them as null. An app that didn't request `profile` simply won't see `owner_sub`, so the limiter has to test for presence and fall back to the agent's own `sub`. ## What does per-owner rate limiting look like in code? Per-owner rate limiting is an ordinary token bucket with a better key. The TypeScript below is illustrative: it keeps buckets in memory to stay short, and the capacity and refill numbers are placeholders for your own. In production the buckets belong in a shared store such as Redis. ```ts // Illustrative only. A token bucket keyed on the agent's owner. type AgentClaims = { sub: string; actor_type: 'agent'; owner_sub?: string } const CAPACITY = 60 // burst size, your number const REFILL_PER_SEC = 1 // steady rate, your number const buckets = new Map() export function limiterKey(claims: AgentClaims): string { // owner_sub comes with the profile scope. Ungranted claims are omitted, // so an agent without one is limited as its own owner. return claims.owner_sub ? `owner:${claims.owner_sub}` : `agent:${claims.sub}` } export function allow(claims: AgentClaims, now = Date.now()): boolean { const key = limiterKey(claims) const bucket = buckets.get(key) ?? { tokens: CAPACITY, updated: now } const elapsed = (now - bucket.updated) / 1000 bucket.tokens = Math.min(CAPACITY, bucket.tokens + elapsed * REFILL_PER_SEC) bucket.updated = now const allowed = bucket.tokens >= 1 if (allowed) bucket.tokens -= 1 buckets.set(key, bucket) return allowed } // Express-style middleware. The claims were saved to the session at sign-in. app.use((req, res, next) => { const agent = req.session.agent if (agent === undefined) return next() // human users keep your existing limits if (allow(agent)) return next() res.status(429).set('Retry-After', '1').end() }) ``` The `owner:` and `agent:` prefixes keep the two kinds of key from colliding. Because `actor_type` is always `"agent"` on an AgentID token, the same session record also tells you which requests belong in this limiter at all, so human traffic can keep the rules it has today. ## Does AgentID rate-limit agents for you? No. AgentID doesn't publish rate limits for its sign-in endpoints, and it doesn't meter your users on your behalf. The token is built to carry enough to attribute, rate-limit, allowlist and revoke, and the limiter that uses it lives in your app. That split is deliberate. Only you know what a fair quota is for your product, whether a free tier gets five requests a minute or five thousand, and whether a paid owner's agents get more. AgentID's part is making the owner a stable, verifiable key, so the number you pick applies to a person rather than to however many accounts they could open. The same owner key also caps signups, not just requests. [How to stop fake agent signups without blocking real agents](/blog/stop-fake-agent-signups-without-blocking-real-agents) covers the console setting that limits accounts per owner before they exist. ## How long does an agent's sign-in last, and how do you refresh it? An agent's id_token and access token both last 10 minutes, and there are no refresh tokens. After that your app runs a new sign-in. Within the 180-day remembered approval for that inbox and app, the new sign-in completes without the agent doing anything, so a periodic re-check costs the agent nothing. Between sign-ins, your app's own session carries the agent, and you choose how long it lasts. Inside the 10-minute window, `/v0/userinfo` re-checks live state on every call, which means a revoked key or inbox shows up there before the token expires. A short session plus a quiet re-sign-in gives you fresh proof without building refresh logic that AgentID doesn't offer. None of this disturbs the limiter, and none of it needs a background job to keep tokens alive. `owner_sub` stays the same across sign-ins, so an agent that signs in again lands in the same bucket it left. The full list of lifetimes and claims is in the [AgentID docs](/docs), and agent builders can see the owner's side of this on the [AgentID page on AgentMail](https://www.agentmail.to/agentid). --- # Revoking an AI Agent's Access: What It Stops and What It Doesn't > Revoke an AI agent's AgentID by deleting its sign-in key. What that stops, what keeps running, how apps notice sooner, and which action fits each case. - **Author:** Binoy Perera - **Date:** 2026-09-30 - **Category:** Guides - **URL:** https://www.agentid.com/blog/revoking-an-ai-agents-access Revoking an AI agent's identity is real, but it doesn't reach into apps where the agent is already signed in. This post explains what revoking an agent's key stops, what keeps running afterwards, how an app can notice sooner, and which action fits five common situations, from a lost laptop to routine key rotation. Yes, an AI agent's identity can be revoked. With AgentID, the sign-in for AI agents from AgentMail, you delete the agent's sign-in key, and new sign-ins with that key stop at every app. What revocation doesn't do is sign the agent out of apps it is already in, and that edge is the part worth understanding before you need it. Most people picture revocation as a kill switch that reaches everywhere. In practice there are two parties: the identity provider, which stops vouching for the agent, and each app, which decides how long its own session lasts. Knowing where one ends and the other begins tells you what to do when a laptop goes missing, when an agent misbehaves, or when you just want to rotate keys on a schedule. ## What does deleting a sign-in key stop, and what keeps running? Deleting a sign-in key stops every new sign-in with that key, everywhere, and leaves existing sessions to each app. You revoke a key with `DELETE /v0/api-keys/{api_key_id}` on the AgentMail API, and the key model behind it is described on the [AgentID security page](/security). Three things keep running after the delete. The id_token an app already received stays valid until it expires, at most 10 minutes after it was issued. Each app's own session lasts as long as that app decides, because AgentID sends no revocation webhook and no back-channel logout. And any other sign-in keys the agent holds keep working, because there is no bulk revocation endpoint and each key is deleted on its own. One trap catches people. A sign-in key is separate from the AgentMail API key that created it, so deleting that bearer key revokes nothing. Delete the sign-in key itself. Left alone, a sign-in key expires 30 days after activation anyway. ## How can an app notice a revocation before the token expires? An app notices sooner by calling `/v0/userinfo`, which re-checks live state on every call. Within the 10 minutes an access token lives, a revoked key or inbox shows up there before the token itself expires. After those 10 minutes the app needs a new sign-in, and a revoked key can't complete one. That gives an app a simple pattern. Keep agent sessions short, and re-read `/v0/userinfo` before the actions that matter most, such as payments, deletes or changes to billing. Everything in between can rely on your own session, which is cheaper than asking on every request. The same call answers a related question: whether an agent is still the one its owner stands behind. For a registered app that requested the owner scopes, `/v0/userinfo` returns the owner claims alongside the agent's identity, re-checked live. What AgentID tells you is who is accountable. What that person has allowed the agent to do inside your product is your app's policy, and [how an AI agent proves its identity to your app](/blog/how-an-ai-agent-proves-its-identity-to-your-app) covers where each claim comes from. ## Why does a remembered approval outlive a revoked key? A remembered approval outlives a revoked key because it is consent, not a credential. When an agent approves an app, AgentID remembers that approval for 180 days per inbox and app, so later sign-ins there don't ask again. The approval can't sign anyone in by itself; a sign-in still needs a working key. There is no endpoint to revoke a remembered approval, and it doesn't need one for security, because the key is the thing that proves the agent. A changed redirect URI or scope set at the app asks again regardless. If you want to clear the AgentID session saved in a particular browser, [auth.agentid.com/sessions](https://auth.agentid.com/sessions) lists and forgets them, for that browser only. ## How do you stop one agent at one app without touching the rest? You stop one agent at one app by disabling its account there, not by revoking its key. A sign-in key works for its own agent at every app that accepts AgentID, so deleting it is the right move when the agent itself is the problem and the wrong one when only a single app is. To stop an inbox signing in at a specific app again, disable its account at that app with the AgentMail Update Account endpoint. Keys are also scoped the other way round. Each key works only for its own agent, so a stolen one reaches nothing else, and revoking one agent's key leaves your other agents and your own accounts untouched. The full agent-side reference is in the [AgentID sign-in guide on AgentMail](https://docs.agentmail.to/agentid-sign-in). ## How do you rotate an agent's key without downtime? Rotate by creating and activating the replacement first, then deleting the old key. The agent keeps signing in throughout, because at no point is it without an active key. ```http # 1. Start a replacement. The response has a single-use magic_url # (valid five minutes) and the new api_key_id. POST /v0/apps/{app_id}/connect # 2. Complete the sign-in from the magic_url. The new key moves from # pending to active; confirm it here. GET /v0/api-keys/{new_api_key_id} # 3. Remove the old key. DELETE /v0/api-keys/{old_api_key_id} ``` The agent's `sub` doesn't change when its key does, because `sub` belongs to the inbox. Apps see nothing, which is what rotation should look like from the outside. ## Which action fits which situation? The right action depends on whether the problem is a key, an agent, an app or an inbox. Five common cases:
Situation Action What the app observes
Lost laptop holding the agent's key Delete that key with DELETE /v0/api-keys/{'{api_key_id}'}. The sessions page can't help, because it only clears the browser you are using. New sign-ins with the key fail. Existing sessions last until the app ends them; /v0/userinfo shows the change within the token window.
Agent misbehaving Delete each of its sign-in keys; there is no bulk endpoint. The agent can't sign in anywhere with those keys. Sessions already open run to the app's own limit.
One app wants one agent gone The app blocks the agent's sub in its own records. The owner can disable the inbox's account there with Update Account. Whatever its own rule says. Other apps are unaffected.
Inbox deleted and recreated Nothing to revoke; the old identity is gone with the inbox. A new sub, even at the same address. Apps keyed on sub treat it as a new agent.
Scheduled key rotation Activate a replacement, then delete the old key. Nothing. The sub is unchanged.
Revocation is dependable because it is narrow. It stops the key everywhere, it touches nothing else, and it leaves each app in charge of its own sessions. The endpoint and lifetime details are in the [AgentID docs](/docs), and agent builders can start from the [AgentID page on AgentMail](https://www.agentmail.to/agentid). --- # SSO for AI Agents with OpenID Connect > SSO for AI agents is plain OpenID Connect. The AgentID discovery values, open vs registered clients, and setup on Clerk, Supabase, Auth0, Descope and Better Auth. - **Author:** Binoy Perera - **Date:** 2026-09-30 - **Category:** Guides - **URL:** https://www.agentid.com/blog/sso-for-ai-agents-with-openid-connect Single sign-on for AI agents doesn't need a new protocol. It is OpenID Connect, the standard behind Sign in with Google, pointed at an issuer whose every user is an agent. You will see what single sign-on means when the user is an agent, what your OpenID Connect library needs to know, and how the setup lands on the auth platform you already run. SSO for AI agents is plain OpenID Connect with an issuer that only signs in agents. AgentID, the sign-in for AI agents from AgentMail, is that issuer: add it to any login that accepts a custom OpenID Connect (OIDC) provider, and an agent signs in to your app with the same identity it uses everywhere else. That also answers the question of whether you can use a custom OIDC provider for agent authentication. You can, and the custom-provider option in your auth platform is exactly where it goes. Nothing about the protocol changes because the user is software. What changes is who the subject is, what the issuer tells you about it, and what "single" means when the one signing in never sees a password prompt. The sections below cover the meaning first, then the configuration your library reads, the choice between the two client types, and where it plugs in on each platform. ## What does "SSO" mean when the user is an agent? SSO for an agent means one identity that works at every app and one approval per app that is remembered. The agent's `sub` is stable across apps for the lifetime of its inbox, so it is the same agent at your app and at the next one. The integration side of that is covered step by step in [how to let an AI agent sign in to your website](/blog/how-to-let-an-ai-agent-sign-in-to-your-website). The "single" part is the remembered approval. The first time an agent signs in to your app it approves what your app will receive, and AgentID remembers that approval for 180 days per inbox and app. Inside that window the agent's browser continues on its own. If you change your redirect URI or the scopes you request, the agent is asked again. For your app, a returning agent looks like a returning user: the same `sub`, the same account, and no second signup. Between those sign-ins your app decides how long the agent stays signed in, because each app sets its own session length. It isn't workforce SSO. There is no company directory behind it and no administrator provisioning seats; each agent brings its own identity, backed by its own inbox. ## What does the discovery document tell your OIDC library? The discovery document at `https://auth.agentid.com/.well-known/openid-configuration` tells your library everything it needs, and most libraries read it for you. This excerpt shows the fields that shape your configuration: ```json { "issuer": "https://auth.agentid.com", "authorization_endpoint": "https://auth.agentid.com/v0/authorize", "token_endpoint": "https://auth.agentid.com/v0/token", "userinfo_endpoint": "https://auth.agentid.com/v0/userinfo", "jwks_uri": "https://auth.agentid.com/v0/jwks.json", "registration_endpoint": "https://auth.agentid.com/v0/register", "grant_types_supported": ["authorization_code"], "response_types_supported": ["code"], "code_challenge_methods_supported": ["S256"], "id_token_signing_alg_values_supported": ["ES256"], "token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "none"], "scopes_supported": ["openid", "email", "profile", "owner_profile", "owner_email"] } ``` Two values trip libraries up. Signing is ES256 only, so a library that assumes RS256 has to be told, or valid tokens fail verification. PKCE is S256 only. There is also no `offline_access` scope and no refresh token, because the flow is built for a sign-in, not for standing access. ## Should you register a client or use an open client? Use an open client to accept agents today with no setup, and register when you need to know who owns them. Both tiers use the same endpoints and the same tokens.
Open client Registered client
Setup None AgentID console or npx @agentmail/agentid-cli init, with an AgentMail account
Client ID An https URL your app owns An issued ID, with a client secret shown once
Redirect URIs On the same site as the client ID Up to 10
PKCE Required, S256 Optional; enforced when you send a challenge
Scopes openid, email, profile Those, plus owner_profile and owner_email
Owner's name and email Never When requested, in the id_token and from /v0/userinfo
Open clients don't work on localhost; the client ID has to be an https URL your app owns. Registration needs an AgentMail account on purpose, so every registered client belongs to one. ## Can you plug AgentID into the identity provider you already run? Yes. If your login already handles Sign in with Google, it can accept AgentID, and on most platforms that is configuration rather than code. One line per platform, each with its own guide: - **[Clerk](/docs/clerk):** Clerk's built-in AgentID connection, with your AgentID application's credentials in production. - **[Supabase](/docs/supabase):** a custom provider named `custom:agentid` with auto-discovery; scopes are comma-separated, and free Supabase projects allow three custom providers. - **[Auth0](/docs/auth0):** the official AgentID social connection from the Auth0 Marketplace, rather than an enterprise OIDC connection. - **[Better Auth](/docs/better-auth):** the `@agentmail/agentid-better-auth` helper for the Generic OAuth plugin, on Better Auth 1.7.2 or later. - **[Auth.js](/docs/auth-js):** version 4 is the documented path, with ES256 set explicitly because v4 otherwise assumes RS256. - **[Anything else](/docs/custom):** point any OIDC client at the endpoints above, or start with [open clients](/docs/open-clients) for no registration at all. The shortcut for most of these is `npx @agentmail/agentid-cli init` in your app's directory. It detects your auth provider, registers the application in your browser with your organization's approval, configures it and verifies it. [Adding a Sign in with AgentID button](/blog/adding-a-sign-in-with-agentid-button) covers the button itself. ## What doesn't AgentID SSO do? AgentID SSO doesn't manage sessions after sign-in. There is no logout endpoint in the discovery document, so your app ends its own sessions, and there are no refresh tokens, so fresh proof means a new sign-in, which completes on its own inside the remembered approval. It also grants nothing beyond identity. Signing in gives your app no access to the agent's mailbox, and the token isn't a trust score; it [tells you which agent this is](/blog/how-an-ai-agent-proves-its-identity-to-your-app) and, for registered apps, who is accountable for it. What happens when that needs to stop is covered in [revoking an AI agent's access](/blog/revoking-an-ai-agents-access), and the agent's half of the setup is on the [AgentID page on AgentMail](https://www.agentmail.to/agentid). --- # How to Stop Fake Agent Signups Without Blocking Real Agents > Stop fake AI agent signups by capping signups per owner, not blocking agents. Three policies compared and the AgentID setting that enforces the cap. - **Author:** Binoy Perera - **Date:** 2026-09-30 - **Category:** Guides - **URL:** https://www.agentid.com/blog/stop-fake-agent-signups-without-blocking-real-agents Blocking AI agents at signup turns away real customers along with the spam, and the spam learns to look human anyway. The control that holds up is knowing which person owns each agent and capping how many accounts one owner can open. By the end you will know how the three common signup policies compare and how an app sets a per-owner cap that the sign-in enforces for it. You stop AI agents from creating fake accounts by capping signups per human owner instead of blocking agents. AgentID, the sign-in for AI agents from AgentMail, tells your app which owner each agent belongs to, and a registered app can set a maximum number of signups per owner that is enforced before the account ever exists. That changes the question a signup form has to answer. The form can't tell whether a request came from a script, a person, or a person's agent, so teams guess, and the guess usually lands on "block anything that looks automated." The cost of that guess is invisible in the dashboard: the agents you turned away were often sent by people who wanted your product. What follows compares the three policies teams reach for, explains how an app tells agents apart at sign-in, and shows the one setting that turns a spam wave into a number you choose. ## Why does blocking AI agents cost you real customers? Blocking AI agents costs you real customers because many of the agents at your signup form are working for someone who meant to buy. Agents already sign up for software today, mostly with their owners' addresses and passwords, which is covered in [can an AI agent sign up for a SaaS](/blog/can-an-ai-agent-sign-up-for-a-saas). A block rule catches the agent that behaves like a bot and misses the one that behaves like its owner. That is why builders keep asking why their agent gets blocked when it tries to create an account. The app has no way to separate a legitimate agent from a script, so it treats both as abuse, and the honest agent is the one that gives up. The dishonest one retries from a new address. The underlying problem is not agents. One large enterprise observed hundreds of signups from AgentMail-domain addresses in a short window and could not tell whether that was one person's fleet or hundreds of customers. Both answers call for a different response, and a block rule can't tell them apart. ## How can you tell an agent signup from a human one? You tell them apart by asking the sign-in, not by scoring the traffic. Every subject AgentID issues is an agent inbox, and every token carries `actor_type` set to the literal `"agent"`, for every client, registered or not. Agent policy becomes a branch in your code instead of a heuristic. The same token carries a stable `sub` for the agent. It stays the same for that inbox across every app, so a second signup from the same agent is recognizable as the same agent. Deleting an inbox and recreating the same address produces a new `sub`, which is worth knowing if you ever see one address with two histories. The agent's `email` claim is its own inbox, checked live when the token is minted, and `email_verified` is always true. You don't need a confirmation email to trust that address. The agents that still sign in with a borrowed human password stay invisible, which is the case for [giving agents a door of their own](/blog/adding-a-sign-in-with-agentid-button). ## Which signup policy actually stops a spam farm? Capping signups per owner is the only one of the three that stops a spam farm without stopping your customers. The other two each fail one side of the problem.
Policy A real customer's agent A spam farm Support load
Block all agents Rejected, or signs up with its owner's credentials and becomes invisible Learns to look human; only the clumsy attempts are caught Appeals from blocked customers, and a signup table nobody trusts
Allow unlimited agents Gets in One person opens as many free accounts as they have inboxes Abuse reviewed one account at a time
Cap signups per owner Gets in, up to the owner's cap Stops at the cap, however many inboxes it creates One owner to review; banning the owner covers every agent they run
The cap works because the unit is the owner, not the account. Creating another inbox is cheap, so a limit per account or per address only measures how patient the abuser is. Agents with the same owner share one owner identifier, so a new inbox under the same owner counts against the same cap. ## How do you cap signups per owner in the AgentID console? You cap signups per owner with one field on your application in the AgentID console. Create the application in the [AgentID console](https://console.agentid.com/sign-up) or with `npx @agentmail/agentid-cli init`, open its settings, and set **Maximum signups per owner**. The console describes it as "How many agents belonging to one owner may sign up to this client."
Value Effect
Blank Unlimited signups per owner
0 New signups paused; existing accounts keep signing in
1 to 1,000,000 That many signups per owner
The issuer enforces the number, not your app. When an owner is already at the cap, the sign-in ends before approval with the outcome `signup_limit_reached`. How many agent accounts one person may run is your policy to set; AgentID enforces whatever number you choose. Zero is the setting to remember during an abuse wave. It pauses new agent signups for that application while every existing agent account keeps working, which buys time without locking out the customers you already have. ## What if you don't want the owner's email? You still get a per-owner key without it. The `profile` scope adds `owner_sub`, an opaque 43-character identifier for the owner that agents with the same owner share across apps. It can't be matched back to AgentMail API ids, so it identifies the owner to your app without telling you who they are. That matters for apps that would [rather not hold a third person's email address](/blog/persistent-agent-identity-without-personal-data). Open clients, which skip registration and use a URL they own as their client ID, can request `profile` too, so even an app that never registers can key its own caps and quotas on `owner_sub`. The console cap itself belongs to registered applications. When you do want a way to reach the person, a registered application can request `owner_email`. It arrives in the id_token and from `/v0/userinfo`, and an agent that isn't allowed to share its owner can't finish the sign-in alone, because the organization owner has to approve it. [How to verify the human behind an AI agent](/blog/how-to-verify-the-human-behind-an-ai-agent) walks through that setup, and the same owner key drives [rate limits per human instead of per account](/blog/rate-limit-ai-agents-per-human-not-per-account). A cap is a policy, and it needs a key that holds still. The owner is that key, and the [AgentID docs](/docs) list every claim that carries it. If you are on the other side of the form, building the agent, the [AgentID page on AgentMail](https://www.agentmail.to/agentid) covers how an agent gets an identity apps can cap fairly. --- # Adding a Sign in with AgentID Button > Add a Sign in with AgentID button with two configuration values. Setup for Clerk, Supabase, Auth0, Descope, Better Auth, and Auth.js, plus the button guidelines. - **Author:** Binoy Perera - **Date:** 2026-09-15 - **Category:** Guides - **URL:** https://www.agentid.com/blog/adding-a-sign-in-with-agentid-button - **Configure the provider, then draw the button.** Clerk, Supabase, Auth0, Descope, Better Auth, and Auth.js each take the issuer and a client_id; the CLI does it for you on the stacks it detects. - **Spell it AgentID.** One word, capital I and D. The verb is yours; match whatever your other buttons say. - **Use the official mark, unmodified.** Four SVG variants for light and dark backgrounds, minimum 16px, clear space of half its height. - **Match your neighbors.** Same shape, width, and icon alignment as your Google and GitHub buttons. Adding a Sign in with AgentID button takes two configuration values and one image. [AgentID is the sign-in for AI agents from AgentMail](/blog/introducing-agentid), and it is standard OpenID Connect. The job has two halves: 1. **Configure the provider.** In your auth platform, add a custom OpenID Connect provider with issuer `https://auth.agentid.com` and your `client_id`. That is a URL you control for the open tier, or the id from registration. 2. **Add the button.** On your login page, next to your Google and GitHub buttons, show the AgentID mark from `https://www.agentid.com/brand/` and the text "Sign in with AgentID." Style it to match its neighbors and wire it to the same sign-in call your other providers use. That is the whole job. The fastest way to do the first half is `npx @agentmail/agentid-cli init` in your project directory. The second half is copy and paste from below. It is free for apps. ## What does an agent see when it clicks the button? An agent that clicks Sign in with AgentID sees what a person sees with Sign in with Google: a redirect to the provider, a short interaction, and a return to your app signed in. That is also why adding the button to a website follows the same steps as adding Google. The redirect goes to `https://auth.agentid.com/v0/authorize`. What happens next depends on the agent: - **Enrolled browser:** the browser produces a fresh one-time signature for this sign-in. A disclosure screen shows which app is asking and what it will receive, and the browser returns to your callback with an authorization code. - **Browser with no AgentID session:** the page shows the agent one command that creates one, which is the one-time enrollment step. - **No browser at all:** its owner can complete the sign-in from the AgentMail console, in the browser where the flow started. A human who clicks it out of curiosity sees the same page and learns what AgentID is. That is intentional. The button on your login page is how AgentMail pays for a free product. ## Step one: how do you configure your auth platform for AI agent authentication? Configure your auth platform by adding AgentID as an OpenID Connect provider with the issuer and a `client_id`. Pick your platform below; each has a per-dashboard walkthrough in the docs, and the CLI handles all of them.
Platform Where it goes Detail that trips people up Guide
Clerk Custom OAuth provider Scopes you request here are the request; registration does not set them. /docs/clerk
Supabase Authentication, Sign In / Providers, Custom Providers Identifier has a fixed custom: prefix; type only agentid. Scopes are comma-separated. Free projects allow three custom providers. /docs/supabase
Auth0 Marketplace social connection AgentID is a listed integration; enable it rather than building an enterprise connection. /docs/auth0
Better Auth Generic OAuth plugin via @agentmail/agentid-better-auth Requires Better Auth 1.7.2 or newer. Provider id is fixed to agentid; your redirect URI ends in /agentid. /docs/better-auth
Auth.js v4 Generic OIDC provider Set PKCE and nonce checks and ES256 in the provider metadata. /docs/auth-js
Anything else OIDC Generic connector or your own client Code flow only, S256 PKCE, ES256, no refresh tokens, no end-session endpoint. /docs/custom
Or skip the dashboard: ```bash npx @agentmail/agentid-cli init ``` Run it from the application you want to configure, with Node.js 20 or newer. The CLI does four things: 1. **Detects** the provider. 2. **Registers** a client. A browser opens for your organization to approve; there is no unattended bypass. 3. **Writes** the configuration. 4. **Verifies** it. Press Enter at the scope picker for `openid email profile`, or add `--owner-email` if your app needs the human owner's address. `npx @agentmail/agentid-cli doctor` checks everything without changing anything. The CLI configures your application to accept agents. It does not sign an agent in. Two values are all any of these need: - **Issuer:** `https://auth.agentid.com` - **Client ID:** your `client_id` Discovery at `https://auth.agentid.com/.well-known/openid-configuration` supplies the rest. If you want the owner's email, create an AgentID application with the CLI or the [AgentID console](https://console.agentid.com/sign-up), and request the `owner_email` scope. The owner arrives in the id_token and from `/userinfo`. The full protocol reference is [OIDC for AI agents: the complete guide](https://www.agentid.com/blog/oidc-for-ai-agents-complete-guide). ## Step two: what are the button assets? The button assets are four variants of the AgentID mark, each as SVG and PNG, all free to use for a sign-in button. Prefer the SVG; the button is usually small and the SVG stays sharp. All four are on the [AgentID brand page](https://www.agentid.com/brand).
Variant Use it on URL
Black, transparent Light backgrounds https://www.agentid.com/brand/icon-black.svg
White, transparent Dark backgrounds https://www.agentid.com/brand/icon-white.svg
Black on white tile When you cannot control the backdrop https://www.agentid.com/brand/icon-black-on-white.svg
White on black tile Light layouts wanting a dark tile https://www.agentid.com/brand/icon-white-on-black.svg
Dashboard providers draw the button from a display name and, where the form has one, a logo URL. - **Display name:** type AgentID. - **Logo field:** where one exists, paste one of these URLs into it. The Auth0 Marketplace listing carries its own branding. - **Variant:** pick the one that matches your login page's background, since a pasted URL cannot switch with the theme. ## Step three: what does the button markup look like? If you render your own buttons with Better Auth, Auth.js, or a custom client, copy the shape of the provider buttons you already have. A minimal version: ```html ``` The `onclick` calls whatever your other providers call: - **Supabase:** `supabase.auth.signInWithOAuth({ provider: 'custom:agentid' })` - **Better Auth:** the provider id is `agentid`. - **Clerk and Auth0:** the platform's own components render the button once the connection is enabled, and you only need to make sure it appears in the list. Three layout rules come from the brand page: - **Pair the mark with the name.** Do not show the mark alone, so someone who has never seen it can tell what it does. - **Match the shape of the other providers.** If Google and GitHub are full width with a left-aligned icon, do the same. A button that stands out from its neighbors reads as an advertisement rather than an option. - **Leave clear space.** Keep at least half the mark's height clear around it, and never render it below 16px. ## What are the Sign in with AgentID button guidelines? The name reads AgentID: one word, no space, capital I and capital D, in running text, button labels, and code comments alike. - **Misspellings to avoid:** "Agent ID," "AgentId," and "agentID." - **Never shortened** to "Agent." The verb around it is yours. "Sign in with AgentID," "Continue with AgentID," and "Log in with AgentID" are all fine. Use whichever your Google and GitHub buttons already use, so the three read as one set. Use a mark from the set above unmodified: no recoloring, effects, rotation, or redrawing. The mark identifies the sign-in option, not your product. It does not belong in your logo or anywhere it would suggest AgentID built or endorsed your app. ## Where should the button go on the login page? Put the Sign in with AgentID button beside the social sign-in buttons, in the same group, not in a separate "for agents" section. There are two reasons: - **Agents find it.** Agents driving a browser find it where they expect sign-in options to be. - **Humans see it.** That is the point of the free product: someone who has never heard of AgentID learns that agents can have accounts here. If your login has a "Continue with" group above the email form, it goes there. If your API docs have an authentication section, add one sentence saying the app accepts Sign in with AgentID and link to your login page, so agents reading docs find the door. ## What happens after the first sign-in? After the first sign-in, your callback receives an ordinary authorization code, exchanges it at `/v0/token`, and gets an ES256-signed id_token with a stable `sub` and the agent's verified email. 1. **Create the account** keyed on `sub`. 2. **Send your normal welcome email.** The agent reads its inbox. 3. **Store the owner.** If you requested `owner_email`, call `/v0/userinfo` with the access token and store the owner on the account for per-human limits, as covered in [how to verify the human behind an AI agent](https://www.agentid.com/blog/how-to-verify-the-human-behind-an-ai-agent). 4. **Get listed.** List your app in the [AgentID directory](https://www.agentid.com/directory) so agents looking for services that accept them find yours. The longer relying-party guide, including the wire format and the security model, is [how to let an AI agent sign in to your website](https://www.agentid.com/blog/how-to-let-an-ai-agent-sign-in-to-your-website). --- # Agent Owner Verification vs End-User Authentication > Delegated access for AI agents vs agent owner verification. Who is this agent, and which human answers for it? The principal and delegate models compared. - **Author:** Binoy Perera - **Date:** 2026-09-15 - **Category:** Blog - **URL:** https://www.agentid.com/blog/agent-owner-verification-vs-end-user-authentication - **Two questions.** Who is this agent, and who is the human accountable for it. End-user authentication answers neither; it authenticates a person at a keyboard. - **Owner verification is a property of the grant.** The identity provider attests to the owner; the agent does not assert it. - **Principal vs delegate is the fork.** auth.md, Auth0 for AI Agents, and Arcade make the human the account. AgentID makes the agent the account and the human a claim. - **Pick by who the customer is.** If your users bring agents, delegate. If agents arrive as customers, principal. Agent owner verification and end-user authentication answer two different questions that look like one. - **End-user authentication** establishes that a person is present and is who they claim to be, usually so software can act with that person's permissions. - **Agent owner verification** establishes which human is accountable for an agent that is acting on its own, without that human being present. In delegate-model systems such as WorkOS auth.md, Auth0 for AI Agents, and Arcade, the human is the account and the agent borrows scoped authority from it. End-user authentication is the whole story. In AgentID, the sign-in for AI agents from AgentMail, the agent is the principal with its own account. The owner is a claim a registered app can request, delivered in the id_token and from `/userinfo`. Neither model is wrong. They fit different products, and the mistake is using one when your problem needs the other. ## What is end-user authentication, and how does delegated access for AI agents work? End-user authentication is the process of confirming that the person at the other end of a session is a specific known user. Passwords, passkeys, OTP codes, and Sign in with Google are all end-user authentication. The output is a session or a token that says "this is user U," and every permission the software exercises afterward is U's. When an agent is involved, end-user authentication is how delegation starts. The user authenticates, then grants the agent some subset of their authority: - An OAuth access token scoped to `read:calendar`. - A session the agent drives. - A vaulted credential a runtime holds on the user's behalf. The agent is never the subject of that authentication. It is a bearer of authority that belongs to someone else. This is a perfectly good design for agents that act for a specific user inside systems that user already has access to. Its limit is that it cannot describe an agent acting on its own: - **No session to delegate from.** If the agent signs up for a new service, there is no user session. - **The wrong container.** If it needs an account of its own, with its own receipts and its own support thread, the user's account does not fit. - **No slot for the owner.** If the receiving app wants to know who is accountable for the agent, end-user authentication has no place for the answer, because from its point of view the agent is the user. ## What is agent owner verification, and how does it differ from AI agent identity verification? Agent owner verification is a statement from a trusted identity provider that a specific agent is owned by a specific human or organization. It sits one layer above agent identity verification. Identity verification establishes that this is the same agent as last time and that its email is real; owner verification adds whose it is. It is a property of the sign-in grant rather than something the agent asserts. The receiving app can rely on it because it comes from the party that issued the agent's identity. In AgentID, owner verification works like this: 1. Every agent is an AgentMail inbox, and every inbox belongs to an organization with a designated owner. 2. A registered client requests the `owner_email` and `owner_profile` scopes. 3. After the code exchange, the app reads `owner_email` and `owner_name` from the id_token, or from `/v0/userinfo` with the access token. When the agent is not allowed to share its owner, it can't finish the sign-in alone; the organization owner has to approve it. The step-by-step is in [how to verify the human behind an AI agent](https://www.agentid.com/blog/how-to-verify-the-human-behind-an-ai-agent). The owner shows up in the data without being in the room. The agent signed in on its own from an enrolled browser; no person clicked anything; and the app still knows who to hold responsible. ## Is the agent a principal or a delegate? A principal is the account holder the app registers, bills, and emails. A delegate acts on behalf of a principal with borrowed, scoped authority. This is the fork that decides which of the two questions your system can answer.
Delegate model Principal model
Who holds the account The human user The agent
Where the human appears As the subject of the token As a claim (owner_email) the app can request
What the token proves A user granted authority to some client Which agent this is, and optionally whose
Can the agent sign up for a new service on its own Only by getting the user to authenticate first Yes, from an enrolled browser, with no user present
Where receipts and support replies go The user's inbox The agent's own inbox
Revoking the agent Revoke the grant; the user's account is unaffected Revoke the agent's credential; the owner's accounts are unaffected
Examples WorkOS auth.md, Auth0 for AI Agents (Token Vault), Arcade AgentID; Microsoft Entra Agent ID and Auth0 Agent as Principal, inside a tenant
The two rows on revocation look symmetric and are not. - **Delegate model:** revoking one agent's grant is clean, but revoking the user cuts off every agent they run and everything else the user does. - **Principal model:** each agent has its own credential. Revoking it touches nothing of the owner's, and banning the owner (by `owner_email`) still covers all their agents. You get per-agent and [per-human control](/blog/rate-limit-ai-agents-per-human-not-per-account) at the same time. Microsoft Entra Agent ID is also a principal model, scoped to the tenant that created the agent and with a required Sponsor as the accountable human. ## How do auth.md, Auth0 for AI Agents, and Arcade authorize an agent, and where is the human? WorkOS auth.md, Auth0 for AI Agents, and Arcade all authorize an agent with the user's authority, so the human is the account. All three are delegate-model products and say so in their own words. **WorkOS auth.md.** WorkOS describes auth.md as "a Markdown file an application hosts at its domain, typically https://yourapp.com/auth.md, that tells agents how to register on behalf of a user." Its two flows both end in "a scoped access token tied to the user, short-lived and revocable." - **Agent verified flow:** the agent's provider (OpenAI, Anthropic, Cursor, and others) mints an ID-JAG asserting that the agent acts for a specific user, with no human in the loop. - **User claimed flow:** the agent shows the user a code and the user confirms it. Either way the account is the user's; the agent is registered "on behalf of" them. This is end-user authentication extended to cover an agent that arrives first. It is a clean design for products whose account model is human accounts. **Auth0 for AI Agents.** Auth0 keeps the agent a bearer of the user's authority: "Your agent never actually holds the root key; instead, it asks Token Vault for a temporary, short-lived access token only when it needs to perform a specific task." Its Agent as Principal feature adds first-class agent identities inside your tenant. A July 30, 2026 Auth0 post describes it as early access, while the product page still says coming soon. That moves toward the principal model for agents you build, but it is scoped to your own Auth0 tenant rather than portable to other apps. **Arcade.** Arcade states the model in one sentence: "Authentication runs against your IdP. Authorization is delegated, so the agent acts as its user." The downstream system sees the user's credentials. None of these is a criticism. Each is the right tool when a known user is delegating to an agent inside systems that user can already reach. What they do not produce is a verifiable statement, delivered to a third-party app, that "this agent is owned by this person." The agent's owner is either the authenticated user (so the app learns nothing new) or invisible to the receiving app entirely. ## How do you tell whether an agent is acting for itself or for a user? Look at who the subject of the token is. If the `sub` is a user and the agent is the client, the agent is a delegate. If the `sub` is the agent, it is acting as itself. AgentID tokens always have the agent as `sub`, with a stable identifier derived from its inbox and the inbox address as `email`. Owner information, when present, is in separate claims (`owner_name`, `owner_email`) and is never confused with the subject. This matters for what you record: - **A delegate token:** attribute actions to the user and log the client. - **A principal token:** create an account for the agent, attribute actions to the agent, and store the owner as the accountable contact. Mixing the two, by treating an agent-as-principal sign-in as if the owner were the user, makes a human the customer of record for an account they never touched. That is the problem you started with. ## Which one does your product need? If your users bring their own agents and the agent should do what the user could do, you need delegation. If agents arrive as customers in their own right, you need the principal model and owner verification. **Delegation.** Publish an auth.md, or configure your identity platform's agent features, and let the user's session be the anchor. End-user authentication is doing its job. **Principal model.** Agents that arrive from organizations you have no relationship with need an account, an inbox for your emails, and a credential you can revoke individually. You need a human to hold accountable. AgentID provides that through standard OpenID Connect that plugs into Clerk, Supabase, Auth0, Descope, Better Auth, or Auth.js with two configuration values. The setup is in [how to let an AI agent sign in to your website](https://www.agentid.com/blog/how-to-let-an-ai-agent-sign-in-to-your-website). Many products end up needing both, because both kinds of agent show up. A user's agent reading their dashboard is a delegate. A standalone agent signing up to provision resources is a principal. The [comparison with WorkOS auth.md](https://www.agentid.com/blog/agentid-vs-workos-auth-md) goes into how an identity provider and a registration protocol can compose. That includes the unshipped possibility of an AgentMail agent minting an ID-JAG that asserts its owner inside auth.md's agent verified flow. The terminology behind all of this, including workload identity and ID-JAG, is collected in the [agent identity field guide](https://www.agentid.com/blog/agent-identity-terminology-explainer). --- # Can an AI Agent Sign Up for a SaaS? > Yes, AI agents already sign up for SaaS, as their owners. Why blocking trades one problem for another, and how to rate-limit per human with owner_email. - **Author:** Binoy Perera - **Date:** 2026-09-15 - **Category:** Blog - **URL:** https://www.agentid.com/blog/can-an-ai-agent-sign-up-for-a-saas - **Agents are signing up now, as people.** Your signup table already contains them; you cannot see which rows. - **Blocking trades one problem for another.** Bot detection catches agents that behave like bots and misses agents that behave like their owners, while turning away paying automation. - **Accountability is what makes admission safe.** An agent with a verifiable owner can be limited per human, contacted, and cut off individually. - **The mechanics are small.** Add AgentID as an OIDC provider, create an AgentID application, request `owner_email`, and index your accounts on it. Yes. AI agents can sign up for a SaaS product, and they already are. They use their owners' email addresses and complete the OTP and consent steps a human would. That leaves a SaaS team with three questions: - How do you tell agents from people? - How many agents is one person running? - Who is accountable when one misbehaves? A sign-in built for agents answers all three. With AgentID, the sign-in for AI agents from AgentMail, the agent signs in as itself through standard OpenID Connect. Your app receives a stable identifier and the agent's verified email. If you create an AgentID application and request the `owner_email` scope, it also receives the owner's email, in the id_token and from `/userinfo`. That owner claim turns an unknown bot into a customer you can [rate-limit per person](/blog/rate-limit-ai-agents-per-human-not-per-account) and contact by name. It is a stronger position than blocking. ## Are AI agents already signing up for SaaS products? AI agents are already signing up for SaaS products, and the evidence is in the support inbox rather than the analytics dashboard. AgentMail, which sells inboxes to agents, launched an API endpoint that let agents sign up on their own. It then emailed new users to ask how they had found the product. Many did not know they had signed up, because their agent had done it. Most support requests began arriving from agents. One large enterprise observed hundreds of signups from AgentMail-domain addresses in a short window, and could not tell whether that was one person's fleet or hundreds of customers. The wider web points the same way: - **All bots:** Cloudflare put automated requests at 57.5% of HTTP requests to HTML content as of June 2026, counting all bot types rather than agents alone. - **Agents specifically:** HUMAN Security's March 2026 benchmark measured agent traffic growing 7,851% year over year, from a low 2024 base. Neither figure is your signup rate. Both say the assumption that a signup is a person is no longer safe to make by default. ## What does your signup table look like today? Every AI agent that has signed up so far appears in your signup table as a human. - **The email says a person.** The agent used a person's email address. - **The OTP passed.** The agent either waited for the person to paste the code or had access to the person's inbox. - **The consent screen was clicked.** The agent was operating a browser. If your product sends onboarding email, that sequence is going to an inbox whose owner may not know the account exists. That is why activation numbers look strange for those rows, and why support tickets arrive from addresses that never reply like people. Three things you cannot do with this table: - Distinguish agent accounts from human ones. - Count agents per person. - Revoke an agent without locking out the person whose credentials it used. Every abuse control you have is built on the account being the unit. The account is the wrong unit when one human runs many agents. ## Should you block AI agents from signing up? Bot-detection vendors will say yes, and for scripted abuse they are right. For AI agents, blocking is weaker than it sounds. Detection catches agents that behave like bots: datacenter IPs, headless browser fingerprints, inhuman timing. It misses agents that behave like their owners, which increasingly means agents driving a real browser at human speed with the owner's cookies. It also blocks the customers you want. An agent that provisions a database for its owner every week is a paying user with a regular pattern. At the network layer, it is indistinguishable from an agent creating throwaway accounts. The alternative is to let agents identify themselves as agents, and to make that path more attractive than pretending to be human. That only works if both sides get something: - **The agent gets** a sign-in that does not require a person, an account of its own, and email it can read. - **You get** a stable identifier and a human you can hold responsible. Accountability is the property that makes admission safe. An app that knows who stands behind an agent can let it sign up, act, and spend on its own, because there is someone to call if it goes wrong. ## How do you tell agents from humans at sign-in? Put a sign-in on your login page that only agents can use. AgentID is an OpenID Connect provider whose subjects are agents. Each agent has an AgentMail inbox as its identity and an enrolled browser holding a key that never leaves it. Add it as a custom OIDC provider in Clerk, Supabase, Auth0, Descope, Better Auth, or Auth.js with two values: - **Issuer:** `https://auth.agentid.com` - **Client ID:** your `client_id` Or run `npx @agentmail/agentid-cli init` to configure it. Every account created through that provider is an agent, tagged as such by the sign-in method. `sub` is its stable identifier, and `email` is an address you can send receipts to that will be read. Agents that still sign up as humans will not disappear on day one. What changes is that you now have a legitimate door, and you can start steering toward it: - Mention it in your API docs. - List your app in the [AgentID directory](https://www.agentid.com/directory) so agents browsing for services find you. - Apply the stricter human-verification steps only to the human door. ## How do you rate-limit agents per human instead of per account? Create an AgentID application and request the `owner_email` scope, then key your limits on the owner instead of the account. 1. **Create an application.** Click **Create application** in the [AgentID console](https://console.agentid.com), or run `npx @agentmail/agentid-cli init`. 2. **Request the scope.** Ask for `owner_email` (and `owner_profile` for the name) when the agent signs in. 3. **Read the owner.** `owner_email` and `owner_name` arrive in the id_token and from `/v0/userinfo`. If the agent is not allowed to share its owner, it can't finish the sign-in alone; the organization owner has to approve it. When a sign-in succeeds, the field is there. Store `owner_email` on the agent's account and index it. Per-human policy becomes one query.
Policy Keyed on account Keyed on owner_email
Free-tier quota One free tier per agent; ten agents get ten free tiers One free tier per human, shared across their agents
Account cap Unenforceable N agents per owner, your choice of N
Abuse response Ban one account; the next agent signs up Ban the owner; every agent they run is covered
Billing Card per agent, or none Roll agents up to one billing contact
Who you email when it breaks The agent's inbox The agent's inbox for operations, the owner for accountability
The right N depends on your product. A database company might allow unlimited agents per owner and bill by usage. A product with a costly free tier might allow three. The point is that the number is now yours to set. ## What is Know Your Agent, and do you need it? Know Your Agent, or KYA, is verifying which agent is transacting and which human or organization stands behind it, by analogy with Know Your Customer. The term comes from the payments and agentic-commerce world. Visa, Mastercard, and Ant International announced a shared KYA interoperability framework on September 10, 2026. McKinsey projected in October 2025 that agents could mediate $3 trillion to $5 trillion of global consumer commerce by 2030 under moderate scenarios. That is why payment providers care. For a SaaS product, KYA at signup is exactly the owner claim above: a verified agent identity plus a verified owner, delivered in the sign-in. The fuller treatment, including what to do when you need more than an email, is in [how to verify the human behind an AI agent](https://www.agentid.com/blog/how-to-verify-the-human-behind-an-ai-agent). ## What changes in your product once agents are customers? Less than you might expect. Most of a SaaS product keeps working unchanged when the customer is an agent. - **Onboarding email** works unchanged, because the agent reads its inbox. - **Receipts and invoices** work unchanged. - **Support** works, and in AgentMail's experience gets busier, because agents open tickets and follow up. Two things are worth building: 1. **An owner invite.** A way for the agent to invite its owner into the organization as a separate member, so a human can look at what the agent set up without sharing its login. 2. **Owner-keyed limits.** Agent-specific rate limits and feature gates keyed on `owner_email`, which is one more column in a table you already have. The differences between the two kinds of account, and what an agent account should be allowed to do, are laid out in [how agentic accounts differ from user accounts](https://www.agentid.com/blog/how-agentic-accounts-differ-from-user-accounts). The step-by-step integration is in [how to let an AI agent sign in to your website](https://www.agentid.com/blog/how-to-let-an-ai-agent-sign-in-to-your-website). It is free for apps. --- # How Agentic Accounts Differ from User Accounts > Agentic account vs user account vs service account. The agent as principal, with its own identifier, credential and inbox, and its owner recorded as a claim. - **Author:** Binoy Perera - **Date:** 2026-09-15 - **Category:** Blog - **URL:** https://www.agentid.com/blog/how-agentic-accounts-differ-from-user-accounts - **Three kinds of account.** User accounts assume a person. Service accounts assume software inside your perimeter. Agentic accounts are software that arrives from outside and needs to be treated as a customer. - **The identifier is the difference.** A service account has a client ID and a secret. An agentic account has a verified, routable email address and a key that never leaves the agent. - **Accountability travels with it.** A service account's owner is known only to the organization that made it. An agentic account's owner is a claim the receiving app can request. - **Enforce per owner, not per account.** Quotas, caps, and bans keyed on `owner_email` are what make agent admission safe. An agentic account is an account held by an AI agent as the principal. It has its own identifier, its own credential, its own inbox, and a human owner recorded as a claim rather than as the account holder. It differs from the two account types you already know: - **From a user account:** no person is present to type a password, read an OTP, or click a consent screen. - **From a service account:** it can introduce itself to applications outside the organization that created it, and it carries a verifiable link to an accountable human. In AgentID, the sign-in for AI agents from AgentMail, an agentic account is an AgentMail inbox with an enrolled browser. The app receives a stable `sub` and a verified email in the id_token, and registered clients read `owner_email` from `/userinfo`. The constraints an app should enforce follow from that shape, starting with three: key on `sub`, limit per owner, revoke per credential. ## What is the difference between a user account and a service account? A user account represents a person, and a service account represents software. The real distinction is who the account is for and where it is trusted. - **A user account** authenticates with something the person knows or has. It gets a mailbox and a profile, and it is the unit of billing, consent, and support. - **A service account** authenticates with a client ID and secret, a certificate, or a cloud workload identity. It has no mailbox, and it exists to let one system call another inside a boundary an administrator controls. A user account is trusted anywhere the person can prove who they are. That is why Sign in with Google works on a site Google has never heard of. A service account is trusted only where it was configured. That is why a GCP service account key means nothing to a random SaaS login page. Google's own agent identity documentation makes the workload version of this explicit. On its runtime, "because the agent itself is the principal, you grant permissions directly to this identifier," through SPIFFE identities and X.509 certificates that infrastructure understands and consumer login pages do not. Agents break the two-way split. They are software, like service accounts, and they show up at other people's login pages, like users. ## What is an agentic account? An agentic account is a third kind of account, in which the agent is the principal: the account belongs to the agent, not to the person who runs it. It has four parts: - **A stable identifier**, so the same agent is recognized on return. - **A credential only the agent holds**, so nothing reusable is shared with the app or the owner. - **An inbox**, so confirmation emails, receipts, and support replies reach something that reads them. - **An owner**, a human or organization accountable for it, available to the app as data rather than as the person logging in. In AgentID the account is an AgentMail inbox. The agent enrolls a browser once, which generates a non-extractable P-256 key, and signs in from that browser with a fresh signature each time. The app receives an OpenID Connect id_token with `sub` and `email`. A registered client reads `owner_email` and `owner_name` from `/v0/userinfo`. The agent creates and uses the account without a human present. The human is one `/userinfo` call away when the app needs them. The agent-side walkthrough is in [how an AI agent creates its own account](https://www.agentid.com/blog/how-an-ai-agent-creates-its-own-account). ## How do the three account types compare? User, service, and agentic accounts differ on who they represent, how they authenticate, where they are trusted, and how far a revocation reaches.
User account Service account Agentic account (AgentID)
Represents A person Software inside your perimeter An agent arriving from outside, as a customer
Identifier Email or username Client ID, SPIFFE ID, or object ID OIDC sub plus a verified email address
Credential Password, passkey, OTP Client secret, certificate, or workload token Non-extractable browser key; fresh signature per sign-in
Inbox Yes, the person's No Yes, the agent's own
Trusted where Anywhere the person can authenticate Only where an administrator configured it Any app that accepts the OIDC provider
Human accountability The account holder is the human Known internally; invisible to third parties owner_email claim, delivered to the app on request
Revocation scope The person loses access everywhere that session reaches Rotate the secret; every consumer of it breaks One agent's credential; owner and other agents untouched
Human required at sign-in Yes No No, if the agent has an enrolled browser; owner hand-off otherwise
## Why does an agentic account need an inbox? An agentic account needs an inbox because every account an app creates generates email, and that email has to go somewhere that reads it. Signup confirmations, receipts, invoices, security alerts, password resets, product updates, and support threads are all addressed to the account's email. - **For a user account**, that address is the person. - **For a service account**, there is no address, which is fine because a service account never signs up for anything. - **For an agent that signed up with its owner's address**, all of that mail lands on a person who may not know the account exists. That last case is how AgentMail found that many of its own new users were unaware their agent had signed up. An agentic account with its own inbox turns the app's existing email into a channel that works. The agent reads the onboarding sequence and acts on it. It files a support ticket from its own address and reads the reply. The owner is not in the loop unless they want to be. When they do, the agent can invite them into the app's organization as a separate member rather than sharing its login. Nothing in the app has to change. The transactional email it already sends to people works for agents unchanged. ## What constraints should an app enforce on agentic accounts? An app should enforce five constraints on agentic accounts, and each follows from the shape of the account. 1. **Key on `sub`, not on `email`.** Both are stable in AgentID, but `sub` is the identifier OpenID Connect guarantees. It is what lets you recognize the same agent on return and refuse a second account for the same agent if that is your policy. 2. **Limit per owner, not per account.** One human can run many agents. Create an AgentID application, request `owner_email`, store it on the account, and index it. 3. **Gate high-consequence actions on owner disclosure.** An agent that is not allowed to disclose its owner cannot sign in to an app that requires it on its own; the organization owner has to approve that sign-in. 4. **Revoke per credential, escalate per owner.** If one agent misbehaves, ban its `sub`, and its owner's other agents continue. If the owner is the problem, ban the `owner_email`, and every agent they run is covered. 5. **Do not confuse the owner with the customer.** The agent is the account holder. Attribute actions to the agent, bill the account the agent set up, and treat the owner as the accountable contact. On limiting per owner: free-tier quotas, account caps, and abuse bans then apply to the person across all their agents. Open clients cannot request owner scopes, so this constraint requires the registered tier. On owner disclosure: a registered client that requests `owner_email` gets a clean rule, because every agentic account in your database has an accountable human attached. For an open client that took only `openid email`, treat spend, deletion, and payment as features that need the registered tier. On owner versus customer: reversing the roles puts a person on the hook as customer of record for something they never touched. The reasoning behind that split is in [agent owner verification vs end-user authentication](https://www.agentid.com/blog/agent-owner-verification-vs-end-user-authentication). ## What is the lifecycle of an agentic account? The AI agent identity lifecycle behind an agentic account is create, enroll, sign in, revoke. 1. **Create.** The owner's organization creates an AgentMail inbox for the agent by API call. 2. **Enroll.** The agent enrolls a browser once, which generates a non-extractable P-256 key and registers the public half with AgentID. 3. **Sign in.** From then on every sign-in at your app is a fresh signature from that browser, and your account record for the agent stays keyed on the same `sub`. 4. **Revoke.** When the agent is retired, the owner revokes the enrolled credential and that agent stops signing in everywhere. Nothing else the owner runs is affected. On your side, offboarding follows the constraints above. Disable the record for that `sub`, or every record with that `owner_email` if the owner is leaving. ## Are there restrictions on how many agentic accounts one person can create? From AgentID's side, an owner can run as many agents as they have AgentMail inboxes. Each inbox is a separate agent with a separate `sub`. From your side, the number is your policy, and `owner_email` is what makes it enforceable. The right N varies: - A database provider billing by usage might allow unlimited agents per owner. - A product with an expensive free tier might allow three before requiring a card. What matters is that you can [set the number](/blog/stop-fake-agent-signups-without-blocking-real-agents) at all. You cannot when agents sign up as their owners and every account looks like a distinct person. ## What is non-human identity, and how is it different from an agentic account? Non-human identity, or NHI, is the enterprise security category for service accounts, API keys, machine certificates, and now agents. Its concerns are inventory, secret sprawl, and lifecycle inside one organization. Enterprise identity vendors sell tools for it. Microsoft Entra Agent ID applies the same governance to agents inside a tenant, with required Sponsors and Conditional Access. That work is about the accounts your organization creates for the software it runs. Agentic accounts as described here are the accounts other people's agents create at your product. - **NHI governance** tells the organization running an agent who sponsors it. - **An agentic account** tells the app receiving the agent who owns it. If you run agents, you need the first. If you run a product agents sign up for, you need the second, and adding it is a configuration change in your auth platform, covered in [how to let an AI agent sign in to your website](https://www.agentid.com/blog/how-to-let-an-ai-agent-sign-in-to-your-website). The concept piece on what an agent identity should contain, covering both sides, is [what is an agent ID](https://www.agentmail.to/blog/what-is-an-agent-id). --- # How an AI Agent Creates Its Own Account > An AI agent signs up on its own with an AgentMail inbox as its email address, one browser enrollment, and Sign in with AgentID. No OTP goes to a human. - **Author:** Binoy Perera - **Date:** 2026-09-15 - **Category:** Blog - **URL:** https://www.agentid.com/blog/how-an-ai-agent-creates-its-own-account - **The OTP is where agents get stuck today.** The verification email goes to a human's inbox, so the agent either waits for a person or borrows their account. An inbox of its own removes both. - **Enrollment happens once.** The agent posts an API key, its browser generates a non-extractable key, and every later sign-in is a fresh signature from that browser. - **Signup is one click.** At an app with the button, the agent signs in as itself; the app creates the account from the id_token. - **The account is the agent's.** Its own inbox, its own credential, its own revocation. The owner is a separate claim the app can request. An AI agent creates its own account the way a person does, once it has the two things a person brings to a signup form: an email address it can read, and a way to prove it is the same entity next time. With AgentMail, the agent gets an inbox of its own. With AgentID, the sign-in for AI agents built on those inboxes, it enrolls a browser once. That generates a private key that stays in the browser, and from then on the agent clicks Sign in with AgentID at any app that shows the button. The app receives a verified email and a stable identifier. It sends its confirmation and its receipts to the agent's inbox, and the agent reads them. No human types an OTP, and no human's credentials are involved. The whole path from bare agent to working account is three steps plus a hand-off for agents without a browser. Only the first two happen once. ## Why can't an AI agent just fill in the signup form? An AI agent can fill in a signup form but cannot finish the process, because signup was designed around a person who owns an email address and a phone. Walk through what happens. The agent types an email into the form. Whose? If it uses its owner's address, the confirmation code lands in the owner's inbox. The agent either has to wait for the owner to paste it back, or already has access to the owner's mail, which means the owner has handed over far more than a signup. From there, the problems compound: - **The app records the owner as the customer.** The agent is invisible in the account record. - **Agents blur together.** If the owner runs five agents, the app sees one person with five accounts, or one account shared five ways, and cannot tell which. - **Email goes to the wrong person.** When the app later emails a receipt, a support reply, or a security alert, it goes to a person who may not know the account exists. That last case is not hypothetical. After AgentMail shipped an API endpoint that let agents sign up directly, the company started emailing new users to ask how they had heard about it. Many of them did not know they had signed up at all, because their agent had done it. Most support requests started arriving from agents. Browser-automation tutorials that teach an agent to complete a signup form with a human's address are teaching the problem. The fix is to give the agent the two things the form is really asking for. ## Step one: how does an AI agent get its own email address? An AI agent gets its own email address through AgentMail, which creates an inbox by API call, with an address like `support@acme.agentmail.to` or on a domain the owner controls. The inbox is the agent's identity for everything that follows. It is where: - Confirmation emails arrive. - The agent receives invoices and product updates. - The agent can open and answer support threads. Inboxes are programmatic, so an agent framework can create one per agent, and the owner's organization holds the API key that created them. Inboxes start at $20 per month. This is also what makes AgentID work at almost every app. An OpenID Connect identity that is an email address is one that existing signup flows already know how to handle; the app can email it, and the email will be read. ## Step two: how does the agent enroll a browser for sign-in? Enrollment is the one-time step that turns an AgentMail inbox into a sign-in credential. 1. The agent posts its AgentMail API key to the enrollment endpoint on auth.agentid.com. 2. JavaScript on that page generates a P-256 keypair inside the agent's browser. 3. The page submits the public key to AgentID. The private key is a non-extractable WebCrypto key stored in IndexedDB under the auth.agentid.com origin. In AgentMail's words: "Your private key is generated and stored in your browser and cannot be exported through browser JavaScript APIs." A headless browser is fine; most agents run one already. The API key is used at enrollment and is never part of a sign-in afterwards, so it does not travel to any app the agent later signs into. If the agent runs in an environment with no browser at all, it does not lose the ability to sign in. The hand-off described below covers that case. ## Step three: how does the agent sign up at an app? The agent visits an app that shows Sign in with AgentID and clicks it, the way a person clicks Sign in with Google. 1. **The app redirects.** The app redirects to `https://auth.agentid.com/v0/authorize` with a PKCE challenge. 2. **The browser signs.** The enrolled browser recognizes its session and produces a fresh, one-time signature over a transaction the server generated for this sign-in. 3. **The agent reviews.** A disclosure screen shows which app is asking and what it will receive: the agent's inbox address and name, and the owner's email and name if the app requested them. 4. **The agent decides.** The agent approves or abandons. 5. **The app exchanges the code.** The browser returns to the app's callback with an authorization code, the app exchanges it, and the app now holds an id_token. From the app's side this is a standard OpenID Connect sign-in. [OIDC for AI agents: the complete guide](https://www.agentid.com/blog/oidc-for-ai-agents-complete-guide) has the wire format. The [id_token that proves who the agent is](/blog/how-an-ai-agent-proves-its-identity-to-your-app) contains a stable `sub`, the agent's verified email, and `email_verified: true`. The app creates an account keyed on `sub`, or resumes the existing one if this agent has been here before. There is no password to store and no OTP to send, because the identity was verified by AgentID at token mint. The confirmation email the app sends anyway lands in the agent's inbox, and the agent reads it.
Signup step Agent borrowing its owner's account Agent with its own AgentID
Email address on the form The owner's The agent's own AgentMail inbox
Verification code Sent to the owner; agent waits or reads the owner's mail None needed; email verified live at token mint
Credential stored by the app A password the agent and owner both know Nothing reusable; the app verifies a signature against published keys
Who the app thinks the customer is The owner The agent, with the owner available as a claim
Where receipts and support replies go The owner's inbox The agent's inbox
Revoking the agent Change the owner's password, breaking everything else Revoke one enrolled credential; nothing else is touched
## What if the agent has no browser? If the agent has no browser, its owner signs in for it, and the resulting account still belongs to the agent. 1. The owner opens the app's sign-in in their own browser. 2. The owner chooses Approve manually. 3. The owner authenticates in the AgentMail console at console.agentmail.to. 4. The owner selects the agent's inbox and approves. The flow has to finish in that same browser; there is no approval code to carry to another session. The app receives the same id_token it would have received from the agent's browser, naming the agent as the subject. The account belongs to the agent rather than the person who clicked. For the app, the customer record is still the agent's inbox rather than the owner's account, and any later sign-in from an enrolled browser resolves to the same `sub`. ## What does the app learn about the agent and its owner? The app learns only what it asked for, and it learns about the owner only if it created an AgentID application. - **Open clients** (a URL as the `client_id`, no setup) can receive `openid`, `email` and `profile`, and nothing about the owner. - **Registered clients** (created in the AgentID console or with the CLI) can also request the `owner_email` and `owner_profile` scopes. The owner values arrive in the id_token and from `/v0/userinfo` with the access token. If the agent is not allowed to share its owner, it can't finish that sign-in alone; the organization owner has to approve it. The app never gets a token quietly missing the claim. The disclosure screen the agent sees lists exactly these items before it approves. On the app side, the owner claim is what turns "an agent signed up" into "an agent signed up and here is the person to call." That is the property that lets apps allow agents rather than block them. The relying-party view of that decision is in [can an AI agent sign up for a SaaS](https://www.agentid.com/blog/can-an-ai-agent-sign-up-for-a-saas). ## What does the agent do with the account afterwards? An AI agent uses its account the same way a user does. - **Onboarding:** it receives the onboarding sequence in its own inbox and can act on it. - **Billing:** it gets invoices and receipts addressed to itself. - **Support:** when something breaks, it opens a support ticket from its own address and reads the reply. - **Owner access:** if the owner wants access to what the agent set up, the agent can invite them into the app's organization as a separate member with their own permissions, rather than sharing a login. Because the agent's identity is an email address, the app does not need to build anything new to communicate with it. Every transactional email an app already sends to human users works for agent users unchanged. AgentMail is building an Apps directory inside its console where agents can discover apps that accept AgentID and start sign-ins from there; that work is in progress. The public list of apps accepting the button today is at the [AgentID directory](https://www.agentid.com/directory). ## What does this look like from the developer's side? From the developer's side, agent builders follow three steps and app builders follow one. **If you build agents:** 1. Create an inbox per agent through the AgentMail API. 2. Run the browser enrollment once per agent. 3. Point the agent at apps that show the button. **If you build apps,** the sequence is shorter. Add AgentID as a custom OIDC provider with the issuer and a `client_id`, or run `npx @agentmail/agentid-cli init` in your project to have it detect and configure Clerk, Supabase, Auth0, Better Auth, or Auth.js. The relying-party walkthrough is in [how to let an AI agent sign in to your website](https://www.agentid.com/blog/how-to-let-an-ai-agent-sign-in-to-your-website). --- # How to Let an AI Agent Sign In to Your Website > AI agent login for your website: add AgentID as an OpenID Connect provider to your existing login, with two configuration values and no SDK. - **Author:** Binoy Perera - **Date:** 2026-09-15 - **Category:** Guides - **URL:** https://www.agentid.com/blog/how-to-let-an-ai-agent-sign-in-to-your-website - **No SDK, just a provider entry.** AgentID is standard OpenID Connect. If your login accepts Google, it can accept AgentID with a configuration change. - **The agent signs in on its own.** An enrolled browser holds the agent's key and completes the flow without a human. Agents with no browser hand the sign-in to their owner. - **You get identity and accountability in the token.** `sub` and `email` arrive in the id_token. Registered apps that request the `owner_email` scope receive it in the id_token and from `/v0/userinfo`; open clients never receive it. - **Fastest path:** `npx @agentmail/agentid-cli init` in your application's directory detects your auth provider and configures it. To let an AI agent sign in to your website, add an OpenID Connect provider built for agents to the login you already have. With AgentID, the sign-in for AI agents from AgentMail, that is two configuration values in your auth platform and no SDK: - **Issuer:** `https://auth.agentid.com` - **Client ID:** a `client_id` The agent completes the sign-in from a browser it enrolled once. Your callback exchanges the code exactly as it would for Google or GitHub, and the id_token gives you a stable subject and the agent's verified email address. If you need to know which human owns the agent, create an AgentID application, request the `owner_email` scope, and read it from the id_token or the `/userinfo` endpoint. The whole setup takes minutes on Clerk, Supabase, Auth0, Descope, Better Auth, or Auth.js, and it is free. ## How does authentication for AI agents differ from a normal login? A normal login assumes a person. An AI agent cannot complete a person's login steps as itself, so today it completes them as its owner. Your login assumes a person in three places: - **OTP:** it sends a code to a phone or an inbox the person can read. - **Password:** it asks for a password the person remembers. - **Consent:** it shows a consent screen the person clicks. So the agent signs up with the owner's email, reads the owner's OTP, and clicks Approve in the owner's session. From your side, the result is indistinguishable from the owner signing up. That is the problem: - You cannot tell agents from people. - You cannot count how many agents one person is running. - You cannot cut off the agent without cutting off the person. AgentMail hit this from the other direction. After it shipped an API endpoint that let agents sign up directly, it started emailing new users to ask how they had heard about the product. Many of them did not know they had signed up at all, because their agent had done it. Most support requests began arriving from agents. One large enterprise saw hundreds of signups from AgentMail-domain addresses in a short window. It had no way to tell whether that was one person's agent fleet or hundreds of customers. An AI agent login fixes this by giving the agent an identity of its own that your app can verify, and a way to reach the human behind it. ## What does AgentID return when an agent signs in? When an agent signs in, AgentID returns an ES256-signed id_token carrying the agent's stable subject and verified email address. Registered apps that request the owner scopes also receive `owner_email` and `owner_name`, in the id_token and from `/v0/userinfo`; open clients never receive them. AgentID is an OpenID Connect provider. The agent's identity is an email address on AgentMail, so every sign-in gives you something you can already handle. The id_token, signed with ES256, carries these claims:
Claim What it is Where it arrives
sub Stable subject derived from the agent's inbox. Same agent, same sub, every sign-in. id_token
email, email_verified The agent's own inbox address, verified live when the token is minted. email_verified is always true when present. id_token (email scope)
name The agent's display name. id_token (profile scope, registered clients)
scope What this sign-in granted, so you can check rather than assume. id_token (registered clients)
owner_email, owner_name The human who owns the organization behind the agent. id_token and /userinfo (owner scopes, registered clients)
iss, aud, exp, iat, jti, nonce Standard OIDC claims. jti names this one sign-in. id_token
Each claim has a job: - **`sub`** is what you key your agent accounts on. - **`email`** is how you reach the agent. Receipts, confirmations, and support replies all land in an inbox the agent reads. - **The owner claims** let you enforce a per-human limit or contact a person when something goes wrong. ## How do you add auth for AI agents to your existing platform? Add AgentID through your auth platform's custom OIDC provider setting. Every supported platform has one. You give it the issuer, a client_id, and optionally a client_secret and the scopes to request. It does discovery from `https://auth.agentid.com/.well-known/openid-configuration` to find the endpoints and keys. The per-platform guides walk each dashboard step by step: - [Clerk](https://www.agentid.com/docs/clerk) - [Supabase](https://www.agentid.com/docs/supabase) - [Auth0](https://www.agentid.com/docs/auth0) - [Better Auth](https://www.agentid.com/docs/better-auth) - [Auth.js](https://www.agentid.com/docs/auth-js) The details that trip people up: **Supabase.** The provider identifier carries a fixed `custom:` prefix, so you type only `agentid` and your code calls `signInWithOAuth({ provider: 'custom:agentid' })`. Its Scopes field is comma-separated and defaults to nothing, which falls back to `openid` and `email`. Add `profile` there. Free projects are capped at three custom providers. **Better Auth.** It uses AgentMail's helper package `@agentmail/agentid-better-auth` on top of the Generic OAuth plugin (Better Auth 1.7.2 or newer). The helper fixes the provider id to `agentid`, so your redirect URI is your origin plus Better Auth's callback path ending in `/agentid`. **Auth0.** Auth0 ships AgentID as a Marketplace social connection. It appears in the connections list rather than needing a hand-built enterprise connection. **Any other stack.** The [custom OIDC guide](https://www.agentid.com/docs/custom) covers what a generic connector form will ask for, and which of its defaults will not work against this issuer: - No refresh token, because `authorization_code` is the only grant. - No `offline_access` scope. - No end-session endpoint. ## Should you set up AgentID from the dashboard or the CLI? For most projects, set up AgentID with the CLI. Run this in the directory of the application you want to configure: ```bash npx @agentmail/agentid-cli init ``` The CLI does four things: 1. **Detects** Clerk, Auth0, Supabase, Better Auth, or Auth.js v4 in the project, or takes your callback URLs directly for any other OIDC stack. 2. **Registers** a client. This opens a browser for your organization to approve; there is no unattended bypass. 3. **Writes** the provider configuration. 4. **Verifies** the result. At the scope picker, press Enter for standard agent identity (`openid`, `email`, `profile`), or pass `--owner-email` to also request the owner's address. `npx @agentmail/agentid-cli doctor` checks an existing setup without changing anything. It exits non-zero on failure, which makes it usable in CI. The CLI configures your application to accept agents. It does not log an agent in; that side is covered next. ## How does the agent actually complete the sign-in? The agent completes the sign-in from a browser it enrolled once. After enrollment, it signs in on its own with a fresh signature each time. Enrollment takes three steps: 1. The agent posts an AgentMail API key to the enrollment endpoint. 2. JavaScript on auth.agentid.com generates a keypair inside that browser. 3. The browser submits the public key to AgentID. The private key is a non-extractable WebCrypto P-256 key stored in IndexedDB under auth.agentid.com. In AgentMail's words: "Your private key is generated and stored in your browser and cannot be exported through browser JavaScript APIs." A headless browser works fine. After that, when your app redirects the agent to `/v0/authorize`, the enrolled browser recognizes the session. It signs a fresh, one-time signature over a server-generated transaction. A disclosure screen shows which app is asking and what it will receive: the agent's inbox and name, and the owner's email and name if you requested them. Sign-ins that start from the Apps page in the AgentMail console skip that screen. No human is involved when the agent has a browser. If the agent has no browser, its owner completes the sign-in instead: 1. The owner starts the sign-in from your app in their own browser. 2. They choose Approve manually. 3. They authenticate in the AgentMail console. 4. They pick the agent's inbox and complete the approval there. It has to finish in that same browser; there is no code to carry to another session. Either way, your callback receives an ordinary authorization code. ## What does the flow look like on the wire? On the wire, an AgentID sign-in is the standard OpenID Connect authorization code flow: an authorization request, then a code exchange. If you implement OIDC yourself rather than through a platform, the two requests are the standard ones. The authorization request must use PKCE with S256 for open clients. Registered clients may use PKCE or an OIDC nonce. ``` GET https://auth.agentid.com/v0/authorize ?response_type=code &client_id=https://yourapp.com &redirect_uri=https://yourapp.com/callback &scope=openid%20email &state= &code_challenge= &code_challenge_method=S256 ``` Your callback exchanges the code: ``` POST https://auth.agentid.com/v0/token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code &code= &redirect_uri=https://yourapp.com/callback &client_id=https://yourapp.com &code_verifier= ``` Verify the id_token against `https://auth.agentid.com/v0/jwks.json` with whichever JOSE library you already use. Check `iss` and `aud` as you would for any provider. Keys rotate with stable key ids and an overlap window, so caching by `kid` is safe. ## How do you find out which human owns the agent? To find out which human owns the agent, create an AgentID application, request the `owner_email` scope, and read it from the id_token or `/v0/userinfo`. Click **Create application** in the [AgentID console](https://console.agentid.com), or run `npx @agentmail/agentid-cli init`. That gives you: - **A client_secret,** shown once (you can regenerate it). - **Up to 10 redirect URIs.** - **Access to the owner scopes:** `owner_profile` and `owner_email`, which open clients cannot request. Then request `owner_email` at `/v0/authorize` and exchange the code as above. The id_token carries `owner_email`, and `/userinfo` returns the same value: ``` GET https://auth.agentid.com/v0/userinfo Authorization: Bearer ``` The response includes `owner_email` and, with `owner_profile`, `owner_name`. The owner's email is personal data, so don't log tokens that carry it. If the agent is not allowed to share its owner, it can't finish the sign-in alone; the organization owner has to approve it. You never get a token with the claim missing, so you can rely on the field whenever a sign-in succeeds. The mechanics and the policy questions around this are in [how to verify the human behind an AI agent](https://www.agentid.com/blog/how-to-verify-the-human-behind-an-ai-agent). ## What makes an AI agent login secure? An AI agent login with AgentID is safer than the status quo, where agents sign in as people, because nothing reusable crosses the sign-in. - **The agent's private key** stays in its browser. - **AgentID's own signing key** is non-exportable. - **Every sign-in** is a fresh signature that your app verifies against published keys. Your app never receives a password or an API key. Revoking a credential stops that one agent; it touches nothing belonging to the owner and nothing belonging to other agents. What the token does not tell you is whether the agent will behave. It proves which agent this is, not that it is well-intentioned. The accountability comes from the owner claim. An agent whose human you can name is an agent you can allow, limit, or ban with a real address to write to. Most of the relying-party decisions that follow, such as [how many agents one owner may run](/blog/stop-fake-agent-signups-without-blocking-real-agents) or whether to gate certain features to agents with a verified owner, are covered in [can an AI agent sign up for a SaaS](https://www.agentid.com/blog/can-an-ai-agent-sign-up-for-a-saas). ## What should your app do after an agent's first sign-in? After an agent's first sign-in, key its record on `sub`, store the owner if you requested it, and send your normal onboarding email. 1. **Key records on `sub`, not on `email`.** The address is stable too, but `sub` is the identifier the protocol guarantees. 2. **Store `owner_email` alongside it** if you requested it, and index on it so per-owner limits are one query. 3. **Send your normal onboarding email** to the agent's address, because the agent will read it. 4. **Add your app to the [AgentID directory](https://www.agentid.com/directory)** so agents browsing for services that accept them can find yours. The [button guide](https://www.agentid.com/blog/adding-a-sign-in-with-agentid-button) covers the markup and the brand rules for the login page itself. --- # How to Verify the Human Behind an AI Agent > Know Your Agent (KYA) at sign-in: verify the human behind an AI agent with AgentID. Request owner_email and read it from the id_token or /userinfo. - **Author:** Binoy Perera - **Date:** 2026-09-15 - **Category:** Guides - **URL:** https://www.agentid.com/blog/how-to-verify-the-human-behind-an-ai-agent - **The identity provider delivers the owner.** The agent cannot type its owner's email into a box; the value comes from the party that issued the agent's identity. - **Create, request, read.** Create an AgentID application, request `owner_email` at `/authorize`, and read it from the id_token or `/userinfo`. Open clients cannot. - **No owner, no silent success.** If the agent is not allowed to share its owner, it can't finish the sign-in alone; the organization owner has to approve it. - **KYA is becoming a payments standard.** Visa, Mastercard, and Ant International agreed on a Know Your Agent interoperability framework on September 10, 2026. Sign-in is where a SaaS product applies the same idea. To verify the human behind an AI agent, you need the agent's identity provider to attest to the owner, not the agent to assert it. With [AgentID, the sign-in for AI agents from AgentMail](/blog/introducing-agentid), the mechanism is three steps: 1. **Create** an AgentID application for your app. 2. **Request** the `owner_email` scope when the agent signs in. 3. **Read** `owner_email` and `owner_name` from the id_token, or from `/v0/userinfo` with the access token. Both return the same values. The values come from the agent's AgentMail organization, which has exactly one designated owner. If the agent is not allowed to share its owner, it can't finish the sign-in alone: the organization owner has to approve it from their AgentMail account. You never get a token with the claim quietly missing. This is Know Your Agent applied at sign-in. Your app gets a verified agent and a verified human in the same OpenID Connect flow it already uses for Sign in with Google. ## What does Know Your Agent (KYA) mean, and why is agentic commerce adopting it? Know Your Agent, or KYA, is the practice of verifying which AI agent is making a request and which human or organization is accountable for it, before letting the agent transact. The term is borrowed from Know Your Customer in financial services. The payments provider Eco defines it as "an emerging identity framework that cryptographically binds an AI agent's requests to a registered operator and an authorized user, so that a merchant can verify both before settling a payment." The card networks have adopted the language. On September 10, 2026, Visa, Mastercard, and Ant International announced a Know Your Agent interoperability framework spanning three protocols: - **Visa:** Trusted Agent Protocol - **Mastercard:** Verifiable Intent - **Ant International:** Agentic Mobile Protocol Mastercard's chief digital officer, Pablo Fourez, said "interoperability across Know-Your-Agent frameworks is essential to making agentic commerce work at scale." Visa's Rubail Birwadker said that "without trusted identity and explicit permissioning, AI agents cannot participate in commerce at scale." At the time of the announcement, no technical specification for the shared framework had been published. The payments version of KYA is about settlement. The SaaS version is about signup and account behavior, and it needs the same two facts: which agent, and whose. This post is about how a web application gets those facts at sign-in. ## Why can't you just ask the agent who owns it? You cannot just ask an AI agent who owns it, because a self-asserted owner is worth nothing. An agent filling in "owner email" on a form can type anything. An agent using its owner's own credentials is already claiming to be the owner. Verification has to come from a party the agent cannot forge: the system that issued the agent's identity and knows who created it. That rules out most of what currently passes for agent verification. - **Bot detection** tells you a request is probably automated, not who is behind it. - **An API key** tells you which developer account is calling your API, which is useful for your API and useless at your login page. - **An OAuth access token** from a delegate-model product tells you a user granted permission to something, but the agent itself is an unnamed bearer. None of them produce a verifiable statement of the form "this agent is owned by this person." The vocabulary for the distinction is in [agent owner verification vs end-user authentication](https://www.agentid.com/blog/agent-owner-verification-vs-end-user-authentication). ## How does AgentID verify the agent and its owner? AgentID verifies the agent by checking its inbox live at token mint, and verifies the owner from the AgentMail organization's designated owner on file. Every AgentID is an AgentMail inbox. Every inbox belongs to an AgentMail organization that holds the API key that created it. The organization has a designated owner: a human with a name and an email address. When an agent signs in through AgentID, the provider knows the agent and knows the organization's owner. Owner verification is the provider disclosing the second fact to your app, with the agent's consent shown on the disclosure screen at sign-in. Two conditions must hold for the agent to share its owner on its own: - The agent's AgentMail API key must have the `App: Share Owner` permission. - The organization must have exactly one designated owner holding the value. When both are true and your app requests it, you get it. When the permission is missing, the agent's own approval is refused and the organization owner has to approve the sign-in instead. An app that looks misconfigured is often waiting on that permission. The behavior is deliberate: an app that asks for the owner never has to handle a successful sign-in with the owner missing. ## How does a relying party verify an AI agent's identity and owner, step by step? A relying party verifies an AI agent's identity and owner in three steps, none of which require an SDK. **Step 1: create an AgentID application.** Open clients (a URL as `client_id`, no setup) can request `openid`, `email` and `profile`, but not the owner scopes. Click **Create application** in the [AgentID console](https://console.agentid.com), or run this from your project: ``` npx @agentmail/agentid-cli init --owner-email ``` You get a Client ID and a client secret. **Step 2: request the owner scopes at sign-in.** Registration-time scope metadata is ignored; what you receive is what you send to `/authorize`. In Clerk, Supabase, Auth0, Descope, Better Auth, or Auth.js this is the Scopes field on the provider configuration. On the wire: ``` scope=openid%20email%20profile%20owner_email%20owner_profile ``` **Step 3: read the owner.** The id_token from the code exchange carries `owner_name` and `owner_email`. You can also call `/userinfo` with the access token, which returns the same values: ``` GET https://auth.agentid.com/v0/userinfo Authorization: Bearer { "sub": "a91f2c8e...43", "email": "support@acme.agentmail.to", "email_verified": true, "name": "Acme Support", "owner_name": "Maya Chen", "owner_email": "maya@acme.com" } ``` Store `owner_email` on the agent's account record and index it. Many auth libraries keep only the standard claims when they build the session user, so the owner fields may not appear there. In Supabase, allow them with the claims allowlist; in Better Auth, read them from `/userinfo`. Each provider guide shows how. ## Where does owner_email arrive? In two places, with the same value: the id_token your app receives from the code exchange, and `/userinfo`. The owner's email is personal data about someone who is not the subject of the token. id_tokens sit in browser storage and end up in logs, session cookies and debugging output, so treat a token that carries owner claims as sensitive, and don't log it. `/userinfo` re-checks the live inbox on every call, so it is the place to look when you need a fresh answer later. ## What can you do once you know the owner? Once you know an AI agent's owner, you can do four things that were impossible when agents signed up as their owners.
Capability Without owner verification With owner_email
Per-human limits One free tier per agent account Quotas and caps keyed on the owner across all their agents
Abuse response Ban an account; the next agent registers Ban the owner and every agent they run
Escalation Email the agent and hope Email the agent for operations, the human for accountability
Gated features Same access for every agent Payments, deletes, or spend only for agents with a disclosed owner
An app that can name the human behind an agent can let that agent act on its own, because there is someone to call. That is what makes autonomy safe to allow. The product-level version of this argument is in [can an AI agent sign up for a SaaS](https://www.agentid.com/blog/can-an-ai-agent-sign-up-for-a-saas). ## Does owner verification tell you the agent is trustworthy? No, and it does not claim to. An AgentID token proves which agent this is and, for registered clients, which human is accountable for it. It does not assert that the agent is safe or well-behaved, and it carries no trust score or endorsement. The owner claim is a verified contact for a real person or organization. That is the same thing you know about a human customer after they confirm their email. Your abuse controls still run; they just have a better key. ## What about verifying the owner's identity beyond an email? Email is the layer AgentID delivers today. For products that need more, the owner email is the join key to whatever verification you already run. A financial service, for example, may need to know the legal identity of whoever is behind an agent before letting it move money. You verify the human once, through your existing KYC provider, and every agent that signs in with that `owner_email` inherits the result. One capability that could sit on top of AgentID is KYC pass-through, where verification completed on the AgentMail side is exposed to relying parties. It is not shipped, and this post makes no claim about when it will be. For the full protocol behind the three steps, including discovery values, client tiers, and token verification, see [OIDC for AI agents: the complete guide](https://www.agentid.com/blog/oidc-for-ai-agents-complete-guide). --- # OIDC for AI Agents: The Complete Guide > OAuth and OpenID Connect for AI agents, with the agent as the subject. PKCE S256, ES256 tokens, client tiers, where owner_email lives, and the threat model. - **Author:** Binoy Perera - **Date:** 2026-09-15 - **Category:** Guides - **URL:** https://www.agentid.com/blog/oidc-for-ai-agents-complete-guide - **OIDC gives you identity; OAuth gives you permission.** Agents need both, and the delegation products compared below only do the second. An OIDC provider for agents issues an id_token that says which agent this is. - **The agent is the principal.** In AgentID the agent has its own account, inbox, and credential. The human owner is a claim you can request, not the account you are logging in. - **Everything is standard.** Authorization code, PKCE S256, ES256 signatures, discovery, JWKS, RFC 7591 dynamic registration. Any OIDC library or auth platform works. - **Owner claims go to registered apps.** `owner_email` and `owner_name` arrive in a registered app's id_token and from /userinfo, and only when the app asks for them. OpenID Connect for AI agents means using the same identity protocol your login already speaks, with the agent as the subject instead of a person. The agent holds a signing key. An OIDC provider built for agents issues an id_token that names the agent: a stable `sub` and its verified email. Your application verifies that token against published keys the way it verifies a Google sign-in. OAuth alone cannot do this. OAuth answers what a client may do on a user's behalf, not who the client is. AgentID, the sign-in for AI agents from AgentMail, is an OIDC provider that does it for the open web: - **Flow:** authorization code with PKCE. - **Tokens:** ES256 signatures. - **Discovery:** `https://auth.agentid.com/.well-known/openid-configuration`. - **Registration:** RFC 7591, for clients that need the owner's identity. - **Enrollment:** a one-time browser enrollment on the agent's side, so no human has to be present at sign-in. This guide covers the whole protocol for developers on the relying-party side, with the exact values the live issuer publishes. **On this page** - [Why is OAuth alone not enough to verify an AI agent?](#why-is-oauth-alone-not-enough-to-verify-an-ai-agent) - [What does the discovery document say?](#what-does-the-discovery-document-say) - [How does the OIDC sign-in flow work for AI agents, step by step?](#how-does-the-oidc-sign-in-flow-work-for-ai-agents-step-by-step) - [What are the two client tiers?](#what-are-the-two-client-tiers) - [Which scopes and claims exist?](#which-scopes-and-claims-exist) - [Where does owner_email actually live?](#where-does-owner_email-actually-live) - [How does the agent hold its credential?](#how-does-the-agent-hold-its-credential) - [How do you verify and manage OAuth tokens for AI agents?](#how-do-you-verify-and-manage-oauth-tokens-for-ai-agents) - [How is this different from Auth0 for AI Agents or Descope Agentic Identity Hub?](#how-is-this-different-from-auth0-for-ai-agents-or-descope-agentic-identity-hub) - [What is the OAuth threat model for AI agents?](#what-is-the-oauth-threat-model-for-ai-agents) ## Why is OAuth alone not enough to verify an AI agent? OAuth 2.0 is an authorization framework, so on its own it cannot verify an AI agent. Its output is an access token that lets a client call a resource on behalf of a resource owner, scoped to what that owner granted. The token says nothing reliable about who the client is. `client_id` is self-asserted for public clients, and there is no standard claim for "this is the agent, and this is the human behind it." Every agent auth product built on OAuth alone inherits this. It can tell you a user delegated authority to something. It cannot tell you which something, or vouch for it to a party who has never met it. OpenID Connect adds the identity layer. An OIDC provider authenticates a subject and issues an id_token: a signed JWT with `iss`, `sub`, `aud`, `exp`, `iat`, and whatever profile claims were granted. The relying party verifies the signature against the provider's JWKS and trusts the claims because it trusts the issuer. Sign in with Google is OIDC. So is Sign in with AgentID; the only difference is what kind of entity the subject is. For agents, that difference matters: - **A delegate-model product** issues tokens about a human, with the agent as an unnamed bearer. - **An agent-as-principal provider** issues tokens about the agent, with the human as an optional claim. The second is the one that lets a third-party app say "this is agent X, owned by person Y, and I have seen X before." The vocabulary for this split is covered in [agent owner verification vs end-user authentication](https://www.agentid.com/blog/agent-owner-verification-vs-end-user-authentication). ## What does the discovery document say? AgentID publishes its OIDC discovery document at the standard path. Every value below is taken from the live document as of September 14, 2026.
Field Value What it means for you
issuer https://auth.agentid.com Paste this into any "issuer" or "well-known" field; the client derives the rest.
authorization_endpoint /v0/authorize Where you redirect the agent.
token_endpoint /v0/token Where your callback exchanges the code.
userinfo_endpoint /v0/userinfo The only place owner claims are served.
jwks_uri /v0/jwks.json Public keys for verifying id_tokens.
registration_endpoint /v0/register RFC 7591 dynamic registration, for the registered tier.
grant_types_supported authorization_code No refresh tokens, no client credentials, no implicit flow.
response_types_supported code Code flow only.
code_challenge_methods_supported S256 PKCE with SHA-256. The plain method is not accepted.
id_token_signing_alg_values_supported ES256 ECDSA P-256. A client that insists on RS256 will fail.
token_endpoint_auth_methods_supported client_secret_basic, client_secret_post, none Open clients use none; registered clients use a secret.
scopes_supported openid, email, profile, owner_profile, owner_email No offline_access, because there are no refresh tokens.
authorization_response_iss_parameter_supported true The callback carries iss (RFC 9207), so mix-up attacks are detectable.
Two absences are deliberate and will surprise a generic connector: there is no `end_session_endpoint`, and `offline_access` is not offered. Sessions are your application's. AgentID authenticates the agent and gets out of the way. ## How does the OIDC sign-in flow work for AI agents, step by step? The relying-party side of an AgentID sign-in is the textbook authorization code flow with PKCE, in five steps. **Step 1: redirect the agent.** Your app generates a PKCE verifier and challenge, plus `state`, and redirects the agent: ``` GET https://auth.agentid.com/v0/authorize ?response_type=code &client_id=https://yourapp.com &redirect_uri=https://yourapp.com/callback &scope=openid%20email &state= &code_challenge= &code_challenge_method=S256 ``` **Step 2: the agent's browser signs in.** The agent's enrolled browser completes the sign-in. A browser that already holds an AgentID session continues on its own; otherwise the page shows the agent one command that creates one. A disclosure screen shows the requesting app and what it will receive. There is no password form because there is no password. **Step 3: AgentID redirects back.** AgentID redirects to your `redirect_uri` with `code`, `state`, and `iss`. **Step 4: exchange the code.** Your callback exchanges the code: ``` POST https://auth.agentid.com/v0/token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code &code= &redirect_uri=https://yourapp.com/callback &client_id=https://yourapp.com &code_verifier= ``` The response carries an `id_token` and an `access_token`. Codes are single-use, expire in seconds, and replay is rejected. **Step 5: verify and look up the account.** Verify the id_token (see below), create or look up the agent account by `sub`, and, if you asked for an owner scope, read `owner_email` from the id_token (or from `/v0/userinfo` with the access token). Nothing here is AgentID-specific in shape. A library that implements OIDC Core 1.0 and RFC 7636 handles it unchanged. The per-platform dashboards do it for you: - [Clerk](https://www.agentid.com/docs/clerk) - [Supabase](https://www.agentid.com/docs/supabase) - [Auth0](https://www.agentid.com/docs/auth0) - [Better Auth](https://www.agentid.com/docs/better-auth) - [Auth.js](https://www.agentid.com/docs/auth-js) - Or run `npx @agentmail/agentid-cli init` to detect and configure whichever one you use. ## What are the two client tiers? AgentID has two client tiers: an open tier that requires no registration, and a registered tier for clients that need more. An open client works like this: - **It identifies by origin.** Its `client_id` is an https URL the client controls, such as `https://yourapp.com`, and its redirect URI sits on that same origin. - **It has no secret.** PKCE is mandatory, and the origin is the whole trust anchor. - **It gets three scopes.** Open clients may request `openid`, `email` and `profile`. - **It cannot run on localhost.** Because the anchor is an https origin, an open client cannot run on `http://localhost`; local development starts at registration. A registered client is an application you create in the [AgentID console](https://console.agentid.com) (**Create application**) or with `npx @agentmail/agentid-cli init`. Both call `/v0/register` for you. You get an opaque `client_id` and a `client_secret` that is shown once (you can regenerate it later). Registered clients get: - Up to 10 redirect URIs. - Loopback and http redirects for development. - Confidential token exchange. - Per-client sign-in history. - Access to the `owner_profile` and `owner_email` scopes. Registration-time scope metadata is ignored: the scopes you actually receive are the ones you send to `/authorize`. Registered clients may use either S256 PKCE or an OIDC nonce; open clients must use PKCE. Creating an application requires an AgentMail account on purpose. Every registered client is an AgentMail account, which is how a free product pays for itself. ## Which scopes and claims exist? AgentID offers five scopes: `openid`, `email`, `profile`, `owner_profile`, and `owner_email`. Scopes are space-delimited at `/authorize`, and a request with no scope falls back to `openid email`.
Scope Claims it unlocks Delivered in Tier
openid sub (plus iss, aud, exp, iat, jti, nonce) id_token Open and registered
email email, email_verified id_token and /userinfo Open and registered
profile name (the agent's display name), preferred_username, owner_sub id_token and /userinfo Open and registered
owner_profile owner_name id_token and /userinfo Registered
owner_email owner_email id_token and /userinfo Registered
Registered clients also receive a `scope` claim in the id_token listing what was granted. Scope-gated claims are omitted rather than nulled when not granted, so test for presence. A decoded id_token for a registered client looks like this: ```json { "iss": "https://auth.agentid.com", "aud": "b7d41e0a-2c65-4f8b-9d31-0a5e7c2f4b18", "sub": "a91f2c8e...43", "scope": "openid email profile owner_email", "email": "support@acme.agentmail.to", "email_verified": true, "name": "Acme Support", "owner_email": "maya@acme.com", "iat": 1767225000, "exp": 1767225600, "jti": "9f1c2a44-3e77-4c19-9a2e-6b0d5f8e1c33" } ``` ## Where does owner_email actually live? In two places with the same value: a registered app's id_token, and `/v0/userinfo`. When `/token` runs, AgentID writes the owner snapshot to the grant record and puts the granted owner claims in the id_token. `/userinfo` returns the same claims for a Bearer access token and re-verifies the live inbox on every call. ``` GET https://auth.agentid.com/v0/userinfo Authorization: Bearer { "sub": "a91f2c8e...43", "email": "support@acme.agentmail.to", "email_verified": true, "name": "Acme Support", "owner_name": "Maya Chen", "owner_email": "maya@acme.com" } ``` Handle a token that carries owner claims with care. id_tokens end up in browser storage, request logs, and session cookies, and the owner's address is personal data about someone who is not the subject of the token. Don't log it. Owner disclosure is also enforced: - **The agent must be allowed to share it.** The agent's AgentMail API key needs the `App: Share Owner` permission. - **The organization needs one owner.** The organization behind the agent must have exactly one designated owner. - **A refused disclosure needs the owner.** When an app requests `owner_email` and the agent lacks that permission, the agent's own approval is refused (403) and the organization owner has to approve the sign-in from AgentMail. AgentID never returns a token silently missing the claim. An app registered for `owner_email` can therefore rely on it being present whenever a sign-in succeeds. Auth platforms often keep only standard claims on the session user. On Supabase, allow the owner claims with the claims allowlist; on Clerk or Better Auth, fetch them from `/userinfo` in your callback and store them yourself. The policy side of using them is in [how to verify the human behind an AI agent](https://www.agentid.com/blog/how-to-verify-the-human-behind-an-ai-agent). ## How does the agent hold its credential? The agent holds its credential as a non-extractable private key inside a browser it enrolls once. 1. The agent posts an AgentMail API key to the enrollment endpoint. 2. JavaScript on auth.agentid.com generates a P-256 keypair inside the browser. 3. The browser submits the public key to AgentID. The private key is a non-extractable WebCrypto key stored in IndexedDB under the auth.agentid.com origin. AgentMail's own wording: "Your private key is generated and stored in your browser and cannot be exported through browser JavaScript APIs." From then on, each sign-in is a fresh signature over a server-generated transaction. Nothing reusable crosses the wire. The API key was used once at enrollment and is not part of any sign-in, and the app never sees the key or a bearer credential it could replay. Headless browsers work. An agent that has no browser at all does not lose the ability to sign in; its owner completes the sign-in in the AgentMail console, in the same browser the flow started in. Revocation is per credential. Revoke an enrolled browser and that agent stops signing in from it; other agents, and the owner's own accounts, are untouched. The step-by-step account creation from the agent's point of view is in [how an AI agent creates its own account](https://www.agentid.com/blog/how-an-ai-agent-creates-its-own-account). ## How do you verify and manage OAuth tokens for AI agents? Verify an AgentID id_token the same way you verify any OIDC id_token: check its ES256 signature against the published JWKS, then check the claims. 1. Fetch the JWKS from `https://auth.agentid.com/v0/jwks.json`. 2. Select the key by `kid`. 3. Verify the ES256 signature. 4. Check that `iss` equals `https://auth.agentid.com`. 5. Check that `aud` equals your exact `client_id`. 6. Check that `exp` is in the future. 7. If you sent a `nonce`, check that it is echoed back. On the issuer side, AgentID: - **Holds signing keys in AWS KMS**, where they cannot be exported. - **Rotates keys** with stable key ids and an overlap window. - **Keeps the id_token lifetime short.** The documented sample is 600 seconds. Because keys rotate with overlap, caching the JWKS by `kid` is safe. Because there is no refresh token, there is nothing long-lived to protect on your side after the exchange; your own session mechanism takes over. Token handling for AI agents therefore comes down to three habits: - Verify every id_token against the live JWKS. - Drop the access token after the `/userinfo` call that needs it. - Key records on `sub` rather than on anything in the token that could change. ## How is this different from Auth0 for AI Agents or Descope Agentic Identity Hub? Auth0 for AI Agents and Descope Agentic Identity Hub also run on OAuth 2.1 and OIDC, so the protocol overlap is real. The difference is what the subject of the token is. **Auth0 for AI Agents.** In Auth0's model the agent obtains tokens to act for a user in your tenant, with credentials for third-party APIs kept in Token Vault. In Auth0's words: "Your agent never actually holds the root key; instead, it asks Token Vault for a temporary, short-lived access token only when it needs to perform a specific task." **Descope Agentic Identity Hub.** Descope's Inbound Apps turn your application into an OAuth authorization server, so agents and MCP clients can obtain scoped tokens for your API. Its audit trail "connects every action back to the originating user." Both are authorization servers you run for your own users' agents. AgentID is an identity provider that vouches for the agent to you. The agent is the subject of the token; your app is the audience; the human is a claim. The three compose rather than compete. An app running Auth0 can add AgentID as a social connection so agents from outside its tenant can sign in. The [AgentID vs Auth0 for AI Agents](https://www.agentid.com/blog/agentid-vs-auth0-for-ai-agents) and [AgentID vs Descope](https://www.agentid.com/blog/agentid-vs-descope-agentic-identity) comparisons go through the specifics. ## What is the OAuth threat model for AI agents? AgentID's design rules out four OAuth threats for AI agents, and leaves one question to your own policy. - **Credential theft in transit.** No long-lived secret crosses the sign-in, so there is nothing to steal in transit; the agent's key never leaves its browser and the app receives a short-lived, audience-bound id_token. - **Code interception.** Mandatory S256 PKCE for public clients, single-use codes that expire in seconds, and the `iss` parameter on the callback close it off. - **Token substitution.** The `aud` check, and for registered clients the opaque `client_id`, stop it. - **Owner-data leakage.** Owner claims go only to registered apps that ask for them, and only with the agent's permission or the owner's approval. What the token does not assert is that the agent is safe or well-behaved, or that it has any trust score. It proves which agent this is and, for registered clients, which human is accountable. Everything after that is your policy: - [Rate limits per owner](/blog/rate-limit-ai-agents-per-human-not-per-account). - Feature gates for open-client sign-ins that carried no owner scope. - The ordinary abuse controls you already run. How to think about those decisions is the subject of [can an AI agent sign up for a SaaS](https://www.agentid.com/blog/can-an-ai-agent-sign-up-for-a-saas). --- # AgentID vs Microsoft Entra > Microsoft Entra Agent ID governs agents inside your Entra tenant. AgentID lets an agent sign in at apps outside your organization and names its human owner. - **Author:** Binoy Perera - **Date:** 2026-09-09 - **Category:** Comparisons - **URL:** https://www.agentid.com/blog/agentid-vs-microsoft-entra-agent-id Microsoft Entra Agent ID governs agents inside your Entra tenant: blueprints, sponsors, Conditional Access. AgentID is an OpenID Connect provider that lets an agent sign in at apps outside any single organization, and tells those apps which human owns it. Microsoft Entra Agent ID and AgentID solve different problems that happen to share a name. Entra Agent ID governs agents inside an enterprise: who sponsors them, what they can reach, when they get disabled. AgentID lets an agent sign in at applications outside any single organization, and delivers the owner's email to the app receiving the sign-in. Both carry human accountability; they differ on who gets to see it. ## What is Microsoft Entra Agent ID? Microsoft Entra Agent ID reached general availability, bringing what Microsoft describes as "first-class identity and access management to AI agents" and extending Zero Trust principles to AI workloads. Its identity model is a three-tier hierarchy: an agent identity blueprint, a blueprint principal, and the agent identity itself. Governance runs through Conditional Access policies written for agents, including templates that block high-risk agent identities and separate policies for autonomous agents versus agents acting on behalf of a user. Registry experiences are converging under Microsoft Agent 365, and the platform ships an Auth SDK "sidecar" for token acquisition. It is not a Microsoft-only story. Entra Agent ID supports non-Microsoft agents through sidecar and federation patterns, with documented guides for AWS Bedrock, GCP, and n8n. Accountability is built into the model through three administrative relationships: Owners, who are technical administrators; Sponsors, who are "business representatives accountable for the agent's purpose and lifecycle decisions"; and Managers, who reflect organizational hierarchy. Sponsorship is not optional. Microsoft states that "at least one sponsor is required for each agent identity and agent identity blueprint," and when a user creates an agent, "the calling user automatically becomes the sponsor if no sponsors are explicitly specified." An agent can also be given an "agent's user account," an Entra user object that lets it "access user-oriented services." The boundary is the tenant. Microsoft is explicit: "Agent identities can only be issued tokens in the Microsoft Entra tenant where they're created. They can't access resources or APIs in other tenants." ## What is AgentID? AgentID is a ["Sign in with AgentID" button](/blog/adding-a-sign-in-with-agentid-button) run by AgentMail as a standard OpenID Connect provider. The agent authenticates as itself with a signing credential that never leaves it, and the app verifies a fresh one-time signature against published keys, receiving an ES256-signed id_token with a stable subject and the agent's live-verified inbox address. Two tiers. Open clients integrate with no registration, using the openid, email and profile scopes. Registered clients, created in the AgentID console or with the CLI, add the owner_profile and owner_email scopes. The owner email arrives in the id_token and from the userinfo endpoint. If the agent isn't allowed to share its owner, the organization owner has to approve the sign-in, so the app never gets a token without the claim. Free for apps to add. ## The distinction that matters: who sees the human Both systems record a human. Entra requires a Sponsor. AgentID passes owner_email. The difference is who receives that information. Entra's sponsor is visible to the tenant that runs the agent. It is governance data for the organization operating the agent, answering "who inside our company is accountable for this thing." AgentID's owner_email is delivered to the relying party the agent signs into. It is accountability data for a third party, answering "who outside our company answers for the agent that just showed up at our login page." The practical consequence is a single sentence. A SaaS application receiving a sign-in from an Entra agent does not learn who sponsors it. A SaaS application receiving a sign-in from AgentID does learn who owns it. One is intra-organizational governance. The other is cross-organizational accountability. ## Side-by-side
AgentID Microsoft Entra Agent ID
For Any app accepting sign-ins from agents it has no prior relationship with Enterprises governing agents inside their Entra tenant
Identity model An email address on AgentMail, routable anywhere Blueprint, blueprint principal, agent identity, inside a tenant
Cross-app sign-in Any app with an OIDC client; two config values Within Entra-federated resources; external SaaS requires the app to integrate with Entra
Human accountability owner_email claim delivered to the relying party in the id_token and /userinfo Required Sponsor, plus Owners and Managers, visible inside the tenant
Standards Standard OpenID Connect, ES256, PKCE S256, RFC 7591 OAuth 2.0, MCP, A2A; proprietary blueprint and sidecar model
Non-Microsoft agents Any agent with an AgentMail inbox Supported via sidecar or federation
Pricing Free for apps; AgentMail inboxes from $20/mo Entra licensing; governance features noted by third parties as requiring P2 or add-ons
Time to integrate for an app Add as custom OIDC provider in Clerk, Supabase, Auth0, Descope, Better Auth App must federate with Entra or validate Entra tokens
On the pricing row: third-party analysis notes that governance features requiring Entra ID P2 licensing or Governance add-ons carry cost implications. That is an outside reading rather than a Microsoft statement. ## When to choose Microsoft Entra Agent ID Choose Entra Agent ID if your organization already runs Entra and the agents you care about are internal, reaching Microsoft 365, Azure, or your own APIs. The blueprint hierarchy gives you consistent policy across a class of agents rather than per-agent configuration, Conditional Access templates let you block high-risk agent identities without writing new machinery, and the required Sponsor means no agent exists in your directory without a named human attached to it. If your agents live inside your tenant and never sign up for third-party SaaS, Entra is the right tool and AgentID adds nothing. That is worth saying plainly, because the two products are frequently compared as substitutes when most organizations evaluating them have only the internal problem. ## When to choose AgentID Choose AgentID when the agent needs an account somewhere your organization does not control. An agent signing up for Turso, Neon, or any consumer or SaaS product is arriving at a login page belonging to a company that has no Entra relationship with you, and will not build one for a single prospective user. What that app needs is a standard OIDC sign-in it already knows how to accept, and a human it can contact if the agent misbehaves. That is what AgentID provides. The tenant boundary is the deciding factor. Entra tokens stop at the tenant that issued them by design, which is correct for governance and disqualifying for open-web sign-in. An AgentID is an email address, so it routes anywhere, and the owner_email claim travels to the app rather than staying in a directory the app cannot read. Running both is coherent. Entra governs your agents at home; AgentID is how those same agents introduce themselves everywhere else. ## Get started Add AgentID as a [custom OIDC provider](/docs/custom) with two values: issuer `https://auth.agentid.com` and your client_id. Create an AgentID application when you need the owner scopes. Guides for Clerk, Supabase, Auth0, Descope, and Better Auth are in the [AgentID docs](https://www.agentid.com/docs). --- # AI Agent Identity, Delegated Access, Workload Identity: A Field Guide > A field guide to agent identity terms: agent ID, agentic identity, delegated access, workload identity, token vaults, SPIFFE and auth.md, with named examples. - **Author:** Binoy Perera - **Date:** 2026-08-15 - **Category:** Blog - **URL:** https://www.agentid.com/blog/agent-identity-terminology-explainer Agent ID, agentic identity, on-behalf-of tokens, token vaults, SPIFFE, auth.md. The vocabulary of agent identity is a mess. Here is what each term actually means, with named examples. Agent identity answers "who is this agent," delegated access answers "what may it do on a user's behalf," workload identity answers "which piece of software is this," and registration protocols answer "how does an agent introduce itself." Those are four separate layers, not four competitors, and most confusion in this category comes from treating them as the same product. This guide defines each term, with named examples, so you can tell which product answers which question. Microsoft, Google, Auth0, Descope, WorkOS, Arcade, and AgentMail all ship products with "agent" and "identity" in the name, and they do not all mean the same thing. ## Agent identity A durable, verifiable identity belonging to the agent itself, separate from any human user. A real agent identity is stable (same identifier every time), cryptographically verifiable (signed tokens checked against published keys), and revocable without touching the owner's accounts. Examples diverge on scope. Microsoft Entra Agent ID creates agent identities inside a Microsoft Entra tenant, built from reusable "blueprints" and governed like enterprise users; the identities are tenant-bound and "can only be issued tokens in the Microsoft Entra tenant where they're created". Source: https://learn.microsoft.com/en-us/entra/agent-id/agent-identities, read 2026-09-09. AgentID (by AgentMail) issues agent identities that work across unrelated apps on the open web: any app with a "Sign in with AgentID" button can verify the agent through standard OpenID Connect. ## Principal vs. delegate The dividing line that explains most of this vocabulary. A principal is the account holder: the identity the app registers, bills, and emails. A delegate acts on behalf of a principal with borrowed, scoped authority. AgentID makes the agent a principal with its own account and inbox, and carries the human as a separate claim. Auth0 for AI Agents, Arcade, and WorkOS's auth.md treat the agent as a delegate of a human principal. Neither is wrong. They fit different products. Ask which one a vendor means before comparing anything else. ## Owner, sponsor, parent The human or organization [accountable for an agent](/blog/every-agent-has-a-human). Different vendors name this differently. Entra records a "sponsor", the user or group accountable for the agent, as a directory attribute visible to tenant admins. AgentID uses owner: a registered app can request the owner_email scope and read the owner's address from the userinfo endpoint after sign-in, which makes accountability available to the receiving application rather than only to the agent's home organization. When you see "every agent has a human" framing, this is the mechanism underneath it. ## Delegated access and on-behalf-of tokens Authority a human grants an agent to act as them, typically expressed as scoped OAuth tokens. The agent is not identified as itself; it wields a slice of the user's power. Auth0 for AI Agents anchors "autonomous actions to verified user identity" and manages the third-party tokens involved. Arcade describes the model directly: "your agents act as real users with dynamic permissions". Delegation and agent identity are complements. Delegation without identity gives you an anonymous actor with real permissions. Identity without delegation gives you a known actor with no authority. Production agents usually need a known actor with scoped authority. ## Token vault Encrypted storage for the third-party credentials an agent uses, so tokens never sit in the agent's code, logs, or prompts. Auth0's Token Vault ensures "sensitive third-party keys never touch your code or logs". Arcade keeps credentials inside its runtime, and Descope ships a credential vault with automatic refresh. A vault protects the credentials an agent holds. AgentID is the credential an agent is. ## Workload identity Identity for a piece of software qua software: a service, container, or deployed process. The relevant standard is SPIFFE, which names workloads with URIs and proves identity with short-lived X.509 certificates. Google's agent identity for its Gemini Enterprise Agent Platform is workload identity applied to agents: each agent gets a SPIFFE ID and certificate, usable within Google's runtime, currently in preview. Workload identity is strong on infrastructure authentication and says nothing about human ownership or signing in to consumer apps. ## Agent registration protocols Standards for how an agent discovers and completes signup at a service it has never met. WorkOS's auth.md is the prominent example: an open protocol where an app hosts a markdown file at its domain that "tells agents how to register on behalf of a user," composed from existing OAuth standards. A registration protocol defines the handshake; it still needs identity providers to vouch for who is registering. An OIDC provider for agents, AgentID included, can serve as that vouching party, which is why the two are complementary rather than competing. ## ID-JAG Identity assertion JSON Web Token. The token an agent's platform (OpenAI, Anthropic, Cursor) mints to attest to a user's identity in auth.md's agent-verified flow. The app verifies it against the platform's published keys and registers the user without a human in the loop. It is a delegate-model proof: it asserts who the human is, not who the agent is. WorkOS documents that agents built on MCP servers or bare LLM APIs typically cannot mint one. Source: https://workos.com/auth-md/docs/flows/verified, read 2026-09-09. ## MCP authentication Securing the connection between agents and Model Context Protocol servers, usually with OAuth 2.1 and PKCE. Descope's Agentic Identity Hub secures MCP servers with per-agent, per-tool scopes, and Auth0 ships auth for MCP as generally available. MCP auth secures the agent's tool channel. AgentID identifies the agent to applications outside that channel. A production agent typically needs both. ## Agentic identity (the marketing umbrella) Vendor shorthand for "our platform, applied to agents." Descope's Agentic Identity Hub bundles MCP auth, a token vault, and access policies under this banner. When you encounter the phrase, ask which of the layers above is actually included. Frequently the answer is delegation and vaulting without a portable identity, which is fine, as long as you know that is what you are buying. ## The distinctions that matter in practice Identity vs. authorization. "Who is this agent" and "what may it do" are different questions with different failure modes. Conflating them is how you end up with a perfectly scoped token held by an actor you cannot name. Tenant-scoped vs. cross-app. An Entra agent identity is authoritative inside its tenant and invisible outside it. A cross-app identity like AgentID is weaker on internal governance and is the only kind that works when an agent signs up for an arbitrary SaaS product. Disclosed vs. borrowed. Any of these systems beats the status quo, in which agents log in with their owners' credentials and applications cannot tell. One huge software company saw hundreds of signups from AgentMail domains in a short window with no way to know how many humans were behind them, and reached out to ask who they were. Every layer in this glossary exists because of that gap. ## Where AgentID sits AgentID is the principal-model layer in this glossary: a standard OpenID Connect provider that gives the agent its own cross-app identity rather than a slice of a human's. It works at any app that speaks OIDC, with no relationship between that app and the agent's operator, and it carries the owner as a claim rather than as the subject. See [AgentID](https://www.agentid.com) for the product, and [Introducing AgentID](/blog/introducing-agentid) for how the sign-in works end to end. For a deeper treatment of the concept itself, see [What is an agent ID?](/blog/introducing-agentid). For head-to-head comparisons, AgentID maintains pages against [Entra Agent ID](/blog/agentid-vs-microsoft-entra-agent-id), [Auth0 for AI Agents](/blog/agentid-vs-auth0-for-ai-agents), and [others](/blog). --- # AgentID vs Arcade: Who the agent is vs what the agent can reach > Arcade is an MCP runtime that lets agents act as real users in tools like Slack and Salesforce. AgentID is a sign-in identity for the agents themselves. - **Author:** Binoy Perera - **Date:** 2026-08-15 - **Category:** Comparisons - **URL:** https://www.agentid.com/blog/agentid-vs-arcade Arcade is an MCP runtime that lets agents act as real users against tools like Slack and Salesforce, with credentials that never leave the runtime. AgentID is a sign-in identity for agents themselves. Identity and tool access are different layers. Arcade and AgentID sit at different layers of the agent stack. Arcade is an MCP runtime that lets an agent act as a known user against tools like Slack and Salesforce, with delegated credentials that stay inside the runtime. AgentID is an OpenID Connect provider that gives the agent an identity of its own, so an application that has never seen it can verify what it is and, for registered clients, which human owns it. ## What is Arcade? Arcade describes itself as "the runtime between your agents and every system they need to reach". It is a middleware layer with three functions: authorization, tool execution, and governance. On authorization, "your agents act as real users with dynamic permissions. Your existing IDP plugs right in, credentials never leave the runtime". On tooling, Arcade ships pre-built MCP tools for systems including Google Workspace, Slack, Microsoft, and Salesforce. On governance, the pitch is auditability: "What did the agent do, on behalf of which user, in which system? You can answer that for every action". The identity model is user impersonation through delegated OAuth rather than [service accounts](/blog/how-agentic-accounts-differ-from-user-accounts). End users authenticate through the company's existing identity provider; the agent then operates with each individual user's credentials and permissions, with tokens held inside Arcade's runtime rather than in agent code. Arcade is framework-agnostic (LangChain, LlamaIndex, CrewAI, and others), deploys to cloud, on-prem, air-gapped, or hybrid environments, and is priced "free to start, priced by usage, designed for enterprise volume". Source: https://www.arcade.dev/pricing, read 2026-09-09. It is a strong answer to a real problem: agents that need to do things in SaaS systems on behalf of known users, with security teams demanding audit trails. ## What is AgentID? AgentID is a "Sign in with AgentID" button apps put on their login pages, run by AgentMail as a standard OpenID Connect provider. The agent authenticates as itself: its signing credential never leaves it, each sign-in is a fresh one-time signature, and the app verifies against published keys without ever holding a reusable secret. The id_token carries a stable subject and the agent's inbox address, verified at token mint. Registered clients (an application created in the AgentID console or with the CLI) can request owner_email, which arrives in the id_token and from the userinfo endpoint. If the agent isn't allowed to share its owner, the organization owner has to approve the sign-in, so the app never gets a token without the claim. Free for apps in both tiers. ## Different questions The two products answer different questions, which is easiest to see side by side.
AgentID Arcade
The problem Disclosure: an agent arriving at an application that has never seen it, needing to prove what it is and who stands behind it Delegation: a known user, inside an organization, granting an agent authority to use their tools
What matters The agent's own identity, and the human accountable for it Whose permissions the agent wields; the agent's own identity is incidental
Prior relationship None at all, which is precisely why the identity must be portable and verifiable by anyone The app being called already trusts the user's IDP
Typical job An agent signs up for a new SaaS product and the product wants to know one human is behind these five agents An agent posts to your company Slack
## Side-by-side
AgentID Arcade
For Apps accepting agent sign-ins; agent developers needing portable identity Teams whose agents call SaaS tools on behalf of known users
Cross-app support Yes, one identity valid at any OIDC-capable app Broad tool catalog, but access is per-user delegation, not portable agent identity
Owner email support Yes, owner_email scope for registered clients User attribution per action via the existing IDP; no owner claim presented to outside apps
Standards support Standard OIDC: code flow + PKCE (S256), ES256, RFC 7591 OAuth-based delegation, MCP runtime, existing IDP integration
Pricing Free for apps Free to start, usage-priced
Time to integrate Minutes on an existing OIDC stack; two config values Runtime deployment plus per-tool authorization setup
Who owns the identity root AgentMail inbox controlled by the agent's owner The organization's existing IDP; agents borrow user permissions
## When to choose Arcade Choose Arcade when your agents need to operate inside the tools your organization already uses, and the security requirement is that every action maps to a real user with real permissions. The pre-built MCP tool catalog saves integration work, the runtime keeps tokens out of agent code, and the per-action audit trail answers the question security reviews actually ask. If your deployment needs on-prem or air-gapped options, that flexibility is there too. Arcade is not trying to give your agent an identity the outside world can verify, and its user-impersonation model means the systems being called see the user, not the agent. ## When to choose AgentID Choose AgentID when the agent needs to be seen as an agent. Apps on the receiving end of agent traffic need sign-ins that disclose agenthood, resolve to a stable identity, and (for registered clients) carry the owner's email for per-human limits, abuse control, and KYC pass-through. Agent developers get an identity that works at every app showing the button, plus a working email inbox attached to it, without lending the agent their personal credentials. The composition is natural: an agent might reach its owner's tools through Arcade and sign in to new services with AgentID. One handles authority inside an existing trust relationship; the other establishes identity where no relationship exists yet. ## Get started Add AgentID as a [custom OIDC provider](/docs/custom) (issuer https://auth.agentid.com plus your client_id), or create an AgentID application for owner scopes. Guides for Clerk, Supabase, Auth0, Descope, and Better Auth at [www.agentid.com/docs](https://www.agentid.com/docs). --- # AgentID vs Auth0 for AI Agents: Agent-native identity vs securing agents inside your auth stack > Auth0 for AI Agents secures agents acting for your users. AgentID gives agents their own cross-app identity with owner accountability, and plugs into Auth0. - **Author:** Binoy Perera - **Date:** 2026-08-15 - **Category:** Comparisons - **URL:** https://www.agentid.com/blog/agentid-vs-auth0-for-ai-agents Auth0 for AI Agents secures agents acting on behalf of your users: token vault, fine-grained authorization, MCP auth. AgentID gives agents their own cross-app identity with owner accountability. They meet in the middle: AgentID plugs into Auth0 as an OIDC connection. Auth0 for AI Agents secures the agents you build for your own users, covering agent authentication, a token vault for third-party credentials, and fine-grained authorization inside your Auth0 tenant. AgentID is a separate OpenID Connect provider that gives agents a portable identity any app can verify, including an owner_email claim for registered clients. The two compose rather than replace each other: an app running Auth0 can add AgentID as an enterprise OpenID Connect connection and start accepting outside agents from the dashboard it already uses. ## What is Auth0 for AI Agents? Auth0 for AI Agents is Okta's product line for securing AI agents, aimed at teams who want to "ship more secure AI agents, faster". It has three pillars. Agent identity and authentication lets you "identify your AI agents, define who they represent, and establish how they're held accountable," anchoring autonomous actions to a verified user identity with audit trails. Token Vault manages the third-party credentials agents use, so "sensitive third-party keys never touch your code or logs," with automated rotation. Fine-Grained Authorization for RAG checks document permissions at retrieval time so an LLM only sees what the authenticated user may access. The platform builds on OAuth 2.1 and OIDC, and for MCP servers provides "standards-based discovery and client registration, resource-scoped tokens, permission downscoping through token exchange". Auth for MCP is generally available; Agent as Principal is listed as coming soon. Pricing is "free to build," then priced on active agent identities. Sources: https://auth0.com/blog/auth0-auth-for-mcp-servers-generally-available/ and https://auth0.com/ai, both read 2026-09-09. The center of gravity is delegation. Auth0 for AI Agents assumes the human is your user, inside your Auth0 tenant, and secures the agent acting as that human against your app and the third-party services it reaches. ## What is AgentID? AgentID is a "Sign in with AgentID" button for agents, a standard OpenID Connect provider run by AgentMail. The agent authenticates as itself with its own signing credential, which never leaves the agent. The app receives an ES256-signed id_token with a stable subject and the agent's verified inbox address. Accountability comes through registration: a registered client (an application created in the AgentID console or with the CLI) can request the owner_email scope and read the owner's address from the id_token or the userinfo endpoint. If the agent isn't allowed to share its owner, the organization owner has to approve the sign-in, so the app never gets a token without the claim. AgentID is free for apps. ## The nuance: two Auth0s Auth0 is both a competitor and a distribution channel here, and the distinction is between SKUs.
Auth0 product What it is Relationship to AgentID
Auth0 for AI Agents The product described above: agent identity and authentication, Token Vault, Fine-Grained Authorization for RAG Competes with AgentID on the question of agent identity
Auth0 the identity platform The login box your application already runs Something AgentID plugs into: add AgentID as an enterprise OpenID Connect connection and start accepting agent sign-ins through the dashboard you already use
If your login box is Auth0, adopting AgentID is configuration, not migration. ## Side-by-side
AgentID Auth0 for AI Agents
For Apps accepting agent sign-ins from anywhere; agent developers Teams building agents on top of their own Auth0-secured apps
Cross-app support Yes, any OIDC-capable app; identity is portable across unrelated services Scoped to your applications and the third-party APIs your agents call
Owner email support Yes, owner_email scope; never a token missing the claim Agents are tied to your existing users; identity of outside agents' owners is not the model
Standards support Standard OIDC: code flow + PKCE (S256), ES256, RFC 7591 OAuth 2.1 and OIDC; token exchange, resource-scoped tokens for MCP
Pricing Free for apps Free to build, then priced on active agent identities
Time to integrate Minutes on an existing OIDC stack; two config values An Auth0 deployment plus SDK integration per framework
Who owns the identity root AgentMail inbox controlled by the agent's owner Your Auth0 tenant
## When to choose Auth0 for AI Agents Choose it when you are building the agent and the human it serves is already your user. If your product ships an assistant that reads customers' calendars, calls their SaaS tools, and queries permission-sensitive documents, Auth0's pillars map directly onto your risks: vaulted third-party tokens, retrieval-time authorization, MCP auth that passed security review. Teams already on Auth0 get all of this inside the platform they know. It stops at identity in one specific sense: the identities involved are your users and your agents. It has no opinion about an unknown agent showing up at your login page from someone else's infrastructure, and no email or communication layer attached to the identities it manages. ## When to choose AgentID Choose AgentID when agents arrive from outside. A SaaS product seeing automated signups, a marketplace wanting to [cap accounts per human](/blog/stop-fake-agent-signups-without-blocking-real-agents), an API wanting to welcome disclosed agents with real rate limits: these need the agent to carry its own verifiable identity and a pointer to its owner. That is what the button provides, with no relationship between the agent's infrastructure and yours. AgentID identities also come with something an authorization platform does not provide: each agent's identity is anchored to a working AgentMail inbox, so the identity that signs in is also an address you can email. Identity extends into a communication channel rather than stopping at the credential. If you run Auth0, this is not either-or. Add AgentID as an enterprise OIDC connection and keep Auth0 for AI Agents for the agents you build yourself. ## Get started If your app runs Auth0, add AgentID as an enterprise OpenID Connect connection from your dashboard. Otherwise, point any OIDC stack at issuer https://auth.agentid.com. Guides at [www.agentid.com/docs](https://www.agentid.com/docs). --- # AgentID vs Descope Agentic Identity Hub: Portable agent sign-in vs an identity platform for MCP and delegation > Descope Agentic Identity Hub secures agents and MCP servers inside your deployment. AgentID gives agents one identity that works at any app's login page. - **Author:** Binoy Perera - **Date:** 2026-08-15 - **Category:** Comparisons - **URL:** https://www.agentid.com/blog/agentid-vs-descope-agentic-identity Descope's Agentic Identity Hub secures agents and MCP servers inside a deployment you administer, with per-agent scopes, a credential vault, and policy controls. AgentID is a public OpenID Connect provider for the opposite case: an agent signing in at an app that has never heard of its operator. Descope's Agentic Identity Hub secures agents and MCP servers inside a deployment you administer, with per-agent identities, tool-level scopes, a credential vault, policy controls, and audit logging. AgentID is a public OpenID Connect provider for the opposite case: an agent signing in at an application that has no relationship with its operator. Descope governs identity inside a perimeter, while AgentID makes an agent verifiable outside every perimeter and carries the owner's email to registered clients. ## What is Descope Agentic Identity Hub? Descope's Agentic Identity Hub provides identity infrastructure for AI agents and MCP servers, aimed at three audiences: MCP server developers, agent builders, and the security teams governing both. Its pieces: dedicated per-agent identities carrying "associated users, tenants, tool-level scopes"; MCP authentication built on OAuth 2.1 and PKCE with granular scope assignment; credential management issuing "portable, revocable tokens designed specifically for agents" backed by 50+ prebuilt connection templates; policy controls for per-agent and per-tool access; and audit logging that records "every AI agent's identity, the delegating user, and the tools / scopes / MCP servers" involved. The platform supports ephemeral scoped credentials, JWT-based authorization, a credential vault with refresh, step-up authentication for sensitive operations, multi-tenant policy engines, SIEM export, and "Bring Your Own Auth" federation with existing IdPs. Descope has iterated quickly here, with 2.0 and 2.5 releases expanding policy controls and ecosystem integrations. It is a serious platform, and its center of gravity is the deployment you control: your MCP servers, your agents, your tenants, your policies. ## What is AgentID? AgentID is a "Sign in with AgentID" button run by AgentMail as a standard OpenID Connect provider. An agent [authenticates as itself](/blog/how-an-ai-agent-proves-its-identity-to-your-app) with a signing credential that never leaves it; the app verifies a fresh one-time signature against published keys and receives an ES256-signed id_token with a stable subject and the agent's live-verified inbox address. Two tiers. Open clients integrate with no registration (openid, email and profile scopes; the client_id is a URL the app controls). Registered clients, created in the AgentID console or with the CLI, add a client secret and the owner_profile and owner_email scopes. The owner claims arrive in the id_token and from the userinfo endpoint. If the agent isn't allowed to share its owner, the organization owner has to approve the sign-in, so the app never gets a token without the claim. Free for apps. ## Inside vs outside Descope governs identity within a perimeter someone administers. AgentID handles the moment an agent leaves one.
AgentID Descope Agentic Identity Hub
Where the identity lives A public OIDC provider on the open web Your Descope deployment, scoped to your tenants, subject to your policies
The moment it covers An agent leaving any perimeter: signing up for a SaaS tool, authenticating to a consumer app, arriving anywhere that has never heard of the organization behind it Agents operating inside a perimeter someone administers
Who has to verify it Strangers, so identity must be verifiable by anyone and must carry accountability with it The administering organization
Relationship required with the agent's operator None at all The agents are yours, in your deployment
Enterprise identity platforms exist for the first column's opposite case, and agents genuinely need that too. What a public OIDC provider with an owner claim adds is identity that survives outside the deployment. ## Side-by-side
AgentID Descope Agentic Identity Hub
For Apps accepting agent sign-ins from anywhere; agent developers Teams securing their own MCP servers, agents, and tool connections
Cross-app support Yes, one identity valid at any OIDC-capable app Identities live in your Descope deployment; external reach via federation you configure
Owner email support Yes, owner_email scope; never a token missing the claim Tracks delegating users internally for audit; no owner claim presented to unaffiliated apps
Standards support Standard OIDC: code flow + PKCE (S256), ES256, RFC 7591 OAuth 2.1, PKCE, JWT authorization, IdP federation
Pricing Free for apps Not published on the product page; platform pricing
Time to integrate Minutes on an existing OIDC stack; two config values Platform adoption: tenants, policies, templates, per-tool scopes
Who owns the identity root AgentMail inbox controlled by the agent's owner Your organization's Descope project
## When to choose Descope Choose the Agentic Identity Hub when you operate the surface being secured. If you are shipping an MCP server and need OAuth 2.1 in front of it, or running a fleet of agents whose tool access needs scoping, vaulting, step-up auth, and SIEM-visible audit, this is the category Descope built for, and the 50+ connection templates shorten real work. Security teams get a policy engine; developers avoid hand-rolling OAuth. Its identities serve your deployment. They are not designed as a credential an agent presents at an arbitrary login page, and outside apps have no way to verify them or learn an owner from them. ## When to choose AgentID Choose AgentID for the login page. If you build apps and want agent traffic disclosed, identified, and accountable, the button gives you that with two configuration values: every AgentID sign-in is an agent by definition, resolves to a stable subject, and, with registration, carries the owner's email for per-human limits, KYC pass-through, and abuse control. If you build agents, AgentID is an identity that works everywhere the button does, anchored to a working email inbox, without lending the agent your credentials. Running both is coherent: Descope securing your MCP and tool layer, AgentID identifying your agents to the outside world (or identifying outside agents to your app). ## Get started Add AgentID as a [custom OIDC provider](/docs/custom) with two values, or create an AgentID application for owner scopes. Guides at [www.agentid.com/docs](https://www.agentid.com/docs). --- # AgentID vs Google Cloud Agent Identity: Sign-in identity for the open web vs workload identity for Google's runtime > Google Cloud Agent Identity gives agents SPIFFE IDs and X.509 certificates on Google's agent runtime. AgentID is an OpenID Connect identity any app accepts. - **Author:** Binoy Perera - **Date:** 2026-08-15 - **Category:** Comparisons - **URL:** https://www.agentid.com/blog/agentid-vs-google-cloud-agent-identity Google Cloud Agent Identity gives agents on Google's runtime a SPIFFE identity and an X.509 certificate for authenticating to infrastructure. AgentID is an OpenID Connect provider that lets an agent sign in at any app on the open web, with the owner's email behind it for registered clients. Google Cloud Agent Identity gives agents deployed on Google's runtime a SPIFFE identity and an X.509 certificate for authenticating to infrastructure. AgentID is an OpenID Connect provider that lets an agent sign in at any application on the open web with a verified email identity and, for registered clients, the owner's email address. They operate at different layers: no consumer app's login page accepts an X.509 SVID, and no cloud IAM system grants infrastructure access on an id_token from a third-party provider. ## What is Google Cloud Agent Identity? Google's agent identity, documented under the Gemini Enterprise Agent Platform (Google's Vertex AI Agent Engine pages now redirect there), "provides a strongly attested, cryptographic identity for each agent that is based on the SPIFFE standard". When an agent is deployed to the platform's runtime, the system "assigns it a unique SPIFFE identity and an X.509 certificate". The design goal is fixing the sins of [service accounts](/blog/how-agentic-accounts-differ-from-user-accounts). Google's documentation draws the contrast directly: "Unlike service accounts, agent identities are not shared by multiple workloads by default, can't be impersonated, and don't allow developers to generate long-lived service account keys". On top of the certificate, agents authenticate several ways depending on target: mTLS to Google Cloud APIs, three-legged OAuth for user-delegated access to external services, two-legged OAuth for the agent's own authority, API keys where needed, and DPoP through the Agent Gateway. Per Google's docs, "Access tokens generated for Google Cloud are cryptographically bound to the agent's unique X.509 certificates to prevent token theft". The scope is Google's own surfaces: the platform runtime and Gemini Enterprise. The agent identity auth manager is in preview, under pre-GA terms. Source: https://docs.cloud.google.com/gemini-enterprise-agent-platform/govern/agent-identity-overview, read 2026-09-09. ## What is AgentID? AgentID is a "Sign in with AgentID" button, a standard OpenID Connect provider run by AgentMail, the same integration shape as "Sign in with Google" but for agents. Every sign-in returns an ES256-signed id_token with a stable subject and the agent's inbox address, verified live at token mint. The agent's signing credential never leaves the agent, each sign-in is a fresh one-time signature, and the app never receives anything reusable. Any app can accept sign-ins without registering. Registered clients (an application created in the AgentID console or with the CLI) also get the owner_profile and owner_email scopes; owner details arrive in the id_token and from the userinfo endpoint. If the agent isn't allowed to share its owner, the organization owner has to approve the sign-in, so the app never gets a token without the claim. ## Different layers, occasionally confused SPIFFE certificates and OIDC tokens solve different problems, and the confusion between them is mostly the word "identity" doing double duty.
AgentID Google Cloud Agent Identity
Question it answers Which agent is signing in to this application, and which human answers for it Which workload is calling this API, and can we prove it without long-lived keys
What the agent presents An ES256-signed OIDC id_token, verified against published keys A SPIFFE identity and an X.509 certificate
Where it is accepted Any application's login page that speaks OpenID Connect Google Cloud infrastructure; no consumer app's login page accepts an X.509 SVID
What it will not do No cloud IAM system grants infrastructure access on an id_token from a third-party provider Gives an agent no identity an unrelated application can verify at sign-in
The two meet only in the sense that a serious agent deployment eventually needs both layers. ## Side-by-side
AgentID Google Cloud Agent Identity
For Any app accepting agent sign-ins; agent developers anywhere Teams deploying agents on Google's agent runtime / Gemini Enterprise
Cross-app support Yes, any OIDC-capable app on the web Google Cloud surfaces; external services via OAuth flows the developer configures
Owner email support Yes, owner_email for registered clients No owner-identity claim presented to receiving apps; delegation via 3-legged OAuth carries the user's own identity
Standards support Standard OIDC: code flow + PKCE (S256), ES256, RFC 7591 SPIFFE, X.509, mTLS, OAuth 2.0, DPoP
Pricing Free for apps Part of Google Cloud platform usage; identity feature in preview
Time to integrate Minutes on an existing OIDC stack Requires deploying agents on Google's runtime
Who owns the identity root AgentMail inbox controlled by the agent's owner Google Cloud trust domain of the operating project
## When to choose Google Cloud Agent Identity Choose it when your agents run on Google's platform and the thing you need to secure is their access to infrastructure. Per-agent certificates that cannot be impersonated, no long-lived keys to leak, tokens bound to hardware-backed identity: this is materially better security than shared service accounts, and if you are on the Gemini Enterprise Agent Platform you should use it. It also cleanly handles the delegation case where an agent needs a user's permission to call an external API on their behalf. Be aware of its boundaries. It is in preview, it presumes Google's runtime, and it gives an agent no identity that an unrelated application on the web can verify at sign-in. ## When to choose AgentID Choose AgentID when the counterparty is an application, not an API you control. An agent signing up for SaaS tools, a consumer product deciding its agent policy, a platform enforcing per-human account limits: these interactions happen at login pages, in OIDC, between parties with no shared cloud. AgentID works regardless of where the agent runs, Google Cloud included. An agent deployed on Google's runtime with a SPIFFE identity for its infrastructure can hold an AgentID for the open web, and the two never conflict. The owner layer is the other differentiator. Google's system attests to which workload is calling. AgentID's registered tier attests to which human stands behind the agent, which is the fact a receiving app needs for rate limiting, abuse control, and KYC. ## Get started Accept agent sign-ins by adding AgentID as a [custom OIDC provider](/docs/custom): issuer https://auth.agentid.com plus your client_id. Owner scopes need an AgentID application, created in the console or with the CLI. Guides at [www.agentid.com/docs](https://www.agentid.com/docs). --- # AgentID vs WorkOS > auth.md tells agents how to register at your app, as delegates of a human. AgentID is an identity provider that vouches for the agent as its own principal. - **Author:** Binoy Perera - **Date:** 2026-08-15 - **Category:** Comparisons - **URL:** https://www.agentid.com/blog/agentid-vs-workos-auth-md auth.md is an open protocol that tells agents how to register at your app. AgentID is an identity provider that vouches for who the agent is. They differ on one question: is the agent a delegate of a human, or a principal of its own? auth.md is a registration protocol and AgentID is an identity provider, so they operate at different layers and can compose. The substantive difference is who ends up holding the account. Under auth.md the agent registers on behalf of a human and receives a token scoped to that human; under AgentID the agent is the account holder and the human travels as a separate claim the app can read. ## What is auth.md? auth.md is "a Markdown file an application hosts at its domain, typically https://yourapp.com/auth.md, that tells agents how to register on behalf of a user". An agent visiting a new service fetches the file, reads which flows the app supports, and registers. The credential the app issues is "a scoped access token tied to the user, short-lived and revocable". The protocol defines two flows. "Agent verified is agent-attested: the agent's identity provider vouches for the user, no human in the loop. User claimed needs no provider: the agent shows the user a code, they sign in and confirm it." WorkOS authored the protocol but designed it to stand alone: "It's open. WorkOS authors the protocol, but auth.md isn't tied to WorkOS infrastructure." In the agent verified flow, "the agent's provider, OpenAI, Anthropic, Cursor, or any trusted agent platform, attests to the user's identity at registration time." WorkOS is direct about the limit: the flow "only works when the agent's provider participates. Agents built on MCP servers or bare LLM APIs typically can't mint ID-JAGs, those need the user claimed flow." Apps also "take on the operational responsibility of curating which providers you trust." It is thoroughly standards-based, and implementing it is real engineering. An app supporting auth.md hosts `/oauth2/token` (RFC 7523) and `/oauth2/revoke` (RFC 7009), accepts Security Event Tokens (RFC 8417), publishes Protected Resource Metadata (RFC 9728), maintains a trust list of agent providers, and implements a claim ceremony page for the user-claimed flow. Adoption is real rather than theoretical. Cloudflare and Firecrawl were launch partners, per WorkOS CEO Michael Grinich. Resend adopted within the first week. Firecrawl is live with a spec-compliant implementation supporting the identity_assertion (ID-JAG) method only. The standards community has taken it seriously too: Aaron Parecki, Senior Director of Identity Standards at Okta, oauth.net maintainer and an OAuth 2.1 co-author, wrote that the agent verified flow is "exactly what I've been telling the agent platforms they should be doing". What auth.md deliberately does not do is issue identities. It defines how an app describes its registration flows and how assertions are presented. Someone still has to make the assertion, which is where identity providers enter. ## What is AgentID? AgentID is a ["Sign in with AgentID" button](/blog/adding-a-sign-in-with-agentid-button) run by AgentMail: a standard OpenID Connect provider agents use to authenticate as themselves. Each sign-in returns an ES256-signed id_token with a stable subject and the agent's verified inbox address. The agent's own signing credential never leaves it; the app verifies fresh one-time signatures against published keys and never holds anything reusable. The accountability layer is the registered tier: an application created in the AgentID console or with the CLI unlocks the owner_email scope, which arrives in the id_token and from the userinfo endpoint. If the agent isn't allowed to share its owner, the organization owner has to approve the sign-in, so the app never gets a token without the claim. Free for apps, both tiers. ## Delegate or principal This is the whole comparison, and it is a product decision rather than a technical one. Under auth.md the agent is a delegate. It acts on behalf of a human, the registered identity is the human's, and the token it receives is scoped to that user. Accountability is structural: the human is the account, so there is never a question of who is responsible. Under AgentID the agent is a principal. It has its own identity in the form of an email address, its own account, and its own inbox. The human is a separate claim, owner_email, that the app can read when it needs to. The agent holds its own credentials, receives its own receipts and support threads, and can invite the human to an organization later as a separate member. Neither model is wrong. auth.md fits apps where the human is the customer and the agent is a tool they point at you. AgentID fits apps where the agent is a customer in its own right, with a human who is reachable if something goes wrong. They also compose in a specific way. AgentID could act as the identity provider inside auth.md's agent verified flow: an AgentMail agent minting an ID-JAG that asserts its owner's identity to an auth.md-enabled app. That is architecturally consistent with both designs rather than something shipping today. ## Side-by-side
AgentID WorkOS auth.md
What it is An OpenID Connect identity provider A registration protocol apps host at /auth.md
Who is the account holder The agent; the human is a claim The human; the agent acts on their behalf
Human accountability owner_email delivered in the id_token and /userinfo Built in: the human is the registered user
Agent provider requirement Any agent with an AgentMail inbox Agent verified flow needs a participating provider (OpenAI, Anthropic, Cursor); MCP and bare API agents fall back to user claimed
Standards OpenID Connect, ES256, PKCE S256, RFC 7591 RFC 7523, RFC 7009, RFC 8417, RFC 9728, ID-JAG
What the app builds Two config values in an existing OIDC client /oauth2/token, /oauth2/revoke, event ingest, provider trust list, claim ceremony page
Usable without the other Yes, through ordinary OIDC integration with no auth.md file involved Yes, an auth.md file can describe flows that use other assertion sources
Live adopters Turso, plus launch partners Firecrawl, Resend (Cloudflare announced)
Relationship Complementary: AgentID can serve as an identity provider inside the agent verified flow
## When to choose auth.md Choose auth.md when your app treats agents as extensions of human users, your users run agents on platforms that participate in ID-JAG, and you want the human to be the account holder. If your billing, support, and terms of service all assume a person on the other end, a protocol that keeps the person as the registered user fits your product rather than fighting it. Budget for the build. Between the token and revocation endpoints, event ingest, the provider trust list, and the claim ceremony page, adopting auth.md is a set of new endpoints to run, plus the ongoing operational responsibility of deciding which agent providers you trust. ## When to choose AgentID Choose AgentID when you want the agent to have its own account, and when you want to support agents on any model or framework. That last point is the sharpest practical difference: WorkOS documents that agents built on MCP servers or bare LLM APIs typically cannot mint ID-JAGs and must fall back to the user-claimed flow, with its human confirmation step. Those agents can use AgentID directly, because the identity belongs to the agent rather than being vouched for by its platform. The integration cost is also different in kind. Accepting AgentID is two configuration values in an OIDC client you already run, rather than a new set of endpoints to host and a trust list to curate. ## Get started Accept agent sign-ins today: add AgentID as a [custom OIDC provider](/docs/custom) with issuer `https://auth.agentid.com`, or create an AgentID application for owner scopes. Guides for Clerk, Supabase, Auth0, Descope, and Better Auth are in the [AgentID docs](https://www.agentid.com/docs). --- # Every Agent Has a Human > Apps cannot tell who is behind an agent, so agents get blocked, rate-limited into uselessness, or let in with no accountability. AgentID exists to fix it. - **Author:** Haakam Aujla - **Date:** 2026-08-15 - **Category:** Manifesto - **URL:** https://www.agentid.com/blog/every-agent-has-a-human Apps cannot tell who is behind an agent. That is not a technical curiosity, it is the reason agents get blocked, rate-limited into uselessness, or waved through with no accountability at all. AgentID exists to fix it. Every AI agent is created, funded, and controlled by a person or an organization, and the web's identity layer has no way to record that fact. Apps therefore cannot tell an agent from a human, cannot enforce per-human limits, and cannot say who is accountable for an account. AgentID closes the gap by giving agents their own OpenID Connect identity and giving registered apps the owner_email claim behind it. {/* ANECDOTE: confirm with Haakam before launch */} Earlier this year, one of the largest software companies in the world reached out to us. They had noticed something strange in their signup logs: roughly 1,500 new accounts over a short window, all registered with email addresses on AgentMail domains. The accounts behaved normally. They verified their emails. They passed every check the company had. Nobody there could answer the most basic question about them: was this 1,500 people, or one person running 1,500 agents? There was no way to know. The web's identity layer has no concept of an agent. It has accounts, and it assumes a person is behind each one. ## How agents sign in today When an agent needs an account somewhere, it borrows one. It signs up as sid@gmail.com. It reads the OTP out of Sid's inbox. It completes Sid's 2FA challenge. From the application's side, this login is indistinguishable from Sid himself. The agent inherits everything Sid can do, and the app has no idea a machine is at the keyboard. The usual response is detection. Fingerprint the browser, score the behavior, throw a CAPTCHA at anything suspicious. Detection treats agents as an infection to be screened out, and it fails in both directions at once: sophisticated agents pass while honest ones get blocked, and the app still learns nothing about who is behind the traffic it does admit. You cannot build policy on top of a guess. Borrowed credentials fail everyone involved. It fails the app first. Per-human limits become unenforceable, because a hundred agents borrowing a hundred inboxes look like a hundred humans. Fraud teams cannot treat agent traffic differently from human traffic they cannot see, and compliance teams cannot say who is legally responsible for an account's actions. The human takes on a different kind of damage. Handing an agent your credentials means handing it your whole account, every permission, every stored payment method, everything. There is no way to grant less, and revoking access means changing your password. Even the agent loses. Agents get caught in bot detection, locked out by security heuristics, and banned for behavior that would be fine if it were disclosed. The honest agent and the fraudulent one look identical, so both get treated as threats. ## The thesis Every agent has a human. Somewhere behind every autonomous process is a person or an organization that created it, funds it, and benefits from what it does. That is true today and it will stay true. Agents do not own credit cards. They do not have legal standing. When an agent does something wrong, a human answers for it. Identity infrastructure should reflect this fact instead of hiding it. The point of accountability is not to constrain agents. It is what makes autonomy safe to allow. An app that knows who stands behind an agent can let that agent sign up, act, and spend on its own, because there is someone to call if it goes wrong. Anonymity forces apps to say no. A verifiable owner lets them say yes. An agent should be able to walk up to an application, present itself as an agent, and carry a verifiable pointer to the human it belongs to. The application should be able to decide, on its own terms, what agents are allowed to do. Some apps will welcome them with higher rate limits than humans get. Some will restrict them. Some will require knowing the owner before granting anything. All of those are reasonable policies, and none of them are possible when agents are disguised as people. ## What AgentID does about it [AgentID is a "Sign in with AgentID" button](/blog/introducing-agentid), the same shape as "Sign in with Google", built for agents. It is a standard OpenID Connect provider, so an app that already accepts Google sign-in can accept agents without new infrastructure. The specific mechanism that carries accountability is a claim called owner_email. An app that creates an AgentID application can request it. After the agent signs in, the owner's email arrives in the identity token and from the userinfo endpoint, and only for the app that asked for it. The failure mode matters as much as the success mode. If an agent has not been given permission to share its owner, it can't finish the sign-in alone; the organization owner has to approve it. It never succeeds with the claim quietly missing. An app that requires owner_email can rely on having it for every agent that gets through. With that one field, the problems above become tractable. The question in that signup log has an answer: those 1,500 accounts resolve to some number of owner emails, and that number is the real user count. Per-human limits work again. A financial app can pass the owner through KYC. A fraud team can rate-limit by owner instead of by account. None of this requires surveilling the agent or weakening it. The agent holds its own signing credential, which never leaves it. Each sign-in is a fresh one-time signature verified against published keys. The app never receives a password, a key, or anything reusable. Revoke the credential and that agent stops signing in everywhere, without touching the owner's own accounts. ## Where this goes Agent commerce arrives first. An agent buying things needs an account, a spending limit, and a person who answers for the charge. Owner identity is the primitive underneath all three, which is why payments companies are already asking about KYC pass-through. A merchant that can resolve an agent to a verified human can extend it credit, honor its purchases, and dispute its chargebacks. A merchant that cannot will keep treating agent checkout as fraud. Regulation arrives second. When rules for autonomous agents on the open internet get written, and they will be, traceability to a responsible party is the requirement they converge on, because it is the only one that makes the rest enforceable. Infrastructure that carries owner identity today will satisfy rules that do not exist yet, while infrastructure that hides it ends up retrofitting under deadline. The larger shift is an internet where agents are first-class citizens rather than tolerated intruders. That internet is better for everyone in it: apps get to set real policy, humans stop lending out their entire accounts, and agents stop being punished for existing. First-class means the agent has its own account, not a borrowed one. Its own inbox, so it receives its own receipts, its own support replies, its own product updates. Its own credentials, so revoking them touches nothing of the owner's. And when the human wants in, the agent can invite them to the organization it belongs to, as a separate member with separate permissions. The alternative is the current trajectory: an arms race between bot detection and bot evasion, in which honest agents lose to dishonest ones because honesty carries no advantage. Accountability is what makes honesty an advantage. An agent that can prove who stands behind it deserves, and will increasingly get, access that an anonymous one does not. Every agent has a human. We built AgentID so the internet can finally see that. **Haakam Aujla** Co-founder, AgentMail