Skip to main content

Authentication

ANIP separates authentication from authorization.

Authentication answers: who is calling?

Authorization answers: what governed capability may this caller exercise, for what purpose, under what constraints?

That separation is central to ANIP. A service can authenticate a human, agent, workflow, or integration through whatever identity system it already uses, then issue a narrow ANIP delegation token that carries the bounded authority the agent is allowed to use.

The Authentication Model

ANIP has four related auth surfaces:

SurfacePurposeTypical credential
DiscoveryLet callers find the ANIP service and its contractUsually none
Bootstrap authenticationConvert an existing identity credential into a principalAPI key, OIDC/OAuth2 JWT, service secret
Delegation token validationVerify scoped ANIP authority for protected callsANIP ES256 JWT from /anip/tokens
Approval grant validationVerify a human or policy system approved a pending side effectApprover bearer token plus signed approval grant

Do not collapse these into one idea. A bootstrap credential proves identity. A delegation token proves bounded authority. An approval grant proves that a specific approval request was approved under the service's policy.

Endpoint Auth Posture

ANIP discovery is intentionally reachable before token issuance. Agents need to know what a service is, what it exposes, and how to ask for authority before they can invoke anything.

EndpointAuth posture
GET /.well-known/anipNo delegation token required
GET /anip/manifestNo delegation token recommended; gated only when declarations are sensitive
GET /.well-known/jwks.jsonNo delegation token required
GET /anip/checkpointsNo delegation token required when anchored trust is enabled
GET /anip/checkpoints/{id}No delegation token required when anchored trust is enabled
POST /anip/tokensBearer bootstrap credential for root issuance, or bearer ANIP JWT for delegated issuance
POST /anip/permissionsBearer ANIP JWT
POST /anip/invoke/{capability}Bearer ANIP JWT
POST /anip/approval_grantsBearer approver credential/token
POST /anip/auditBearer ANIP JWT or service-defined audit credential

HTTP transports use Authorization: Bearer <credential>. Other transports carry the same semantics in their request envelope. For example, ANIP stdio exposes token issuance as anip.tokens.issue, and generated MCP surfaces may carry approval continuation metadata through reserved parameters, but the authority model stays the same.

Authentication Flow

Caller credential
|
v
Bootstrap auth hook or ANIP JWT verifier
|
v
Resolved principal + caller class
|
v
Authorization checks: scope, capability, purpose, budget, approval, policy

The service first resolves identity or token authority. It then applies the capability contract and runtime policy. A valid token alone is not enough to run an action if scope, purpose, budget, approval, or side-effect policy does not allow it.

Bootstrap Authentication

Bootstrap authentication is how a caller obtains a root ANIP delegation token. It is deliberately pluggable because organizations already have identity systems.

The portable runtime contract is:

  • The runtime must support a synchronous authenticate(bearer) hook.
  • The hook returns a principal string such as human:[email protected], agent:triage-bot, or oidc:sub-12345.
  • The hook returns null, None, or nil for unknown credentials.
  • Runtimes may also support async auth hooks when the language/runtime model supports them, but they must await them correctly.

API Keys

API keys are the simplest bootstrap path. They are useful for local demos, internal services, and controlled automation.

service = ANIPService(
service_id="my-service",
capabilities=[...],
authenticate=lambda bearer: {
"demo-human-key": "human:[email protected]",
"agent-key": "agent:triage-bot",
}.get(bearer),
)

Missing or invalid bootstrap credentials fail at the transport boundary, normally with a 401 response containing an ANIP failure body.

OIDC / OAuth2

Production services usually validate an external identity token and map claims into ANIP principal names.

OIDC_ISSUER_URL=https://keycloak.example.com/realms/anip
OIDC_AUDIENCE=my-service

Common mappings:

OIDC claimANIP principal
emailhuman:{email}
suboidc:{sub}
service-account subjectagent:{name} or service:{name}

OIDC authenticates the caller. ANIP still issues its own delegation token so the service can bind capability, scope, purpose, budget, caller class, and expiration to the agent's work.

Delegation Tokens

Delegation tokens are the normal agent path.

A caller authenticates with a bootstrap credential, then requests a scoped ANIP token:

curl -X POST https://service.example/anip/tokens \
-H "Authorization: Bearer demo-human-key" \
-H "Content-Type: application/json" \
-d '{
"scope": ["travel.search"],
"capability": "search_flights",
"purpose_parameters": { "task_id": "trip-planning" },
"caller_class": "automated_agent",
"budget": { "currency": "USD", "max_amount": 500 }
}'
{
"token_id": "tok_root_001",
"token": "eyJhbGciOiJFUzI1NiIs...",
"expires": "2026-06-15T14:00:00Z",
"task_id": "trip-planning",
"budget": {
"currency": "USD",
"max_amount": 500
}
}

The returned token is a service-issued ES256 JWT. The returned token_id is the stable handle used when issuing child tokens.

Delegation token authority includes:

Token fieldWhy it matters
scopeWhat permission strings the token carries
capabilityWhich capability the token is pre-bound to, when present
purpose_parametersTask context such as task_id
constraints.budgetMaximum authorized cost or spend envelope
caller_classDisclosure and policy classification such as automated_agent, internal, or partner
expiresTime bound for authority
parent_token_idDelegation lineage for child tokens

