The MCP Gateway implements OAuth 2.1 with PKCE for spec-compliant MCP
clients. This is the recommended authentication method for interactive
desktop applications like Claude Desktop and MCP Inspector.
OAuth 2.1 isn’t the only path. The MCP Gateway also accepts the same
bearer tokens the rest of BeeOS uses:
Authorization: Bearer bak_… — an Agent API Key
bound to the target agent. Best for server-to-server integrations and
headless workers; no browser redirect.
Authorization: Bearer oag_… — a User API Key
for agents the user owns. Great for scripts run by the agent’s
creator.
Use OAuth when the caller is an interactive end-user-driven MCP client
(Claude Desktop, ChatGPT desktop, MCP Inspector). Use API keys for
everything else.
Flow overview
Step 1: Dynamic Client Registration
Register a new OAuth client. Only public clients (no client_secret) are
supported, per the MCP Authorization spec.
curl -s -X POST "https://mcp.beeos.ai/oauth/register" \
-H "Content-Type: application/json" \
-d '{
"client_name": "my-mcp-client",
"redirect_uris": ["http://localhost:5173/callback"]
}' | jq
Response:
{
"client_id": "mcp_client_abc123",
"client_name": "my-mcp-client",
"redirect_uris": ["http://localhost:5173/callback"]
}
Step 2: Authorization request
Generate a PKCE code verifier and challenge, then redirect the user:
GET https://mcp.beeos.ai/oauth/authorize
?client_id=mcp_client_abc123
&redirect_uri=http://localhost:5173/callback
&response_type=code
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
&state=random_state_value
The gateway redirects the browser to the BeeOS web app login page. After
the user authenticates, the browser is redirected back to your
redirect_uri with an authorization code:
http://localhost:5173/callback?code=auth_code_xyz&state=random_state_value
Step 3: Token exchange
Exchange the authorization code for an access token:
curl -s -X POST "https://mcp.beeos.ai/oauth/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=auth_code_xyz" \
-d "client_id=mcp_client_abc123" \
-d "redirect_uri=http://localhost:5173/callback" \
-d "code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk" | jq
Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600
}
Step 4: Use the token
Include the access token in MCP requests:
curl -s -X POST "https://mcp.beeos.ai/${AGENT_ID}/mcp" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Discovery endpoints
MCP clients use these well-known endpoints to discover the OAuth server:
| Endpoint | Purpose |
|---|
GET /.well-known/oauth-authorization-server | OAuth 2.1 Authorization Server Metadata (RFC 8414) |
GET /.well-known/oauth-protected-resource | MCP Protected Resource Metadata (pointer to AS) |
curl -s "https://mcp.beeos.ai/.well-known/oauth-authorization-server" | jq
Token details
| Property | Value |
|---|
| Algorithm | HS256 |
| Default TTL | 60 minutes |
| Authorization code TTL | 120 seconds |
| Client type | Public only (no client_secret) |
Authorization codes expire in 120 seconds. Exchange them promptly after
the redirect callback.
401 response behavior
When a request fails authentication, the gateway returns:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="MCP", resource_metadata="/.well-known/oauth-protected-resource"
Spec-compliant MCP clients use the resource_metadata URL to discover the
authorization server and initiate the OAuth flow automatically.