# OAuth 2.1 Authentication Guide
Complete guide for using OAuth 2.1 authentication with MCP Hub.
---
## 📋 Table of Contents
1. [Overview](#overview)
2. [Quick Start](#quick-start)
3. [Configuration](#configuration)
4. [OAuth Flows](#oauth-flows)
5. [Registering OAuth Clients](#registering-oauth-clients)
6. [OpenAI GPT Integration](#openai-gpt-integration)
7. [Claude Custom Connectors](#claude-custom-connectors-remote-mcp)
8. [Testing](#testing)
9. [Security Best Practices](#security-best-practices)
10. [Troubleshooting](#troubleshooting)
---
## Overview
MCP Hub implements **OAuth 2.1** with **API Key-Based Authorization** and **MCP Specification Compliance**:
- ✅ **API Key Authentication** - Users authorize with their existing API Keys
- ✅ **Permission Inheritance** - OAuth tokens inherit API Key's scope and project access
- ✅ **PKCE Mandatory** - Proof Key for Code Exchange (S256)
- ✅ **Refresh Token Rotation** - Security best practice
- ✅ **JWT Access Tokens** - Stateless validation
- ✅ **Multiple Grant Types** - Authorization Code, Refresh Token, Client Credentials
- ✅ **Scope-based Authorization** - Fine-grained access control
- ✅ **Backward Compatible** - API Keys still work
- ✅ **Open DCR for MCP Clients** - Claude/ChatGPT can register automatically (RFC 7591) 🆕
- ✅ **Protected Resource Metadata** - RFC 9728 compliant endpoints 🆕
- ✅ **401 + WWW-Authenticate** - Proper OAuth discovery for MCP clients 🆕
### Security Model (Updated for MCP Compliance)
**🔓 Open DCR for Trusted Clients**: Claude and ChatGPT can automatically register OAuth clients without authentication:
- Redirect URIs must match allowlist (claude.ai, chatgpt.com, localhost)
- Rate limited per IP (10/min, 30/hour)
- All registrations are audit logged
**🔐 Protected DCR for Custom Apps**: Custom applications still require Master API Key for registration.
**🔒 API Key Authorization**: Users MUST provide their API Key when authorizing OAuth clients (required mode).
**🎯 Permission Inheritance**: OAuth tokens automatically inherit the API Key's permissions:
- **Master API Key** → OAuth token with full access
- **Per-project API Key** → OAuth token limited to that project
- **Read-only API Key** → OAuth token with read-only access
**✅ Claude/ChatGPT Integration**: MCP clients automatically discover OAuth endpoints and register themselves.
### Supported Grant Types
1. **Authorization Code** (with PKCE) - For third-party apps
2. **Refresh Token** (with rotation) - Renew access tokens
3. **Client Credentials** - Machine-to-machine auth
---
## Quick Start
### 1. Generate JWT Secret
```bash
# Generate a secure secret key
python -c "import secrets; print(secrets.token_urlsafe(64))"
# OR using openssl
openssl rand -base64 64
```
### 2. Configure Environment
Add to `.env`:
```bash
# Required
OAUTH_JWT_SECRET_KEY=your_generated_secret_key_here
# Optional (defaults shown)
OAUTH_JWT_ALGORITHM=HS256
OAUTH_ACCESS_TOKEN_TTL=3600 # 1 hour
OAUTH_REFRESH_TOKEN_TTL=604800 # 7 days
```
### 3. Rebuild & Deploy
```bash
# Local development
docker-compose up --build -d
# Coolify deployment
# Update environment variables in Coolify UI and redeploy
```
---
## Configuration
### Environment Variables
| Variable | Description | Default | Required |
|----------|-------------|---------|----------|
| `OAUTH_JWT_SECRET_KEY` | Secret key for signing JWTs | - | ✅ Yes |
| `OAUTH_JWT_ALGORITHM` | JWT signing algorithm | `HS256` | No |
| `OAUTH_ACCESS_TOKEN_TTL` | Access token lifetime (seconds) | `3600` (1h) | No |
| `OAUTH_REFRESH_TOKEN_TTL` | Refresh token lifetime (seconds) | `604800` (7d) | No |
| `OAUTH_STORAGE_TYPE` | Storage backend | `json` | No |
| `OAUTH_STORAGE_PATH` | Storage path for JSON files | `/app/data` | No |
### JWT Algorithms
Supported algorithms:
- `HS256` (default) - HMAC with SHA-256
- `HS384` - HMAC with SHA-384
- `HS512` - HMAC with SHA-512
- `RS256` - RSA with SHA-256 (requires RSA keys)
- `RS384` - RSA with SHA-384
- `RS512` - RSA with SHA-512
---
## OAuth Flows
### Authorization Code Flow (with PKCE)
**Use Case**: Third-party applications (like OpenAI GPTs)
```
┌──────────┐ ┌──────────────┐
│ Client │ │ MCP Server │
└────┬─────┘ └──────┬───────┘
│ │
│ 1. Generate PKCE verifier & challenge │
│─────────────────────────────────────────────► │
│ │
│ 2. GET /oauth/authorize? │
│ client_id=xxx& │
│ redirect_uri=https://app.com/callback& │
│ response_type=code& │
│ code_challenge=yyy& │
│ code_challenge_method=S256& │
│ scope=read+write& │
│ state=random_state │
│───────────────────────────────────────────────►│
│ │
│ 3. Authorization Code (5-min expiry) │
│◄───────────────────────────────────────────────│
│ │
│ 4. POST /oauth/token │
│ grant_type=authorization_code& │
│ client_id=xxx& │
│ client_secret=zzz& │
│ code=auth_abc& │
│ redirect_uri=https://app.com/callback& │
│ code_verifier=original_verifier │
│───────────────────────────────────────────────►│
│ │
│ 5. Access Token + Refresh Token │
│◄───────────────────────────────────────────────│
│ │
```
### Refresh Token Flow
**Use Case**: Renewing expired access tokens
```
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&
client_id=cmp_client_xxx&
client_secret=your_secret&
refresh_token=rt_xxx
```
**Response**:
```json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "rt_new_token",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read write"
}
```
**Security**: Old refresh token is immediately revoked (rotation).
### Client Credentials Flow
**Use Case**: Machine-to-machine authentication
```
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&
client_id=cmp_client_xxx&
client_secret=your_secret&
scope=read
```
**Response**:
```json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read"
}
```
**Note**: No refresh token for client credentials.
---
## Registering OAuth Clients
### Two Registration Modes
The `/oauth/register` endpoint supports two authentication modes:
#### 1. Open DCR (No Auth Required) 🆕
For trusted MCP clients (Claude, ChatGPT), registration is automatic:
```bash
# Claude/ChatGPT automatically calls this - no auth needed
curl -X POST https://your-mcp-server.com/oauth/register \
-H "Content-Type: application/json" \
-d '{
"client_name": "Claude MCP Client",
"redirect_uris": ["https://claude.ai/oauth/callback"],
"grant_types": ["authorization_code", "refresh_token"]
}'
```
**Allowed Redirect URI Patterns:**
- `https://claude.ai/*`
- `https://claude.com/*`
- `https://chatgpt.com/*`
- `https://chat.openai.com/*`
- `https://platform.openai.com/*`
- `http://localhost:*/*` (development)
- `http://127.0.0.1:*/*` (development)
**Rate Limits (per IP):**
- 10 requests per minute
- 30 requests per hour
#### 2. Protected DCR (Master API Key Required)
For custom applications with non-allowlisted redirect URIs:
```bash
curl -X POST https://your-mcp-server.com/oauth/register \
-H "Authorization: Bearer YOUR_MASTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"client_name": "My Custom App",
"redirect_uris": ["https://myapp.com/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"scope": "read write"
}'
```
### Security Flow (MCP Compliant)
```
1. MCP Client (Claude) discovers OAuth via /.well-known/oauth-authorization-server
2. MCP Client registers via Open DCR at /oauth/register (no auth for trusted URIs)
3. MCP Client receives client_id + client_secret
4. User is redirected to /oauth/authorize
5. User enters their API Key → Authorization code returned
6. MCP Client exchanges code for tokens at /oauth/token
7. OAuth token inherits user's API Key permissions
```
**Benefits**:
- ✅ Claude/ChatGPT connect with one click (Open DCR)
- ✅ Custom apps still require admin approval
- ✅ Users control their own permissions via API Keys
- ✅ Rate limiting prevents abuse
**Example**:
- User has "read-only" API Key → OAuth token gets "read-only" access
- User has project-specific API Key → OAuth token limited to that project
- User has Master API Key → OAuth token gets full access
### ChatGPT Integration (OAuth Manual Mode)
ChatGPT now supports **OAuth (manual)** integration where you manually configure the OAuth client credentials.
#### ⚠️ Security Considerations
**Current Limitation**: Due to ChatGPT OAuth (manual) design:
- ChatGPT cannot pass user-specific API Keys in authorization URL
- Must use `OAUTH_AUTH_MODE=optional` which allows anyone with the authorization URL to connect
- OAuth tokens issued to ChatGPT get **full access** (no API Key inheritance)
**Security Measures You Can Take**:
1. **Use Minimal Scopes** (Recommended):
- Register ChatGPT client with `scope: "read"` only
- Create separate clients for different access levels
2. **Private Deployment Only**:
- Only share client credentials with trusted users
- Use this integration for personal/team use, not public GPTs
3. **Monitor Usage**:
- Check audit logs regularly: `tail -f logs/audit.log`
- Review OAuth tokens: use `oauth_list_tokens()` tool
4. **Future Enhancement** (Phase E - Planned):
- 🔒 **Custom Authorization Page** (Priority 2)
- Beautiful HTML form for API Key input
- OAUTH_AUTH_MODE=required works with ChatGPT
- Per-user access control
- Multi-language support (EN/FA)
- See `docs/ROADMAP.md` Phase E for details
- IP whitelisting for OAuth endpoints
- Per-client rate limiting
**For Production/Public Use**: Consider using `OAUTH_AUTH_MODE=required` with a custom client that supports API Key parameters, instead of ChatGPT OAuth (manual).
---
#### Step-by-Step Setup:
**1. Register OAuth Client (Admin Only)**
Use MCP tool or API with Master API Key:
```bash
# Using curl with Master API Key
curl -X POST https://your-mcp-server.com/oauth/register \
-H "Authorization: Bearer YOUR_MASTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"client_name": "ChatGPT OAuth Integration",
"redirect_uris": ["https://chatgpt.com/connector_platform_oauth_redirect"],
"grant_types": ["authorization_code", "refresh_token"],
"scope": "read"
}'
```
**Response**: Save the `client_id` and `client_secret` (shown only once!)
**2. Configure ChatGPT**
1. Go to ChatGPT → Settings → Authentication
2. Select **OAuth (manual)**
3. Enter:
- **Client ID**: `cmp_client_xxx` (from step 1)
- **Client Secret**: `secret_xxx` (from step 1)
- **Authorization URL**: `https://your-mcp-server.com/oauth/authorize`
- **Token URL**: `https://your-mcp-server.com/oauth/token`
- **Scope**: `read write`
**3. Configure Environment for ChatGPT**
⚠️ **IMPORTANT SECURITY NOTE**: ChatGPT OAuth (manual) has a limitation:
ChatGPT builds the authorization URL automatically and **does not allow users to add API Key parameters**. Therefore, you must use `optional` mode:
```bash
# In .env file
OAUTH_AUTH_MODE=optional
```
**Security Implications**:
- ⚠️ **Anyone with the URL can authorize** - Client ID/Secret alone don't prevent access
- ⚠️ **OAuth tokens get full access** - No API Key = no permission inheritance
- 🔒 **Mitigation**: Use restricted `scope` when registering the client
**Recommended Scopes for ChatGPT**:
- `read` - Read-only access (safest)
- `read write` - Allow content creation (moderate risk)
- ⚠️ Avoid `admin` scope for public ChatGPT integrations
**4. User Authorization**
When users connect ChatGPT to your MCP server:
1. ChatGPT redirects to authorization endpoint automatically
2. Server validates client_id and redirect_uri
3. User approves the connection
4. OAuth token is issued with the scope defined during client registration
5. Redirects back to ChatGPT - Done!
✅ **Best Practice**: Register separate OAuth clients for different use cases with minimal required scopes
### Using MCP Tools
You can also pre-register clients using MCP tools:
```python
# 1. Register a new OAuth client
result = await oauth_register_client(
client_name="My OpenAI GPT",
redirect_uris="https://chat.openai.com/aip/callback",
grant_types="authorization_code,refresh_token",
allowed_scopes="read,write"
)
# Save these credentials securely!
print(f"Client ID: {result['client_id']}")
print(f"Client Secret: {result['client_secret']}") # Only shown once!
```
### Using Direct API (Admin Required)
⚠️ **Master API Key Required** - Only server administrators can register OAuth clients.
```bash
curl -X POST https://mcp-dev.mcphub.dev/oauth/register \
-H "Authorization: Bearer YOUR_MASTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"client_name": "My Application",
"redirect_uris": ["https://example.com/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"scope": "read write"
}'
```
**Success Response** (201 Created):
```json
{
"client_id": "cmp_client_abc123",
"client_secret": "very_long_secret_string",
"client_id_issued_at": 1234567890,
"client_secret_expires_at": 0,
"client_name": "My Application",
"redirect_uris": ["https://example.com/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"token_endpoint_auth_method": "client_secret_post"
}
```
⚠️ **Important**: Save `client_secret` immediately - it's shown only once!
**Error Response** (401 Unauthorized):
```json
{
"error": "unauthorized",
"error_description": "Master API Key required for OAuth client registration. Add 'Authorization: Bearer YOUR_MASTER_API_KEY' header."
}
```
### List Registered Clients
```python
result = await oauth_list_clients()
for client in result['clients']:
print(f"{client['client_name']}: {client['client_id']}")
```
### Revoke a Client
```python
result = await oauth_revoke_client(
client_id="cmp_client_abc123"
)
```
---
## OpenAI GPT Integration
### Step 1: Register OAuth Client
Use the MCP tool to register:
```python
result = await oauth_register_client(
client_name="OpenAI GPT Integration",
redirect_uris="https://chat.openai.com/aip/callback,https://chatgpt.com/aip/callback",
allowed_scopes="read,write"
)
# Save these!
# Client ID: cmp_client_abc123
# Client Secret: very_long_secret_string
```
### Step 2: Configure GPT Action
In OpenAI GPT editor, add an Action with:
**Authentication Type**: OAuth
**Client ID**: `cmp_client_abc123`
**Client Secret**: `very_long_secret_string`
**Authorization URL**: `https://your-mcp-server.com/oauth/authorize`
**Token URL**: `https://your-mcp-server.com/oauth/token`
**Scope**: `read write`
**Token Exchange Method**: `POST` with Basic auth
### Step 3: Test Integration
1. In GPT conversation, trigger an action
2. OAuth consent flow will start
3. User approves (or auto-approved in MCP context)
4. GPT receives access token
5. GPT can now call MCP tools via OAuth!
---
## Claude Custom Connectors (Remote MCP)
Claude supports **Custom Connectors** for Remote MCP servers, allowing direct integration without SSH tunnels or local setup.
### Requirements
- **Claude Plan**: Pro, Max, Team, or Enterprise
- **MCP Server**: Publicly accessible with HTTPS
- **OAuth**: Automatically handled via Open DCR 🆕
### Step 1: Add Connector in Claude
1. Open Claude (claude.ai or desktop app)
2. Go to **Settings** → **Connectors** (or **Integrations**)
3. Click **Add custom connector**
4. Enter your MCP server URL:
- Full access: `https://your-mcp-server.com/mcp`
- Per-project: `https://your-mcp-server.com/project/{alias}/mcp`
5. Click **Add connector** or **Connect**
### Step 2: Authorize (Automatic Flow) 🆕
Thanks to **Open DCR** and **MCP OAuth Compliance**, the OAuth flow is now automatic:
1. Claude discovers OAuth metadata at `/.well-known/oauth-authorization-server`
2. Claude automatically registers via Open DCR at `/oauth/register`
3. Claude redirects you to the authorization page
4. Enter your API Key
5. Done! Claude now has access to your MCP tools
**No manual client registration required!**
### Alternative: Manual Registration (Optional)
If you prefer to pre-register the OAuth client:
```bash
curl -X POST https://your-mcp-server.com/oauth/register \
-H "Content-Type: application/json" \
-d '{
"client_name": "Claude Custom Connector",
"redirect_uris": ["https://claude.ai/oauth/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"scope": "read write"
}'
```
Note: Authorization header is optional for Claude's redirect URIs (Open DCR).
### Security Considerations
⚠️ **Important Security Notes**:
- **Only add trusted connectors** - Remote MCP servers have access to your Claude conversations
- **Use minimal scopes** - Register clients with only required permissions (`read` for safe exploration)
- **Disable write-actions** for Research feature if using with sensitive data
- **Monitor usage** via audit logs: `get_audit_log` tool
### Recommended Configuration
For **safe exploration** (read-only):
```bash
curl -X POST https://your-mcp-server.com/oauth/register \
-H "Authorization: Bearer YOUR_MASTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"client_name": "Claude (Read-Only)",
"redirect_uris": ["https://claude.ai/api/mcp/auth_callback", "https://claude.com/api/mcp/auth_callback"],
"scope": "read"
}'
```
For **full access** (trusted environments):
```bash
curl -X POST https://your-mcp-server.com/oauth/register \
-H "Authorization: Bearer YOUR_MASTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"client_name": "Claude (Full Access)",
"redirect_uris": ["https://claude.ai/api/mcp/auth_callback", "https://claude.com/api/mcp/auth_callback"],
"scope": "read write admin"
}'
```
### Using Per-Project Endpoints
For better security isolation, connect Claude to project-specific endpoints:
```
https://your-mcp-server.com/project/{alias}/mcp
```
This restricts Claude to tools for that specific project only.
### Troubleshooting Claude Connectors
#### "Configure" button instead of "Connect"
This was fixed in Phase K.1. If you still see this:
- Ensure server is updated to v2.10.0+
- Check that `OAuthRequiredMiddleware` is active
- Verify `/.well-known/oauth-protected-resource` returns 200
#### "Connection failed" or "Error connecting to server"
1. **Check server accessibility**: `curl https://your-server.com/health`
2. **Check OAuth metadata**: `curl https://your-server.com/.well-known/oauth-authorization-server`
3. **Check path-specific metadata**: `curl https://your-server.com/.well-known/oauth-protected-resource/mcp`
4. **Check logs** for errors:
```bash
docker logs your-container | grep -i oauth
```
#### "Unauthorized" during authorization
- Enter a valid API Key on the authorization page
- Check that your API Key has the required scope
#### DCR Rate Limited
If you see rate limit errors:
- Wait 1 minute (per-minute limit: 10)
- Or wait 1 hour (per-hour limit: 30)
- Configure limits: `DCR_RATE_LIMIT_PER_MINUTE` and `DCR_RATE_LIMIT_PER_HOUR`
#### Tools not appearing
- Check endpoint path (should include `/mcp`)
- Verify OAuth scopes match tool requirements
- Review server logs for errors
---
## Testing
### Manual Testing
#### 1. Test Authorization Endpoint
```bash
# Generate PKCE challenge
python -c "
import secrets, hashlib, base64
verifier = secrets.token_urlsafe(64)[:64]
challenge = base64.urlsafe_b64encode(
hashlib.sha256(verifier.encode()).digest()
).decode().rstrip('=')
print(f'Verifier: {verifier}')
print(f'Challenge: {challenge}')
"
# Call authorization endpoint
curl -X GET "http://localhost:8000/oauth/authorize?\
client_id=cmp_client_xxx&\
redirect_uri=http://localhost:3000/callback&\
response_type=code&\
code_challenge=YOUR_CHALLENGE&\
code_challenge_method=S256&\
scope=read+write"
```
#### 2. Test Token Endpoint
```bash
# Exchange authorization code for tokens
curl -X POST http://localhost:8000/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code&\
client_id=cmp_client_xxx&\
client_secret=YOUR_SECRET&\
code=auth_abc123&\
redirect_uri=http://localhost:3000/callback&\
code_verifier=YOUR_VERIFIER"
```
#### 3. Test Access Token
```bash
# Use access token to call MCP tools
curl -X POST http://localhost:8000/tools/wordpress_post_list \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"site": "site1", "status": "publish"}'
```
### Automated Testing
```bash
# Run integration tests
pytest tests/test_oauth_integration.py -v
# Run all OAuth tests
pytest tests/test_oauth*.py -v
```
---
## Security Best Practices
### 1. JWT Secret Key Management
✅ **DO**:
- Use cryptographically secure random keys (64+ characters)
- Store in environment variables, never in code
- Rotate keys periodically
- Use different keys for dev/staging/production
❌ **DON'T**:
- Use weak or predictable secrets
- Commit secrets to version control
- Share secrets between environments
### 2. Client Secrets
✅ **DO**:
- Save client secrets immediately after creation
- Store securely (password manager, secrets vault)
- Rotate if compromised
❌ **DON'T**:
- Log client secrets
- Expose in error messages
- Transmit over insecure channels
### 3. PKCE
✅ **DO**:
- Always use S256 method
- Generate new verifier for each flow
- Validate code_challenge correctly
❌ **DON'T**:
- Reuse code verifiers
- Use plain method (OAuth 2.1 disallows it)
### 4. Token Handling
✅ **DO**:
- Use short-lived access tokens (1 hour)
- Implement refresh token rotation
- Detect and prevent token reuse
- Validate JWT signatures
❌ **DON'T**:
- Store tokens in localStorage (XSS risk)
- Log tokens in production
- Ignore token expiration
### 5. Scope Management
✅ **DO**:
- Grant minimum necessary scopes
- Validate scopes on every request
- Document scope requirements
❌ **DON'T**:
- Grant "admin" scope by default
- Allow scope escalation
---
## Troubleshooting
### ChatGPT OAuth (Manual) Issues
#### 1. "Something went wrong with setting up the connection"
**Common Causes**:
- Wrong redirect URI
- OAUTH_AUTH_MODE is set to `required` (should be `optional` for ChatGPT)
- Client ID/Secret mismatch
**Solution**:
```bash
# 1. Check redirect URI in oauth_clients.json
cat /app/data/oauth_clients.json | grep -A 3 redirect_uris
# Should contain: "https://chatgpt.com/connector_platform_oauth_redirect"
# 2. Verify OAUTH_AUTH_MODE
echo $OAUTH_AUTH_MODE
# Should be: optional
# 3. Check logs for specific error
tail -f logs/audit.log | grep -i oauth
```
#### 2. "API Key is required" error during authorization
**Cause**: `OAUTH_AUTH_MODE=required` but ChatGPT cannot pass API Key
**Solution**:
```bash
# In .env file, change to:
OAUTH_AUTH_MODE=optional
# Then restart/redeploy
```
#### 3. "Invalid redirect_uri" error
**Cause**: Redirect URI mismatch between client registration and ChatGPT request
**Solution**:
```bash
# Register new client with correct URI
curl -X POST https://your-server.com/oauth/register \
-H "Authorization: Bearer YOUR_MASTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"client_name": "ChatGPT OAuth",
"redirect_uris": ["https://chatgpt.com/connector_platform_oauth_redirect"],
"grant_types": ["authorization_code", "refresh_token"],
"scope": "read"
}'
# Update ChatGPT config with new client_id and client_secret
```
#### 4. ChatGPT connection works but has too much access
**Cause**: OAuth client registered with broad scopes (e.g., "read write admin")
**Solution**:
```bash
# Revoke old client
curl -X POST https://your-server.com/tools/oauth_revoke_client \
-H "Authorization: Bearer YOUR_MASTER_API_KEY" \
-d '{"client_id": "cmp_client_old"}'
# Register new client with minimal scope
curl -X POST https://your-server.com/oauth/register \
-H "Authorization: Bearer YOUR_MASTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"client_name": "ChatGPT (Read-Only)",
"redirect_uris": ["https://chatgpt.com/connector_platform_oauth_redirect"],
"scope": "read"
}'
```
---
### Common Issues
#### 1. "Invalid client credentials"
**Cause**: Wrong client_id or client_secret
**Solution**:
```bash
# List registered clients
curl -H "Authorization: Bearer $MASTER_API_KEY" \
http://localhost:8000/tools/oauth_list_clients
# Verify credentials match
```
#### 2. "PKCE validation failed"
**Cause**: Mismatch between code_verifier and code_challenge
**Solution**:
- Ensure code_verifier used in token request matches the original
- Verify code_challenge was generated correctly with S256
#### 3. "Token expired"
**Cause**: Access token expired (default 1 hour)
**Solution**:
```bash
# Use refresh token to get new access token
curl -X POST http://localhost:8000/oauth/token \
-d "grant_type=refresh_token&\
client_id=xxx&\
client_secret=yyy&\
refresh_token=rt_zzz"
```
#### 4. "Insufficient scope"
**Cause**: Access token doesn't have required scope
**Solution**:
- Request correct scopes during authorization
- Check allowed_scopes for the client
- Ensure scope is included in JWT payload
#### 5. "Authorization code already used"
**Cause**: Attempting to reuse authorization code
**Solution**:
- Authorization codes are single-use only
- Start a new authorization flow
- Check for client-side caching issues
### Debug Logging
Enable debug logging:
```bash
# .env
LOG_LEVEL=DEBUG
```
View logs:
```bash
docker-compose logs -f mcp-server | grep -i oauth
```
---
## API Reference
### Endpoints
#### GET /oauth/authorize
Authorization endpoint for OAuth flow.
**Query Parameters**:
- `client_id` (required) - OAuth client ID
- `redirect_uri` (required) - Callback URI
- `response_type` (required) - Must be "code"
- `code_challenge` (required) - PKCE challenge
- `code_challenge_method` (required) - Must be "S256"
- `scope` (optional) - Requested scopes (space-separated)
- `state` (optional) - CSRF protection token
**Response**:
```json
{
"redirect_uri": "http://localhost:3000/callback?code=auth_xxx&state=yyy",
"code": "auth_xxx",
"expires_in": 300
}
```
#### POST /oauth/token
Token endpoint for all OAuth grants.
**Request Body** (application/x-www-form-urlencoded or JSON):
- `grant_type` (required) - "authorization_code" | "refresh_token" | "client_credentials"
- `client_id` (required) - OAuth client ID
- `client_secret` (required) - Client secret
For authorization_code:
- `code` (required) - Authorization code
- `redirect_uri` (required) - Same as /authorize
- `code_verifier` (required) - PKCE verifier
For refresh_token:
- `refresh_token` (required) - Current refresh token
For client_credentials:
- `scope` (optional) - Requested scopes
**Response**:
```json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "rt_xxx",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read write"
}
```
### MCP Tools
#### oauth_register_client
Register a new OAuth client.
#### oauth_list_clients
List all registered OAuth clients.
#### oauth_revoke_client
Revoke (delete) an OAuth client.
---
## Resources
- [OAuth 2.1 Specification](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-10)
- [RFC 7636 - PKCE](https://datatracker.ietf.org/doc/html/rfc7636)
- [JWT Best Practices](https://datatracker.ietf.org/doc/html/rfc8725)
- [OpenAI Actions Documentation](https://platform.openai.com/docs/actions)
---
## Support
For issues or questions:
- GitHub Issues: https://github.com/airano-ir/mcphub/issues
- Documentation: `/docs`
---
**Last Updated**: 2025-12-05
**Version**: v2.10.0 (Phase K.1 - OAuth MCP Compliance, Open DCR, RFC 9728)