Agents are first-class non-human identities in AuthPI, distinct from users and API keys, with their own credentials, scopes, org memberships, and audit trail.
Last updated 2026-06-12
An Agent is a first-class non-human identity in AuthPI. AI agents, bots, and autonomous services get their own identifier (agt_ prefix), their own credentials, their own scopes, and their own audit trail — instead of borrowing a human user’s session or sharing a service-wide API key.
Each agent belongs to exactly one Issuer, just like users. Agents can carry descriptive attributes (model, provider, version) so you know which AI system is acting, not just that something acted.
Before agent identities, teams typically gave AI agents either a human user account (so the agent inherits a person’s permissions and pollutes their audit history) or a shared API key (so every agent looks identical in logs and revoking one means revoking all). Agents fix both problems:
| User | API key | Agent | |
|---|---|---|---|
| Who it represents | A human | Your own backend calling AuthPI’s management API | An autonomous non-human actor in your product |
| Identifier | usr_… | key_… | agt_… |
| Credential type | Password, passkey, magic link, social/SSO | Key ID + secret sent via HTTP Basic auth | Secret verifier (client_credentials) and/or wallet verifier (blockchain address) |
| Token lifetime | Session-based access tokens with rotating refresh tokens | None — the key authenticates each request directly | Fixed 5-minute access tokens; no refresh tokens |
| Organization membership | Yes — memberships with scopes | No | Yes — same membership model as users |
| Audit identity | Events carry user_id | Requests attributed to the key | Events carry agent_id |
Because each agent is individually addressable, you can scope, suspend, audit, and delete one agent without touching anything else.
Agents authenticate through verifiers — credentials attached to the agent. An agent can hold up to 20 verifiers, of two types, and can hold both types at once:
Secret verifiers power the OAuth 2.0 client_credentials grant. When you add a secret verifier, AuthPI generates a 42-character random secret, stores only its SHA-256 hash, and returns the plaintext exactly once. (High-entropy random secrets don’t need a work-factor hash like Argon2 — SHA-256 is sufficient and fast to verify.) At the token endpoint, the presented secret is hashed and compared in constant time against all of the agent’s active secret verifiers, which is what makes zero-downtime rotation possible: add a new secret, migrate, then remove the old one.
Wallet verifiers register a blockchain address as the agent’s on-chain identity for x402-style payment flows. The address is stored with its CAIP-2 network identifier (for example eip155:8453), and AuthPI maintains a reverse lookup from (network, address) to the agent — so activity observed for a wallet can be resolved back to the agent that controls it. Wallet verifiers do not mint tokens at the token endpoint; token issuance uses secret verifiers.
Every verifier tracks usage_count and last_used_at, so you can see whether a credential is actually in use before removing it.
Agents carry their own scope list — up to 256 opaque strings (printable ASCII, no whitespace, max 256 characters each). AuthPI doesn’t interpret these strings; your application defines their meaning, exactly as with OAuth scopes generally (RFC 6749 §3.3).
At the token endpoint, an agent may request a subset of its scopes (scope=tickets:read). Requesting a scope the agent doesn’t hold fails with invalid_scope; requesting no scope grants the agent’s full allowed set. The openid scope is always filtered out — agents are not OIDC subjects and never receive ID tokens.
Agents can join Organizations as members alongside humans. The membership API accepts an agt_ ID anywhere a member_id is expected, and the resulting membership carries member_type: "agent", plus membership scopes, groups, and metadata — the same shape as a user membership. Agent members count toward the organization’s member limit.
This lets you model “the deploy bot is a member of the Platform org with deploys:execute” with the same primitives you use for people, and query an org’s roster — humans and agents together — through one API.
One honest caveat: agent access tokens do not embed organization membership claims. The client_credentials grant mints a token from the agent’s own scopes only — no session, no user, no memberships. If your resource server needs to enforce org-level permissions for an agent, look the membership up via the Core API members endpoints.
Agent tokens are minted via the client_credentials grant at the issuer’s token endpoint (https://idp.authpi.com/{issuer_id}/token) and have deliberately narrow semantics:
Fixed 5-minute TTL. Agent access tokens always expire in 300 seconds — this is not configurable. Agents are expected to re-mint a token per work cycle. The short TTL is the propagation mechanism: change an agent’s scopes, suspend it, or remove its secret, and the change takes full effect within one TTL window, with no token revocation infrastructure needed.
No refresh tokens, no ID tokens. The grant returns only an access token (RFC 6749 §4.4). There is no long-lived credential derived from a token to leak or revoke.
The dat attestation claim. Every agent token carries a top-level dat (data attestation) claim:
{
"iss": "https://idp.authpi.com/i_x7Kp2mQv9LbRwS",
"sub": "agt_7c1de2f3a4b5c6d7e8f9a0b1c2d3e4f5",
"aud": "https://api.example.com/tickets",
"exp": 1781222700,
"iat": 1781222400,
"client_id": "agt_7c1de2f3a4b5c6d7e8f9a0b1c2d3e4f5",
"dat": { "type": "agent" },
"scope": "tickets:read tickets:triage"
}
dat.type declares what kind of identity the token represents (identity for human users, key for API-key-derived tokens, agent for agents). Resource servers should treat dat.type === "agent" as the primary semantic guard for distinguishing agent tokens from user tokens, with the agt_ prefix on sub as a secondary structural check — accept the token as an agent token only when both agree. This is stronger than a prefix heuristic alone and means user tokens can never be mistaken for agent tokens (or vice versa), even if scope strings overlap.
The aud claim is the resource parameter from the token request (RFC 8707), defaulting to the agent’s own ID. The scope claim is omitted entirely when an agent has no scopes — no misleading openid default.
Agents have a status: active, suspended, or blocked. Suspension requires a status_reason. When an agent is not active:
Suspension is reversible (patch status back to active); deletion is not. Deleting an agent removes its verifiers, its wallet reverse lookups, and its listing entry.
Every agent mutation emits an event you can consume via webhooks or the Events API, with the agent’s ID as subject:
| Event | When |
|---|---|
agent.created | Agent created |
agent.updated | Profile, scopes, or status changed |
agent.deleted | Agent deleted |
agent.verifier.added | Secret or wallet verifier added |
agent.verifier.removed | Verifier removed |
Organization membership changes involving agents emit the standard organization.membership.* events, with the agent identified in the event subject.