> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bedrock.cv/llms.txt
> Use this file to discover all available pages before exploring further.

# OAuth 2.1

> Authenticate third-party integrations using OAuth 2.1 with PKCE.

Bedrock supports OAuth 2.1 authorization code flow with PKCE for third-party integrations like Microsoft 365 Copilot, ChatGPT, and Claude. OAuth lets external AI agents authenticate to the Bedrock API on behalf of an organization.

## When to Use OAuth vs API Keys

|                             | API Keys                            | OAuth 2.0                                            |
| --------------------------- | ----------------------------------- | ---------------------------------------------------- |
| **Use case**                | Direct API access, scripts, CI/CD   | Third-party integrations (Copilot, ChatGPT, Claude)  |
| **Who creates credentials** | You, in the Bedrock dashboard       | Automated via dynamic registration or pre-configured |
| **Token lifetime**          | Long-lived (with optional rotation) | Short-lived access (1 hour) + refresh token          |
| **Authentication**          | `Authorization: Bearer sk_...`      | `Authorization: Bearer oat_...`                      |

## Discovery (MCP Auth Spec)

AI copilots discover Bedrock's OAuth configuration automatically using well-known metadata endpoints.

### Protected Resource Metadata

```
GET /.well-known/oauth-protected-resource
```

Returns:

```json theme={null}
{
  "resource": "https://api.bedrock.cv",
  "authorization_servers": ["https://api.bedrock.cv"],
  "scopes_supported": ["read", "write"],
  "bearer_methods_supported": ["header"]
}
```

### Authorization Server Metadata

```
GET /.well-known/oauth-authorization-server
```

Returns:

```json theme={null}
{
  "issuer": "https://api.bedrock.cv",
  "authorization_endpoint": "https://app.bedrock.cv/oauth/authorize",
  "token_endpoint": "https://api.bedrock.cv/oauth/token",
  "registration_endpoint": "https://api.bedrock.cv/oauth/register",
  "revocation_endpoint": "https://api.bedrock.cv/oauth/revoke",
  "scopes_supported": ["read", "write"],
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "token_endpoint_auth_methods_supported": ["none"],
  "code_challenge_methods_supported": ["S256"]
}
```

### WWW-Authenticate Header

Unauthenticated requests to protected endpoints return:

```
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://api.bedrock.cv/.well-known/oauth-protected-resource"
```

## Client Registration

Bedrock supports three methods for registering OAuth clients:

### Static Clients

Pre-registered for known partners (e.g., Microsoft Copilot). These are seeded in the database with a fixed slug as the `client_id`.

### Dynamic Client Registration (RFC 7591)

Clients like Claude self-register by POSTing to `/oauth/register`:

```bash theme={null}
POST /oauth/register
Content-Type: application/json

{
  "client_name": "Claude",
  "redirect_uris": ["https://claude.ai/api/mcp/auth_callback"],
  "grant_types": ["authorization_code"],
  "response_types": ["code"],
  "token_endpoint_auth_method": "none"
}
```

Response:

```json theme={null}
{
  "client_id": "550e8400-e29b-41d4-a716-446655440000",
  "client_name": "Claude",
  "redirect_uris": ["https://claude.ai/api/mcp/auth_callback"],
  "grant_types": ["authorization_code"],
  "response_types": ["code"],
  "token_endpoint_auth_method": "none"
}
```

### Client ID Metadata Documents (CMID)

Clients like ChatGPT use a URL as their `client_id`. When Bedrock encounters a URL-based client\_id, it fetches the metadata document to validate the client and its redirect URIs.

## Authorization Code Flow with PKCE

```
1. AI copilot discovers OAuth config via well-known endpoints
2. Copilot registers as a client (DCR or CMID)
3. Copilot redirects user to Bedrock consent screen
4. User logs in, selects organization, and authorizes
5. Consent screen signs an authorization code and redirects to copilot callback
6. Copilot exchanges code + PKCE verifier for access token
7. Copilot uses access token to call Bedrock API
8. When token expires, copilot uses refresh token to get a new one
```

### Step 1: Authorization

The copilot redirects the user to the consent screen:

```
https://app.bedrock.cv/oauth/authorize
  ?response_type=code
  &client_id=550e8400-e29b-41d4-a716-446655440000
  &redirect_uri=https://claude.ai/api/mcp/auth_callback
  &scope=read
  &state=random_csrf_token
  &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
  &code_challenge_method=S256
```

The user logs in (if needed), sees the client name and requested permissions, selects an organization, and clicks Authorize or Deny.

On approval, the consent screen signs a PKCE-bound authorization code and redirects directly to the client's callback:

```
302 redirect to redirect_uri?code=...&state=...
```

### Step 2: Token Exchange

```bash theme={null}
POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=abc123
&redirect_uri=https://claude.ai/api/mcp/auth_callback
&client_id=550e8400-e29b-41d4-a716-446655440000
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
```

**Response:**

```json theme={null}
{
  "access_token": "oat_a1b2c3...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "ort_d4e5f6...",
  "scope": "read"
}
```

### Step 3: Use the Access Token

```bash theme={null}
curl https://api.bedrock.cv/mcp \
  -H "Authorization: Bearer oat_a1b2c3..." \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"list_projects","arguments":{}},"id":1}'
```

### Step 4: Refresh

```bash theme={null}
POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token=ort_d4e5f6...
&client_id=550e8400-e29b-41d4-a716-446655440000
```

Returns a new access/refresh token pair. The old refresh token is revoked.

### Step 5: Revoke

```bash theme={null}
POST /oauth/revoke
Content-Type: application/x-www-form-urlencoded

token=oat_a1b2c3...
```

Always returns 200 OK, even if the token was already revoked or not found (per RFC 7009).

## Scopes

| Scope   | Permissions                                                                      |
| ------- | -------------------------------------------------------------------------------- |
| `read`  | Read projects, drawings, sheets, blocks, features, overlays, jobs, organizations |
| `write` | Create/update projects, drawings, files, jobs                                    |

## Platform Compatibility

|              | ChatGPT                      | Claude.ai / Cowork | Claude Code           | Microsoft Copilot       |
| ------------ | ---------------------------- | ------------------ | --------------------- | ----------------------- |
| Registration | CMID preferred, DCR fallback | DCR                | DCR or pre-configured | Pre-registered (static) |
| PKCE         | Required (S256)              | Required (S256)    | Required (S256)       | Optional                |

## Security

* All tokens are stored as SHA-256 hashes (never in plaintext)
* Access tokens expire after 1 hour
* Refresh tokens expire after 30 days
* PKCE (S256) is required for all authorization requests
* Authorization codes expire after 10 minutes
* Tokens are scoped to a specific organization (selected during consent)
