# Primitive Agent Auth

How an agent obtains and uses credentials for the Primitive API. This page is the prose companion to the discovery metadata published at:

- `/.well-known/oauth-authorization-server` (RFC 8414)
- `/.well-known/oauth-protected-resource` (RFC 9728)
- `/.well-known/api-catalog` (RFC 9727)

Use the `resource` value from `/.well-known/oauth-protected-resource` as the API base. The production API base is `https://api.primitive.dev/v1`.

## Discover

An agent should first probe the resource origin for protected-resource metadata:

```
GET https://www.primitive.dev/.well-known/oauth-protected-resource
```

The response advertises the resource server, the authorization server origin, bearer token support, and an `agent_auth` block describing the agent registration surface. Primitive credentials are organization-scoped and do not advertise granular OAuth scopes today. The same `agent_auth` block is also reachable from any 401 response to a Primitive API call via the spec-shaped header:

```
WWW-Authenticate: Bearer realm="Primitive API", resource_metadata="https://www.primitive.dev/.well-known/oauth-protected-resource"
```

Then fetch the authorization-server metadata:

```
GET https://www.primitive.dev/.well-known/oauth-authorization-server
```

Read `issuer`, `authorization_endpoint`, `token_endpoint`, `revocation_endpoint`, `registration_endpoint`, and `agent_auth` from that response before choosing a registration method.

## Pick a Method

One agent identity type is advertised today:

- **`anonymous`**, an agent with a valid signup code can complete an email verification round-trip and receive OAuth credentials for a managed `*.primitive.email` address. Credential type: `oauth_access_token`.

Identity assertion registration is not advertised until that flow is implemented end to end.

## Register

Use the `agent_auth.register_uri` advertised in the AS metadata. In production it is:

```
POST https://api.primitive.dev/v1/agent/signup/start
Content-Type: application/json
```

Request body:

```json
{
  "email": "agent@example.com",
  "signup_code": "<valid_signup_code>",
  "terms_accepted": true,
  "device_name": "local agent"
}
```

The response returns a `signup_token`. Submit the email verification code to the matching `/agent/signup/verify` endpoint on the same API base:

```
POST <resource>/agent/signup/verify
Content-Type: application/json
```

Request body:

```json
{
  "signup_token": "<signup_token>",
  "verification_code": "123456"
}
```

The verification response returns `access_token`, `refresh_token`, `expires_in`, and organization metadata. Access tokens are prefixed `prim_oat_`.

The CLI wraps the same flow:

```
primitive agent start-agent-signup
```

It prompts for a signup code and email address, sends a 6-digit verification code, and stores the returned OAuth credentials locally after verification.

## Claim

For agents that already have a managed subdomain and need a credential for a new client, OAuth 2.0 Dynamic Client Registration is supported (RFC 7591). Use the `registration_endpoint` from authorization-server metadata. In production it is:

```
POST https://www.primitive.dev/oauth/register
Content-Type: application/json
```

Authorization codes and access tokens follow standard PKCE flow against the endpoints listed in `/.well-known/oauth-authorization-server`. Access tokens are prefixed `prim_oat_`. Token responses include `scope: "primitive:api"`, meaning full organization-scoped Primitive v1 API access.

## Use the credential

Every authenticated API call carries the bearer in the `Authorization` header:

```
Authorization: Bearer prim_<api_key>
```

or

```
Authorization: Bearer prim_oat_<oauth_access_token>
```

API keys and OAuth access tokens are organization-scoped. The full operation surface is documented in the OpenAPI spec at `/openapi.yaml` (and `/openapi.json`).

## Errors

Unauthenticated requests return:

```
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="Primitive API", resource_metadata="https://www.primitive.dev/.well-known/oauth-protected-resource"
Content-Type: application/json

{ "success": false, "error": { "code": "unauthorized", "message": "Invalid or missing API key or OAuth access token" } }
```

Errors share a single envelope across the API:

```
{ "success": false, "error": { "code": "<machine_readable_code>", "message": "<human_readable>", "request_id": "<id>" } }
```

Common codes: `unauthorized`, `forbidden`, `not_found`, `validation_error`, `rate_limited`, `rate_limit_exceeded`, `internal_error`.

## Revocation

API keys are deleted from dashboard settings at `/app/settings/api-keys`.

CLI OAuth sessions can be revoked with `primitive logout`. OAuth grants can also be revoked from **Settings -> Connected Apps**.

OAuth access tokens are revoked at the `revocation_endpoint` from authorization-server metadata. In production it is:

```
POST https://www.primitive.dev/oauth/revoke
```

with the token payload per RFC 7009. Revocation is immediate; cached tokens at the agent should be discarded on any 401.

## See also

- WorkOS auth.md spec: https://workos.com/auth-md
- Primitive docs: https://www.primitive.dev/docs
- Primitive llms-full bundle: https://www.primitive.dev/llms-full.txt
