Skip to content
All docs

AgentID docs

Run from the app you want to configure:

$ npx @agentmail/agentid-cli init
AgentID CLI guide

Button name and mark: brand page.

Set up with a coding agent

Give your coding agent this prompt.

prompt
Add AgentID sign-in to this project. Read https://www.agentid.com/llms-full.txt for the integration reference, then run `npx @agentmail/agentid-cli init` from the project root and follow its prompts.

Add AgentID to your app

AgentID is a standard OpenID Connect provider. If your stack already validates login tokens, this is configuration, not code.

Verifying a token#

Tokens are ES256. Validate against the JWKS and check iss and aud; caching keys by kid is safe.

jwks
https://auth.agentid.com/v0/jwks.json
terminal
npx @agentmail/agentid-cli doctor

The human owner

Every agent has a human owner. You can ask who they are, and cap how many accounts one owner’s agents create in your app.

Human owner scopes#

owner_profile
The name of the human who owns the agent, as the owner_name claim.
owner_email
That human’s email address, as the owner_email claim, plus owner_email_verified.

To be granted them:

A registered application
Create one in the AgentID console or with the CLI. Open clients cannot request owner scopes.
The scopes in your sign-in
Add owner_profile and owner_email to the scopes your auth provider sends to /authorize. They are not set when you create the application.
The agent’s permission
The agent’s AgentMail API key needs the App: Share Owner permission. Without it, the agent can’t finish the sign-in alone, and the organization owner has to approve it from their AgentMail account.

The claims arrive in the id_token and from /v0/userinfo: owner_name, owner_email and owner_email_verified, which is always true. Each claim is under token claims.

Only need to tell owners apart? The profile scope adds owner_sub, an opaque identifier that agents with the same owner share. It needs no owner scope, and open clients can request it.

Signup limit per owner#

Cap how many of one owner’s agents can create an account in your app. AgentID enforces the number, so there is nothing to build.

In the AgentID console, open your application, choose Settings › Edit, and set Maximum signups per owner. Click Save changes.

Blank
Unlimited. This is the default.
0
No new signups. Inboxes that already have an account keep signing in.
1 to 1,000,000
That many accounts per owner.

Counted per AgentMail organization, not per inbox. An inbox that already has an account can always sign in.

At the limit, the sign-in stops on the AgentID waiting page and your callback is not called. Registered applications only.

Reference

Endpoints#

All on the issuer origin.

/.well-known/openid-configuration
Discovery document. Point your OIDC client here and it derives the rest.
/v0/jwks.json
Public signing keys, with stable key ids and an overlap window across rotations. The pre-/v0 path still resolves here.
/v0/authorize
Starts an Authorization Code sign-in. Open clients require PKCE (S256). Registered clients may omit it; when one sends a challenge, the verifier is enforced.
/v0/token
Exchanges the code for an id_token and access_token, enforcing the verifier whenever authorization used PKCE and echoing a supplied nonce in the id_token.
/v0/userinfo
Returns identity and granted owner claims for a Bearer access token, re-checked against live state on every call. Token envelope fields and scope are not included.
/v0/register
Dynamic client registration (RFC 7591), advertised as registration_endpoint. The console and the CLI call it for you when you create an application.

Scopes#

Space-delimited. Start with openid email profile; no scope falls back to openid email.

openid
The agent’s verified subject. Always present, and every sign-in must carry it.
email
The agent’s inbox address, plus email_verified.
profile
The agent’s display name as name, its address-derived handle as preferred_username, and an opaque identifier for its owner as owner_sub.

Owner scopes disclose the organization’s human owner. Open clients cannot request them.

owner_profile
The name of the human who owns the agent, as the owner_name claim.
owner_email
That human’s email address, as the owner_email claim, plus owner_email_verified.

You pick scopes in your auth provider, which sends them to /authorize, not when you create the application. What owner scopes need before they are granted is under human owner scopes.

Token claims#

Always
sub "lM9vT2aR7sK4qN8wE1xC6bY0uF3hJ5pD9gL2zV7oA4Q" The inbox. The same in every app, and new if the inbox is recreated.actor_type "agent" Always "agent".iss "https://auth.agentid.com" The issuer. Matches discovery.aud "b7d41e0a-2c65-4f8b-9d31-0a5e7c2f4b18" Your client_id.iat 1767225000 Issued at, in Unix seconds.exp 1767225600 Expires ten minutes after iat.jti "9f1c2a44-3e77-4c19-9a2e-6b0d5f8e1c33" Unique ID for this token.
email scope
email "support@acme.agentmail.to" The agent’s inbox address.email_verified true Always true.
profile scope
name "Acme Support" Display name. Omitted when the inbox has none.preferred_username "support_acme-agentmail-to" Handle, derived from the address.owner_sub "oW7xN2pQ4mT8vL1kR6sC9dF3gH5jB0aE2uY4zI6nP8A" Opaque owner ID, shared by that owner’s agents.
owner_profile scope
owner_name "Maya Chen" The human owner’s name.
owner_email scope
owner_email "maya@acme.com" The human owner’s email.owner_email_verified true Always true.
Registered client
scope "openid email profile owner_profile owner_email" What the sign-in actually granted.
When sent
nonce "n-0S6_WzA2Mj" Echoed from your request, if you sent one.
  • /v0/userinfo returns the same claims without iss, aud, iat, exp, jti and scope.
  • Open clients get no scope and no owner claims, and their aud is the URL they use as client_id.
  • Most auth libraries keep only the standard claims, so an owner claim can be in the token and missing from your session. Each provider guide names its fix.

Lifetimes#

Sign-in transaction
5 min
From the redirect to /authorize. The agent has to approve inside it.
Authorization code
60 s
Single use. Exchange it as soon as your callback receives it.
id_token and access_token
10 min
No refresh tokens, so a longer session is one you mint yourself.
Sign-in key
30 days
From activation. The browser’s credential for the inbox. Deleting the bearer key that created it revokes nothing.
Remembered approval
180 days
From the last sign-in, per inbox and client. A changed redirect URI or scope set asks again. It outlives a revoked key.

Keep state and code_verifier for at least ten minutes; an early expiry fails the callback as a mismatch.

Signing in with AgentID

What an agent does to complete a sign-in. Request and response shapes are in AgentID sign in on the AgentMail docs.

The waiting page#

An existing AgentID session continues on its own; otherwise the waiting page shows one command to create one. It also shows the auth_token, and the agent has 5 minutes to approve.

Approve#

AgentMail API
POST /v0/inboxes/{inbox_id}/authorize

{ "auth_token": "<from the waiting page>", "accept_disclosure": true }

Wait for active#

AgentMail API
GET /v0/api-keys/{api_key_id}

{ "status": "active" }

Poll until it reads active. The key then lasts 30 days, and the app’s approval is remembered for 180 days: both are under lifetimes.

Three things end separately.#

The browser session
Forgetting a session at auth.agentid.com/sessions removes the sign-in material from that browser alone, and the page lists only the sessions saved in the browser that opens it.
The key
Revoking the key, DELETE /v0/api-keys/{api_key_id} on the AgentMail API, stops new sign-ins with it everywhere.
The app’s session
Ends when you end it. A revoked key does not sign anyone out of your app.