OAuth 2.1
OAuth 2.1 with PKCE and Dynamic Client Registration, so an MCP client can connect to LLM Pulse without the user pasting an API key.
OAuth 2.1 (ChatGPT Apps SDK, MCP clients)
OAuth 2.1 authorization server with PKCE-S256, Dynamic Client Registration (RFC 7591), and discovery metadata (RFC 8414 + RFC 9728). Used by ChatGPT Apps SDK and any other MCP client that supports OAuth. Available to all plans for the MCP resource at /api/v1/mcp. RS256-signed JWT access tokens and the reusable refresh token share a fixed one-year authorization deadline.
OAuth 2.1 Overview
Use OAuth 2.1 when your client needs per-user delegated access to the MCP endpoint and you cannot ship an API key (e.g., a multi-tenant AI assistant). Use API keys when you control both ends and want a simpler integration (Scale plan and above). MCP via OAuth is available on every plan including the free trial.
Endpoints: /oauth/authorize, /oauth/token, /oauth/register, /oauth/jwks.json, /.well-known/oauth-authorization-server, /.well-known/oauth-protected-resource.
GET/.well-known/oauth-authorization-server
Authorization-server metadata at /.well-known/oauth-authorization-server (RFC 8414) and protected-resource metadata at /.well-known/oauth-protected-resource (RFC 9728). The JWKS used to verify access-token signatures lives at /oauth/jwks.json. Clients should fetch these to discover the authorize, token, and registration endpoints, never hard-code them.
No parameters. Returns JSON with issuer, authorization_endpoint, token_endpoint, registration_endpoint, jwks_uri, scopes_supported, code_challenge_methods_supported, and related metadata.
POST/oauth/register
Dynamic Client Registration per RFC 7591. Unauthenticated and rate-limited to 5/hour per IP. Only RFC 7591 fields are persisted (extra fields are dropped). Redirect URIs must be HTTPS (any host) or HTTP loopback (localhost / 127.0.0.1); custom schemes like javascript:, data:, file: are rejected. Maximum 10 redirect URIs per client; client_name capped at 200 chars; URIs capped at 2048 chars.
JSON body: redirect_uris (required array), client_name, grant_types (defaults to authorization_code refresh_token), token_endpoint_auth_method (none for public PKCE clients, client_secret_post for confidential), scope.
GET/oauth/authorize
Renders an in-app consent screen. On approval, redirects the user back to redirect_uri with a single-use code (10-minute TTL) and the original state. PKCE-S256 is mandatory; plain challenges are rejected.
Params: response_type=code (required), client_id (required), redirect_uri (required, must match a registered URI exactly), code_challenge (required), code_challenge_method=S256 (required), scope (space-separated: mcp:read mcp:write), state, resource (RFC 8707 resource indicator).
POST/oauth/token
Exchanges an authorization code for an access token + refresh token, or refreshes an access token. Uses application/x-www-form-urlencoded. Rate-limited to 60/minute per IP. Refresh responses return the same reusable refresh token, and all credentials expire at the fixed one-year authorization deadline.
Body: grant_type (authorization_code or refresh_token), client_id (required), client_secret (required for confidential clients), and either {code, code_verifier, redirect_uri} OR {refresh_token, optional scope for downscoping}.
Scopes & Audience Verification
Two scopes are defined. mcp:read grants access to every read tool (list_*, get_*). mcp:write additionally grants the write tools (create_prompts, create_competitor, create_collection, assign_prompt_tags, create_annotation, create_intelligence_task, launch_recommendations, create_technical_geo_report). A token issued with only mcp:read cannot invoke write tools, both tools/list hides them and direct tools/call returns an error. The JWT aud claim must equal the resource server URL; tokens with a different audience are rejected at /api/v1/mcp.
When refreshing a token, you MAY pass a narrower scope, anything broader than the original grant returns invalid_grant.