OAuth2 Authentication & DCR Guide
This guide explains how to apply OAuth 2.0 authentication to Custom Remote MCP servers. With Dynamic Client Registration (DCR) support, users can complete authentication automatically by simply entering a URL.
Overview
| Question | Answer |
|---|---|
| Does Custom MCP support OAuth2? | ✅ Fully supported. |
| Can each user authenticate individually? | ✅ Yes, tokens are managed per user. |
| Is DCR required? | ❌ No, it’s optional. Without it, users manually enter Client ID/Secret. |
| What are the benefits of DCR? | Automatic client registration greatly improves the user experience. |
OAuth2 Authentication Methods
When you enter the MCP server URL, AIP automatically detects OAuth metadata and operates in one of three modes:
OAuthWithDCR (Automatic Client Registration)
- Condition: MCP server supports DCR specification
- User Action: Enter URL only
- AIP Process: Automatically registers client
- Result: OAuth popup appears automatically
OAuth (Manual Client ID/Secret Entry)
- Condition: MCP server does not support DCR
- User Action: Manually enter Client ID / Secret
- AIP Process: Processes OAuth with the provided credentials
- Result: OAuth popup appears
NoAuth (No Authentication)
- Condition: OAuth metadata discovery does not return usable metadata
- User Action: None
- AIP Process: No OAuth flow is started for this setup
- Result: No OAuth popup
As soon as you enter the MCP server URL, AIP automatically performs OAuth Discovery to determine which authentication method to use.
What is DCR
Dynamic Client Registration (DCR) is a standard protocol defined in RFC 7591 that allows an OAuth2 client (AIP) to automatically register with an Authorization Server and obtain a Client ID and Secret.
Without DCR (Traditional Flow)
- User manually creates an OAuth App on the service.
- Obtains Client ID / Secret.
- Manually enters them in AIP.
- OAuth popup proceeds.
With DCR
- User simply enters the MCP Server URL in AIP.
- AIP automatically registers a client with the server.
- Client ID / Secret obtained automatically.
- OAuth popup proceeds (no user input required).
How DCR Support is Detected
AIP checks whether the Authorization Server Metadata contains a registration_endpoint field:
// Example response from /.well-known/oauth-authorization-server
{
"issuer": "https://mcp.example.com",
"authorization_endpoint": "https://mcp.example.com/oauth/authorize",
"token_endpoint": "https://mcp.example.com/oauth/token",
"registration_endpoint": "https://mcp.example.com/oauth/register" // DCR supported if present
}AIP’s Automatic OAuth Detection Flow
When an MCP server URL is entered, the AIP backend automatically performs the following detection steps:
- Send POST request to MCP server
- 401 response +
WWW-Authenticateheader → Extract Protected Resource Metadata URL - No 401 → Check
/.well-known/oauth-protected-resource
- 401 response +
- Extract
authorization_serversfrom Protected Resource Metadata - Fetch Authorization Server Metadata (ASM) — Priority Order
- RFC 8414:
/.well-known/oauth-authorization-server/{path} - OIDC (path insertion):
/.well-known/openid-configuration/{path} - OIDC (path appending):
/{path}/.well-known/openid-configuration
- RFC 8414:
- Determine authentication method
- ASM fetch fails → NoAuth (metadata fallback)
- ASM has
registration_endpoint→ OAuthWithDCR - ASM has no
registration_endpoint→ OAuth (manual input)
If OAuth metadata cannot be resolved during Discovery, metadata detection falls back to NoAuth and no OAuth popup is shown. DCR runtime failures are handled separately: AIP returns a DCR unsupported error and the UI falls back to manual Client ID / Secret input.
Setup Guide
Connecting a DCR-Supported Server (e.g., Linear)
Enter URL
Go to Integrations → All Integrations → click Custom MCP Integration Setup and enter the MCP Server URL.
Automatic Authentication
AIP automatically performs DCR and an OAuth popup appears. Log in with your service account to complete the integration.
Token Management
Each user authenticates independently. Tokens are managed separately per user.
Connecting a Non-DCR Server (e.g., Salesforce)
Add MCP in AIP
- Go to Integrations → All Integrations → Custom MCP Integration Setup and enter the MCP Server URL.
- Click Install — a Client ID / Secret input dialog appears. The dialog also displays the OAuth Callback URL (with a copy button) and the list of required Scopes.
Create an OAuth App
Create an OAuth App in the MCP server’s admin console:
- Enable OAuth Settings.
- Enter the Callback URL. Copy the OAuth Callback URL from AIP’s Client ID / Secret input dialog and register it.
- Select the required Scopes.
- Note the Client ID and Client Secret.
OAuth Login
- Return to AIP’s Client ID / Secret input dialog and enter the Client ID / Secret from the previous step.
- Log in with your service account via the OAuth popup. Once login is complete, AIP receives authentication tokens from the service and the integration is finalized. For details on the internal processing, see OAuth2 Internal Processing Flow.
For Salesforce Custom Domain environments, AIP automatically requests re-login to prevent cross-org OAuth errors. If the issue persists, try using a separate browser profile.
Connecting Internal Network Servers (Edge Tunnel Required)
If the MCP server runs on an internal network or localhost:
- Start Edge Tunnel using the AIP Desktop CLI.
- Check the “Use Edge Tunnel” option when configuring the Custom MCP.
- The subsequent OAuth Discovery and authentication flow proceeds as usual.
For details, see the Edge Tunnel documentation.
Challenges When DCR is Not Supported
Issues that may arise when integrating MCP servers without DCR support:
- Manual client setup required — Someone configuring the integration must create or register an OAuth app and provide Client ID / Secret.
- Scope misconfiguration — AIP provides scope guidance, but users must manually add scopes to their OAuth App. Missing scopes cause tool call failures.
- Client Secret security — Secrets are directly entered into AIP, increasing operational burden.
- Operational complexity — Re-entry is required when Client ID/Secret expires or is rotated.
- High adoption barrier — Creating an OAuth App is a difficult task for non-technical users.
DCR Implementation Guide (For MCP Server Developers)
To enable DCR support on your MCP server, you need both the two metadata endpoints and the registration_endpoint implementation that the metadata points to.
1. Protected Resource Metadata
GET /.well-known/oauth-protected-resource
Response:
{
"resource": "https://mcp.example.com",
"authorization_servers": ["https://auth.example.com"]
}2. Authorization Server Metadata
The registration_endpoint must be included for AIP to recognize DCR support.
GET /.well-known/oauth-authorization-server
Response:
{
"issuer": "https://auth.example.com",
"authorization_endpoint": "https://auth.example.com/authorize",
"token_endpoint": "https://auth.example.com/token",
"registration_endpoint": "https://auth.example.com/register",
"scopes_supported": ["read", "write"],
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code", "refresh_token"],
"code_challenge_methods_supported": ["S256"],
"token_endpoint_auth_methods_supported": ["client_secret_basic"]
}Without registration_endpoint, AIP automatically falls back to the OAuth (manual input) method.
Including S256 in code_challenge_methods_supported enables AIP to automatically apply PKCE for enhanced security. This is recommended.
3. Client Registration Endpoint
The registration_endpoint is a POST endpoint that AIP calls directly during automatic client registration. It must accept client metadata in RFC 7591 format and return registration results including client_id and client_secret.
POST /oauth/register
Content-Type: application/json
Request:
{
"client_name": "Custom MCP Client of AI Platform",
"redirect_uris": ["https://{aip-domain}/integration/oauth/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"scope": "read write",
"token_endpoint_auth_method": "client_secret_basic"
}
Response (201 Created):
{
"client_id": "aip_123456789",
"client_secret": "replace-with-secure-secret",
"client_id_issued_at": 1712236800,
"client_secret_expires_at": 0,
"redirect_uris": ["https://{aip-domain}/integration/oauth/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"token_endpoint_auth_method": "client_secret_basic"
}Implementation Example (Node.js)
const crypto = require('crypto');
// Protected Resource Metadata
app.get('/.well-known/oauth-protected-resource', (req, res) => {
res.json({
resource: 'https://mcp.example.com',
authorization_servers: ['https://auth.example.com']
});
});
// Authorization Server Metadata
app.get('/.well-known/oauth-authorization-server', (req, res) => {
res.json({
issuer: 'https://auth.example.com',
authorization_endpoint: 'https://auth.example.com/authorize',
token_endpoint: 'https://auth.example.com/token',
registration_endpoint: 'https://auth.example.com/register',
scopes_supported: ['read', 'write', 'admin'],
response_types_supported: ['code'],
code_challenge_methods_supported: ['S256'],
grant_types_supported: ['authorization_code', 'refresh_token'],
token_endpoint_auth_methods_supported: ['client_secret_basic']
});
});
// Client Registration Endpoint
app.post('/oauth/register', (req, res) => {
res.status(201).json({
client_id: `aip_${crypto.randomBytes(16).toString('hex')}`,
client_secret: crypto.randomBytes(32).toString('hex'),
client_id_issued_at: Math.floor(Date.now() / 1000),
client_secret_expires_at: 0,
redirect_uris: req.body.redirect_uris ?? [],
grant_types: req.body.grant_types ?? ['authorization_code', 'refresh_token'],
token_endpoint_auth_method: req.body.token_endpoint_auth_method ?? 'client_secret_basic'
});
});Implementation Example (Python)
from flask import Flask, jsonify, request
import time
import secrets
app = Flask(__name__)
@app.route('/.well-known/oauth-protected-resource')
def oauth_resource_metadata():
return jsonify({
'resource': 'https://mcp.example.com',
'authorization_servers': ['https://auth.example.com']
})
@app.route('/.well-known/oauth-authorization-server')
def oauth_authorization_server():
return jsonify({
'issuer': 'https://auth.example.com',
'authorization_endpoint': 'https://auth.example.com/authorize',
'token_endpoint': 'https://auth.example.com/token',
'registration_endpoint': 'https://auth.example.com/register',
'scopes_supported': ['read', 'write', 'admin'],
'response_types_supported': ['code'],
'code_challenge_methods_supported': ['S256'],
'grant_types_supported': ['authorization_code', 'refresh_token'],
'token_endpoint_auth_methods_supported': ['client_secret_basic']
})
@app.route('/oauth/register', methods=['POST'])
def oauth_register():
payload = request.get_json(silent=True) or {}
return jsonify({
'client_id': f'aip_{secrets.token_hex(16)}',
'client_secret': secrets.token_hex(32),
'client_id_issued_at': int(time.time()),
'client_secret_expires_at': 0,
'redirect_uris': payload.get('redirect_uris', []),
'grant_types': payload.get('grant_types', ['authorization_code', 'refresh_token']),
'token_endpoint_auth_method': payload.get('token_endpoint_auth_method', 'client_secret_basic')
}), 201These examples are minimal implementations for documentation purposes. In production, you should persist registered clients, validate allowed redirect URIs, and implement client secret protection policies.
Troubleshooting
OAuth Popup Does Not Appear
- Verify OAuth metadata discovery works correctly.
If PRM returns
curl https://mcp.example.com/.well-known/oauth-protected-resourceauthorization_servers, verify the referenced Authorization Server Metadata is reachable as well. - Confirm AIP can reach the MCP server URL over HTTP (check firewalls).
- For internal network servers, check the “Use Edge Tunnel” option.
- Verify the MCP Server URL is correct (e.g.,
https://host/sse). - Confirm the MCP server supports standard OAuth2 Authorization Code Flow.
Authentication Failure
- Verify Client ID / Secret are correct.
- Add AIP’s OAuth callback URL to the OAuth app’s redirect URI whitelist.
- Check server logs for OAuth endpoint error messages.
Per-User Authentication Not Working
- Log in with a different user account.
- Verify the MCP server issues different tokens per user.