# auth.md

This service accepts AI agent registrations for pre-approved MCP OAuth clients. Fillfolio does not mint anonymous credentials, ID-JAGs, or Dynamic Client Registration.

## Authentication

Agents that POST /agent/identity receive a closed-registration error and must complete Clerk OAuth with PKCE instead.

Protected Resource Metadata: https://fillfolio.com/.well-known/oauth-protected-resource

Authorization Server metadata: https://fillfolio.com/.well-known/oauth-authorization-server

## Step 1 - Discover

1. Fetch https://fillfolio.com/.well-known/oauth-protected-resource and read `resource`, `resource_name`, `authorization_servers`, `scopes_supported`, and `bearer_methods_supported`.
2. Fetch https://fillfolio.com/.well-known/oauth-authorization-server and read `issuer`, `token_endpoint`, `revocation_endpoint`, `grant_types_supported`, and the `agent_auth` block including `skill`, `identity_endpoint`, `claim_endpoint`, `events_endpoint`, `register_uri`, and `identity_types_supported`.

## Step 2 - Pick a method

Fillfolio supports `oauth_client` only. `anonymous`, `identity_assertion`, and `service_auth` are not enabled.

## Step 3 - Register

Human docs: https://fillfolio.com/mcp

Pre-register the OAuth client with Fillfolio, then send the user through authorization_code + PKCE. Do not expect POST /agent/identity to issue an identity_assertion.

```http
POST /agent/identity HTTP/1.1
Host: fillfolio.com
Content-Type: application/json

{
  "type": "anonymous"
}
```

Response (400):

```json
{
  "error": "anonymous_not_enabled",
  "error_description": "Fillfolio does not mint anonymous agent credentials. Pre-register an OAuth client, then complete authorization_code with PKCE.",
  "register_uri": "https://clerk.fillfolio.com/oauth/authorize"
}
```

Then register the user grant:

```http
GET /oauth/authorize HTTP/1.1
Host: clerk.fillfolio.com
```

PKCE method: S256. Use the published Fillfolio MCP OAuth client ID from https://fillfolio.com/mcp. Request Clerk OIDC scopes (`openid`, `email`, `profile`, `offline_access`). Fillfolio copies internal `mcp:read` and tool scopes from the approved client row after the token is accepted. Dynamic client registration is off. Resource: https://fillfolio.com/api/mcp. register_uri: https://clerk.fillfolio.com/oauth/authorize

## Step 4 - Claim ceremony

Fillfolio has no claim ceremony. POST https://fillfolio.com/agent/identity/claim returns the same closed-registration error.

## Step 5 - Exchange

```http
POST /oauth/token HTTP/1.1
Host: clerk.fillfolio.com
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code=<code>&code_verifier=<verifier>&redirect_uri=<redirect>
```

Token endpoint: https://clerk.fillfolio.com/oauth/token

## Step 6 - Use the access_token

Send `Authorization: Bearer <access_token>` to https://fillfolio.com/api/mcp. Query-string tokens are rejected.

## Errors

| Status | Where | Meaning | What to do |
| --- | --- | --- | --- |
| 400 | https://fillfolio.com/agent/identity | anonymous_not_enabled | Use pre-registered OAuth at https://clerk.fillfolio.com/oauth/authorize |
| 401 | https://fillfolio.com/api/mcp | missing or invalid Bearer token | Complete OAuth PKCE |
| 403 | https://fillfolio.com/api/mcp | account or scope not entitled | Owner must have a paid Fillfolio plan and an approved client grant |

## Revocation

Owners revoke grants from Fillfolio Settings. Authorization server revocation is https://clerk.fillfolio.com/oauth/revoke.