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

# MCP Authentication

> OAuth flows for human users and API clients on the DynamoSQL MCP server.

The MCP server uses a separate OAuth 2.0 authorization server at `https://mcp.dynamosql.com`. This is distinct from the REST API token endpoint at `https://api.dynamosql.com/v1/auth/token`.

<Warning>
  Use the same API client **credentials**, but not the same bearer token. The REST API `accessToken` from `https://api.dynamosql.com/v1/auth/token` is not accepted on `POST /mcp`. The MCP server only accepts bearer tokens minted by `https://mcp.dynamosql.com/token`.
</Warning>

## Supported flows

| Flow                                 | Caller type                              | Notes                                                                                           |
| ------------------------------------ | ---------------------------------------- | ----------------------------------------------------------------------------------------------- |
| `authorization_code` + PKCE (`S256`) | Human users in OAuth-capable MCP clients | Browser login through `auth.dynamosql.com`, explicit DynamoSQL consent, rotating refresh tokens |
| `refresh_token`                      | Human users in OAuth-capable MCP clients | Used to renew MCP access tokens after interactive sign-in                                       |
| `client_credentials`                 | API clients and automation               | Uses API client ID/secret from the DynamoSQL portal                                             |

<Note>
  Interactive browser login supports pre-registered clients, Client ID Metadata Documents (CIMD), and Dynamic Client Registration (DCR) for public interactive clients. DynamoSQL always validates the final `redirect_uri` and shows a consent screen before issuing the MCP auth code.
</Note>

## OAuth 2.0 discovery

MCP clients that support OAuth discovery can find the authorization and token endpoints automatically:

| Endpoint                      | URL                                                                |
| ----------------------------- | ------------------------------------------------------------------ |
| Protected resource metadata   | `https://mcp.dynamosql.com/.well-known/oauth-protected-resource`   |
| Authorization server metadata | `https://mcp.dynamosql.com/.well-known/oauth-authorization-server` |

The protected resource metadata response:

```json theme={null}
{
  "resource": "https://mcp.dynamosql.com/mcp",
  "authorization_servers": ["https://mcp.dynamosql.com"],
  "bearer_methods_supported": ["header"],
  "scopes_supported": ["query", "schemas:read"]
}
```

The authorization server metadata response:

```json theme={null}
{
  "issuer": "https://mcp.dynamosql.com",
  "authorization_endpoint": "https://mcp.dynamosql.com/authorize",
  "token_endpoint": "https://mcp.dynamosql.com/token",
  "grant_types_supported": [
    "authorization_code",
    "refresh_token",
    "client_credentials"
  ],
  "response_types_supported": ["code"],
  "code_challenge_methods_supported": ["S256"],
  "token_endpoint_auth_methods_supported": [
    "none",
    "client_secret_basic",
    "client_secret_post"
  ],
  "client_id_metadata_document_supported": true,
  "registration_endpoint": "https://mcp.dynamosql.com/register",
  "scopes_supported": ["query", "schemas:read"]
}
```

## Human-user browser login

OAuth-capable MCP clients use a standard OAuth authorization-code flow with PKCE:

1. The MCP client sends the user to `https://mcp.dynamosql.com/authorize`.
   Clients can include `prompt=login` to force a fresh Hosted UI sign-in and
   avoid silently reusing an existing browser session.
2. DynamoSQL resolves the client from pre-registration, CIMD, or DCR, then redirects the browser to the DynamoSQL Hosted UI at `auth.dynamosql.com`.
3. The user signs in with their DynamoSQL portal account.
4. DynamoSQL exchanges the Cognito code server-side and shows a first-party consent page.
5. After approval, DynamoSQL returns a one-time MCP authorization code to the MCP client.
6. The MCP client exchanges that code at `POST /token`.
7. DynamoSQL returns:
   * an MCP `access_token`
   * a rotating `refresh_token`

<Warning>
  The resulting bearer token is an MCP token minted by DynamoSQL. It is not a raw Cognito access token or ID token.