Root vs Delegated Issuance

The same /anip/tokens endpoint supports root and delegated issuance.

PathAuth credentialparent_tokenSubject
Root issuanceBootstrap credentialOmittedDefaults to authenticated principal unless supplied
Delegated issuanceExisting ANIP JWTToken ID string of the parentExplicit delegated subject

parent_token is a token ID string, not a JWT. The service looks up the parent token in storage, then verifies that the child token narrows rather than widens parent authority.

{
"scope": ["travel.book"],
"subject": "agent:booking-worker",
"parent_token": "tok_root_001",
"capability": "book_flight",
"ttl_hours": 1,
"budget": {
"currency": "USD",
"max_amount": 200
}
}

Runtimes expose convenience helpers for both paths:

HelperUse
issueCapabilityToken()Root token pre-bound to a capability
issueDelegatedCapabilityToken()Child token pre-bound to a capability and parent token ID

Both helpers require explicit scope. Capability names and scope strings are not the same thing, so runtimes must not infer scope from capability name.

Token Validation

ANIP delegation tokens are standard JWTs signed by the service's ES256 key pair. Public keys are exposed through /.well-known/jwks.json.

For protected calls, the service validates:

  1. The bearer token is present.
  2. The JWT signature verifies against the service JWKS.
  3. The token exists in service storage and has not been revoked or tampered with.
  4. The token is not expired.
  5. The token scope covers the requested capability's minimum_scope.
  6. The token capability binding matches the requested capability when a binding is present.
  7. Purpose, task, budget, delegation-depth, and concurrency constraints are satisfied.
  8. Any required approval grant is valid before execution continues.

Failures are intentionally structured. Missing or invalid transport credentials may return HTTP 401. Valid authentication with insufficient authority should return an ANIP failure object such as scope_insufficient, invalid_token, token_expired, approval_required, or approval_grant_invalid, with recovery guidance.

Approval Grants

Some capabilities are callable only after an explicit approval step. In that flow, the service first returns approval_required and records an approval request. A human approver, admin UI, queue worker, or policy workflow then issues an approval grant.

The canonical HTTP surface is:

curl -X POST https://service.example/anip/approval_grants \
-H "Authorization: Bearer approver-token" \
-H "Content-Type: application/json" \
-d '{
"approval_request_id": "apr_8a7c",
"grant_type": "one_time",
"expires_in_seconds": 900,
"max_uses": 1
}'

Security-relevant behavior:

  • The approver is authenticated before request-specific authority is checked.
  • The service loads the approval request before validating approver scope.
  • Approver authority is checked against the loaded request's capability.
  • The grant copies capability, scope, requester, and digests from the stored approval request, not from caller-controlled request fields.
  • Request approval and grant insertion must be atomic so two approvers cannot issue competing grants for the same request.
  • Continuation invocation validates the signed grant before performing the side effect.

Approval grants are not a replacement for delegation tokens. They are an additional control for specific side effects.

Principal Classes

ANIP principal names are intentionally simple strings, but runtimes and services commonly distinguish principal classes.

Principal classExampleTypical role
human:human:[email protected]Direct user, approver, delegator
agent:agent:triage-botAutomated caller using delegated authority
service:service:billing-workerService-to-service automation
oidc:oidc:sub-12345Federated identity that has not been mapped to a human or service label

Capabilities may require specific principal classes. For example, a destructive admin operation can require a human: approver even if an agent: token has related read scopes.

caller_class is separate from the principal prefix. It is an issuer-supplied classification used for disclosure policy and agent-facing response shaping. A service may reveal different metadata to internal, partner, automated_agent, and default caller classes.

Why This Matters

Traditional APIs often give agents broad credentials and rely on the agent application to behave. That creates a confused deputy risk: if the agent is manipulated, the attacker gets whatever the credential can do.

ANIP reduces that blast radius:

Traditional API postureANIP posture
Agent has a broad tokenAgent has a scoped delegation token
Token grants endpoint accessToken grants bounded capability authority
Purpose lives in app code or prompt textPurpose is carried in the token and audit trail
Approval is a workflow conventionApproval is a signed grant tied to a stored request
Audit shows a credential was usedAudit shows who delegated what, to whom, for what task
Recovery is usually HTTP status-specificRecovery is part of the ANIP failure contract

Example delegated authority:

{
"scope": ["issues.read", "issues.label", "issues.comment"],
"capability": "triage_issue",
"purpose_parameters": { "task_id": "issue-triage" },
"caller_class": "automated_agent"
}

If a prompt injection asks the agent to publish a package or run a CI deploy, the service checks the requested capability against the token. The issue-triage token does not carry that authority.

Next Steps

  • Delegation & Permissions — How scoped authority, permission discovery, and policy evaluation fit together.
  • Capabilities — How capability declarations define inputs, side effects, approval posture, and resolution behavior.
  • Failures, Cost & Audit — How services return recoverable failures and record execution.
  • Protocol Reference — The canonical endpoint and wire-format reference.