Skip to main content

OAuth Flow

email-connector implements OAuth 2.0 Authorization Code with PKCE (RFC 7636) using the S256 challenge method. This is the same pattern used by mobile apps and SPAs where the client cannot securely store a secret.

Why OAuth + PKCE?

Claude’s MCP connector system uses OAuth to authorize third-party tools. PKCE adds a layer of protection that prevents authorization code interception — even if someone captures the code in transit, they cannot exchange it for a token.

Step-by-Step Flow

1. Authorization Request

Claude opens the authorization endpoint in a browser popup:
GET /oauth/authorize
  ?client_id=<CLIENT_ID>
  &redirect_uri=https://claude.ai/api/mcp/auth_callback
  &response_type=code
  &code_challenge=<BASE64URL(SHA256(verifier))>
  &code_challenge_method=S256
  &state=<random-csrf-token>
Validation checks:
  • response_type must be code
  • client_id must match the server’s configured client ID
  • redirect_uri must be in the allowlist
  • code_challenge_method must be S256
  • state is required (CSRF protection)
If any check fails, the server returns a 400 or 401 error.

2. User Authorization

email-connector renders the setup form where you:
  1. Select your email provider
  2. Enter your email address
  3. Enter your app-specific password
The server validates your credentials by opening a live IMAP connection to your email provider. If the connection succeeds, your credentials are valid.

3. Authorization Code

On successful validation:
  1. The server generates a 48-character random authorization code
  2. Stores the code with the associated credentials and PKCE challenge
  3. Redirects to Claude’s callback URL:
https://claude.ai/api/mcp/auth_callback
  ?code=<authorization_code>
  &state=<same-state-from-step-1>
Authorization codes expire after 5 minutes.

4. Token Exchange

Claude exchanges the authorization code for an access token:
POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=<authorization_code>
&client_id=<CLIENT_ID>
&client_secret=<CLIENT_SECRET>
&code_verifier=<original_verifier>
&redirect_uri=https://claude.ai/api/mcp/auth_callback
Server verification:
  1. Validates client_id and client_secret
  2. Computes BASE64URL(SHA256(code_verifier)) and compares it to the stored code_challenge
  3. Verifies redirect_uri matches the original request
  4. If everything checks out, returns an access token

5. Token Response

{
  "access_token": "64-char-hex-token",
  "token_type": "Bearer",
  "expires_in": 2592000,
  "scope": "email:read email:write"
}
The access token is valid for 30 days. Claude stores it and includes it as a Bearer token in all subsequent MCP requests.

Token Revocation

To revoke access:
POST /oauth/revoke
Content-Type: application/json

{
  "token": "<access_token>"
}
Returns 200 OK with {"revoked": true} regardless of whether the token was valid. This prevents token existence probing.

Error Responses

ErrorCause
unsupported_grant_typeOnly authorization_code is supported
invalid_clientWrong client_id or client_secret
invalid_requestMissing code_verifier
invalid_grantCode expired, already used, or PKCE mismatch
All error responses follow RFC 6749 format:
{
  "error": "invalid_grant",
  "error_description": "Authorization code is invalid, expired, or PKCE verification failed."
}