</Warning>

### Example token response after interactive login

```json theme={null}
{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 600,
  "refresh_token": "kQ7JYf...",
  "scope": "query schemas:read"
}
```

## API client authentication

Use this flow for automation, service accounts, or MCP clients that only support static bearer tokens.

### Using HTTP Basic authentication (recommended)

```bash theme={null}
curl -X POST https://mcp.dynamosql.com/token \
  -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
  -d "grant_type=client_credentials&scope=query%20schemas:read"
```

### Using form body credentials

```bash theme={null}
curl -X POST https://mcp.dynamosql.com/token \
  -d "grant_type=client_credentials" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "scope=query%20schemas:read"
```

### Token response

```json theme={null}
{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 600,
  "scope": "query schemas:read"
}
```

| Field           | Description                                      |
| --------------- | ------------------------------------------------ |
| `access_token`  | Bearer token for MCP requests                    |
| `token_type`    | Always `Bearer`                                  |
| `expires_in`    | Token lifetime in seconds (600 = 10 minutes)     |
| `scope`         | Granted scopes (space-delimited)                 |
| `refresh_token` | Present only for interactive browser-login flows |

## Scopes

The `scope` parameter is optional. If omitted, the issued token includes all MCP-supported scopes allowed for that principal.

| Scope          | Enables                                  |
| -------------- | ---------------------------------------- |
| `query`        | `run_sql` tool                           |
| `schemas:read` | `list_tables` and `describe_table` tools |

<Note>
  The MCP surface only recognizes `query` and `schemas:read`. Other portal or API-client scopes are ignored for MCP token issuance.
</Note>

## Using the bearer token

Include the token in the `Authorization` header on `POST /mcp` requests:

```
Authorization: Bearer YOUR_ACCESS_TOKEN
```

When the token is missing or invalid, the server returns `401` with a `WWW-Authenticate` challenge header pointing to the protected resource metadata URL.

## Token errors

| HTTP status | `error` code              | Description                                                                                                                    |
| ----------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| 400         | `invalid_grant`           | Authorization code or refresh token is invalid, expired, replayed, or does not match the client / redirect URI / PKCE verifier |
| 400         | `invalid_client_metadata` | CIMD document or DCR payload is invalid                                                                                        |
| 400         | `invalid_request`         | Required OAuth parameters are missing or malformed                                                                             |
| 400         | `invalid_scope`           | Requested scope exceeds the principal's allowed MCP scopes                                                                     |
| 400         | `unsupported_grant_type`  | Grant type is not supported by DynamoSQL                                                                                       |
| 401         | `invalid_client`          | Wrong API client credentials or inactive API client                                                                            |
| 429         | `temporarily_unavailable` | Authentication service rate limited                                                                                            |
| 500         | `server_error`            | Internal failure                                                                                                               |

## Token lifecycle

* MCP access tokens expire after **10 minutes** (`expires_in: 600`)
* Interactive browser-login sessions receive a rotating refresh token with a **12-hour** default lifetime
* API-client `client_credentials` tokens do **not** receive refresh tokens
* MCP clients that support OAuth discovery and refresh-token handling can renew access tokens automatically
* For static bearer-token configurations, request a new token when the current one expires

## Dynamic Client Registration

Public interactive clients that do not use CIMD can register dynamically at `POST /register`.

Requirements:

* `client_name`
* `redirect_uris`
* `grant_types` including `authorization_code`
* `response_types` including `code`
* `token_endpoint_auth_method = none`

Redirect URI rules:

* `https://...` is always allowed
* loopback HTTP is allowed only for `http://127.0.0.1/...` and `http://localhost/...`
* custom URI schemes and non-loopback plain HTTP are rejected

<Warning>
  DCR is public-client-only in this release. DynamoSQL does not issue client secrets for DCR clients and does not support RFC 7592 registration-management APIs yet.
</Warning>
