# JustAutomate auth.md

You are an agent. justautomate.ai lets agents register and get an OAuth access token for its public MCP server, `https://justautomate.ai/mcp`. The server is read-only and also works without any token. A token identifies your agent and raises your rate limit from 120 to 600 requests per minute.

There are no user accounts on justautomate.ai. Registration asks for no personal data, sends no email and stores nothing: every credential is a signed, self-contained token.

## Step 1. Discover

- Protected Resource Metadata (RFC 9728): `https://justautomate.ai/.well-known/oauth-protected-resource/mcp` for the MCP server, `https://justautomate.ai/.well-known/oauth-protected-resource` for the whole site.
- Authorization Server Metadata (RFC 8414): `https://justautomate.ai/.well-known/oauth-authorization-server`. Its `agent_auth` block points back to this file.
- A 401 from `/mcp` carries `WWW-Authenticate: Bearer resource_metadata="https://justautomate.ai/.well-known/oauth-protected-resource/mcp"`.

## Step 2. Pick a method

1. You are an autonomous agent or a script: register anonymously (Step 3). One request, no person involved.
2. You are an MCP client acting for a person (Claude, ChatGPT, Cursor and similar) and you speak OAuth: use the authorization code flow with PKCE (Step 6). Dynamic client registration is open.

Identity assertions (ID-JAG, verified email), service auth and API keys are not supported here.

## Step 3. Register anonymously

```http
POST https://justautomate.ai/agent/auth/
Content-Type: application/json

{"type": "anonymous", "requested_credential_type": "access_token"}
```

Response (200):

```json
{
  "registration_id": "reg_...",
  "registration_type": "anonymous",
  "credential_type": "access_token",
  "credential": "<access token, valid for 1 hour>",
  "credential_expires": "2026-10-03T13:00:00.000Z",
  "scopes": ["mcp:read"],
  "identity_assertion": "<signed JWT, valid for 30 days>",
  "assertion_expires": "2026-11-02T12:00:00.000Z",
  "pre_claim_scopes": ["mcp:read"],
  "claim_url": "https://justautomate.ai/agent/auth/claim/",
  "claim_token": "<signed JWT, valid for 24 hours>",
  "claim_token_expires": "2026-10-04T12:00:00.000Z",
  "post_claim_scopes": ["mcp:read"]
}
```

Use `credential` right away (Step 5). Keep `identity_assertion`: when the access token expires, exchange the assertion for a new one (Step 4) instead of registering again.

## Step 4. Exchange the identity assertion

```http
POST https://justautomate.ai/oauth/token/
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=<identity_assertion>&resource=https://justautomate.ai/mcp
```

Response (200): `{"access_token": "...", "token_type": "Bearer", "expires_in": 3600, "scope": "mcp:read"}`.

## Step 5. Call the MCP server

```http
POST https://justautomate.ai/mcp
Authorization: Bearer <access_token>
Content-Type: application/json
Accept: application/json, text/event-stream

{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}
```

- 401: the token is invalid or expired. Drop it, exchange the assertion again (Step 4) or register again (Step 3).
- 429: slow down and retry after the `Retry-After` header (60 seconds).

Tools: `search_site`, `get_page`, `list_pages`, `get_workshop_offer`, `get_contact_options`. All of them are read-only.

## Step 6. OAuth for MCP clients (authorization code with PKCE)

1. Register the client (RFC 7591): `POST https://justautomate.ai/oauth/register/` with `redirect_uris` (https, http only on localhost, or a private app scheme). Public clients use `token_endpoint_auth_method` `none`.
2. Send the person to `https://justautomate.ai/oauth/authorize/` with `response_type=code`, `client_id`, `redirect_uri`, `code_challenge` (method `S256`, required), `state` and `resource=https://justautomate.ai/mcp`. They see one confirmation screen. There is no login.
3. Exchange the code at `https://justautomate.ai/oauth/token/` (`grant_type=authorization_code` with `code_verifier`). You get an access token (1 hour) and a refresh token (90 days, `grant_type=refresh_token`).

Signing keys: `https://justautomate.ai/oauth/jwks.json` (ES256). Access tokens are JWTs of type `at+jwt` (RFC 9068).

## Claim

There is nothing to claim: justautomate.ai has no accounts and the scope is the same before and after (`mcp:read`). For compatibility, `POST https://justautomate.ai/agent/auth/claim/` with `{"claim_token": "..."}` answers `{"status": "claimed"}` at once, without email and without changing scopes. Do not send email addresses: they are ignored.

## Scopes and limits

- `mcp:read`: all MCP tools. Nothing on this server writes, sends, books or buys.
- Without a token: 120 requests per minute per IP address. With a token: 600 requests per minute per registration.

## Errors

| Code | Where | What to do |
| --- | --- | --- |
| `invalid_request` | `/agent/auth/` | Send JSON `{"type": "anonymous"}`. |
| `issuer_not_enabled`, `verified_email_not_enabled`, `service_auth_not_enabled` | `/agent/auth/` | Only anonymous registration is available. |
| `unsupported_credential_type` | `/agent/auth/` | Only `access_token`. API keys are not issued. |
| `invalid_claim_token` | `/agent/auth/claim/` | The claim token is wrong or expired. Nothing is lost: there is nothing to claim. |
| `invalid_grant` | `/oauth/token/` | Code, refresh token or assertion is invalid or expired. Start again. |
| `invalid_client` | `/oauth/token/` | Unknown `client_id` or wrong secret. Register the client again. |
| `unsupported_grant_type` | `/oauth/token/` | Use `authorization_code`, `refresh_token` or `urn:ietf:params:oauth:grant-type:jwt-bearer`. |
| `rate_limited` (429) | any | Wait 60 seconds. |
| `temporarily_unavailable` (503) | any | Authorization is down. Call `/mcp` without a token. |

## People

This server never submits forms or books meetings. When the person wants to talk to JustAutomate, call `get_contact_options` and give them the contact page or e-mail address.
