File size: 4,293 Bytes
d705bb5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | ---
title: "OAuth 2.1 Server"
description: "Dynamic client registration, authorization, and token exchange endpoints that back the World Monitor MCP server's OAuth 2.1 authentication flow."
---
WorldMonitor runs a minimal OAuth 2.1 authorization server whose only client-facing purpose today is **granting access to the MCP server** at `/api/mcp`. It implements:
- [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) β Dynamic Client Registration
- [RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636) β PKCE (required, S256 only)
- [RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414) β Authorization Server Metadata
- [RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728) β Protected Resource Metadata
## Discovery
| URL | Purpose |
|-----|---------|
| `/.well-known/oauth-authorization-server` | AS metadata (endpoints, supported grants, PKCE methods) |
| `/.well-known/oauth-protected-resource` | Resource metadata (authorization servers, scopes) |
`/.well-known/oauth-protected-resource` currently advertises the public resource scope `mcp`. Pro authorization-code grants return the internal scope value `mcp_pro`; legacy API-key grants and `client_credentials` return `mcp`.
## Endpoints
### `POST /api/oauth/register`
Dynamic Client Registration. Returns a `client_id` (public clients, no secret).
**Request**:
```json
{
"redirect_uris": ["https://claude.ai/api/mcp/auth_callback"],
"client_name": "Claude Desktop",
"token_endpoint_auth_method": "none"
}
```
**Response**:
```json
{
"client_id": "7c3b08f0-0c1f-4a9c-8a52-69e13d2a5d5e",
"client_name": "Claude Desktop",
"redirect_uris": ["https://claude.ai/api/mcp/auth_callback"],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "none"
}
```
**Redirect URI allowlist**: only these prefixes are accepted:
- `https://claude.ai/api/mcp/auth_callback`
- `https://claude.com/api/mcp/auth_callback`
- `http://localhost:<port>` / `http://127.0.0.1:<port>` β any port
**Rate limit**: 5 registrations / 60 s / IP.
**Client TTL**: 90 days sliding (every successful token exchange refreshes).
### `GET /api/oauth/authorize`
Starts the OAuth flow. Renders a consent page that redirects to Clerk for sign-in, then issues an authorization code bound to the caller's PRO entitlement.
**Required query params**:
- `response_type=code`
- `client_id` β from DCR
- `redirect_uri` β must match the one registered
- `code_challenge` β PKCE S256
- `code_challenge_method=S256`
- `state` β opaque
- `scope` (optional)
**Code TTL**: 10 minutes. Single-use (atomic `GETDEL` on exchange).
### `POST /api/oauth/token`
Exchanges an authorization code for an access token, or refreshes an existing token.
**Grant type: `authorization_code`**:
```
grant_type=authorization_code
code=<from /authorize>
code_verifier=<PKCE>
client_id=<from DCR>
redirect_uri=<same as /authorize>
```
**Response**:
```json
{
"access_token": "6f13d8fa-89b6-4a02-a527-7f6f61a2df55",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "6ba38313-9a4d-4797-9186-3d2c3c1cfe02",
"scope": "mcp_pro"
}
```
**Grant type: `refresh_token`**:
```
grant_type=refresh_token
refresh_token=<from previous exchange>
client_id=<from DCR>
```
**Rate limit**: 10 token requests / minute. The limiter is keyed by `client_secret` hash for `client_credentials`, by `client_id` when present (`authorization_code` and `refresh_token`), and falls back to caller IP only when neither identifier is available.
**Token TTLs**:
- Access token: 1 hour
- Refresh token: 7 days
Access and refresh tokens are opaque UUIDs. All token-endpoint responses include `Cache-Control: no-store, Pragma: no-cache`.
## Using tokens
Pass the access token on every MCP request:
```
Authorization: Bearer 6f13d8fa-89b6-4a02-a527-7f6f61a2df55
```
Tokens are bound to the user's account and re-check entitlement on every call β a downgrade revokes access on the next request.
## Error responses
Per [RFC 6749 Β§5.2](https://datatracker.ietf.org/doc/html/rfc6749#section-5.2):
```json
{ "error": "invalid_grant", "error_description": "..." }
```
Common errors: `invalid_request`, `invalid_client`, `invalid_grant`, `unsupported_grant_type`, `invalid_scope`.
|