Summary
The OAuth token audience validation added in PR #3941 fails for real-world OAuth providers (Salesforce, Azure AD, etc.) because:
The resource field in oauth_config is not exposed in the Admin UI
The fallback behavior uses the full gateway.url (including path) as the expected audience
Most OAuth providers issue tokens with audiences at the origin level, not the full endpoint path
This causes legitimate OAuth flows to fail with "Token audience mismatch" errors that users cannot fix via the UI.
Severity : HIGH - Regression bug that breaks OAuth functionality for common enterprise IdPs
Root Cause Analysis
Timeline
March 20, 2026 : Documentation (oauth-design.md:131) explicitly documented as "Known Gap" that audience/scope validation did not exist
April 6, 2026 : PR Add OAuth token claim validation before MCP server forwarding #3941 added token validation to fix security bug [BUG][AUTH]: OAuth OBO flow missing token audience and scope validation before MCP server call #3563
Current state : Validation exists but has implementation flaws that break real OAuth flows
Cause → Effect Chain
CAUSE 1: PR #3941 added audience validation
↓
EFFECT 1: Code now validates token aud claim against expected audience
↓
CAUSE 2: Expected audience falls back to gateway.url when resource not configured
↓ (token_validation_service.py:155)
| expected_audience = oauth_config.get("resource") or gateway_url
↓
CAUSE 3: resource field is NOT exposed in Admin UI
↓ (admin.html:5689-5967 - OAuth form has no oauth_resource field)
↓
EFFECT 2: All OAuth configurations use fallback behavior
↓
CAUSE 4: gateway.url contains full endpoint path
↓ Example: "https://api.salesforce.com/platform/mcp/v1/platform/sobject-all"
↓
EFFECT 3: Expected audience is overly specific
↓
CAUSE 5: Real OAuth providers issue tokens with origin-level audiences
↓ Example token aud: "https://api.salesforce.com"
↓
EFFECT 4: Audience mismatch → blocking error
↓ (gateway_service.py:1598-1601)
| blocking = token_validation.blocking_errors
| if blocking:
| raise GatewayConnectionError(...)
↓
FINAL EFFECT: OAuth authorization succeeds but tool fetch fails
✗ Users see: "Refusing to forward OAuth token... Token audience mismatch"
✗ Error message says to fix oauth_config but UI doesn't expose the field
✗ Users must resort to API calls or direct DB updates
Affected Code Locations
1. Token Validation (The Check)
File : mcpgateway/services/token_validation_service.py:155
expected_audience = oauth_config .get ("resource" ) or gateway_url
✅ Correctly checks for resource field
❌ Fallback to gateway_url uses full path instead of origin
2. Gateway Service (The Block)
File : mcpgateway/services/gateway_service.py:1586-1601
token_validation = validate_oauth_token_claims (...)
blocking = token_validation .blocking_errors
if blocking :
raise GatewayConnectionError (f"Refusing to forward OAuth token..." )
✅ Validation happens before forwarding token
❌ Blocks legitimate tokens due to overly specific audience expectation
3. Admin UI Form (The Gap)
File : mcpgateway/templates/admin.html:5689-5967
OAuth form fields exposed: grant_type, issuer, client_id, client_secret, username, password, token_url, authorization_url, scopes
❌ MISSING : oauth_resource field
4. Backend Form Handler (The Gap)
File : mcpgateway/admin.py:12070-12090
Form processing reads: oauth_grant_type, oauth_issuer, oauth_client_id, etc.
❌ MISSING : oauth_resource extraction from form
5. URL Normalization (Insufficient)
File : mcpgateway/routers/oauth_router.py:_normalize_resource_url()
normalized = urlunparse ((parsed .scheme , parsed .netloc , parsed .path , ...))
Strips query/fragment but preserves path
❌ Does not extract origin when used as fallback
Steps to Reproduce
Prerequisites
ContextForge instance with Admin UI enabled
OAuth provider (Salesforce, Azure AD, Keycloak, etc.)
Reproduction Steps
Register an MCP server gateway with OAuth via Admin UI :
Name: "Salesforce Hosted v2"
URL: https://api.salesforce.com/platform/mcp/v1/platform/sobject-all
Auth Type: OAuth 2.0
Configure OAuth fields:
Grant Type: Authorization Code
Issuer: https://login.salesforce.com
Authorization URL: https://login.salesforce.com/services/oauth2/authorize
Token URL: https://login.salesforce.com/services/oauth2/token
Client ID: <your-client-id>
Client Secret: <your-client-secret>
Scopes: api refresh_token
Note : No "OAuth Resource" field exists in UI
Complete OAuth authorization :
Click "Authorize" on the gateway
Authenticate with Salesforce
OAuth flow succeeds, tokens stored
Attempt to fetch tools :
Click "Fetch Tools"
Observe : Request fails with error
Actual Behavior
Error message :
❌ Failed to Fetch Tools
Error: Failed to fetch tools: Failed to fetch tools after OAuth: Refusing to forward OAuth token for gateway 'Salesforce Hosted v2': Token audience mismatch: token aud=[https://orchestrate-agentforce-dev-ed.develop.my.salesforce.com, https://api.salesforce.com], expected 'https://api.salesforce.com/platform/mcp/v1/platform/sobject-all'. Fix oauth_config (resource/scopes/issuer) or the IdP token request.
Why it fails :
Token audience: ["https://orchestrate-agentforce-dev-ed.develop.my.salesforce.com", "https://api.salesforce.com"]
Expected audience: "https://api.salesforce.com/platform/mcp/v1/platform/sobject-all" (full gateway URL)
No match → blocking error
User cannot fix : Error says to "fix oauth_config (resource/...)" but UI doesn't expose this field
Expected Behavior
Option A : Admin UI should expose "OAuth Resource" field
Users can explicitly configure: https://api.salesforce.com
Validation would succeed: https://api.salesforce.com ∈ token aud list
Option B : Fallback should extract origin from gateway URL
Auto-derived resource: https://api.salesforce.com (not the full path)
Validation would succeed without manual configuration
Option C : Validation should be advisory, not blocking
Log warnings but allow forwarding token to MCP server
Let upstream server be authoritative (original design per docs)
Impact Assessment
Affected Users
✅ Works : Test environments where token aud accidentally matches full gateway URL
❌ Broken : Production OAuth with Salesforce, Azure AD, Google, Okta, Keycloak
❌ Broken : Any OAuth provider issuing origin-level audiences (industry standard)
Workarounds
Workaround 1: API Update (requires technical expertise)
curl -X PATCH " http://localhost:4444/admin/gateways/{GATEWAY_ID}" \
-H " Authorization: Bearer TOKEN" \
-H " Content-Type: application/json" \
-d ' {"oauth_config": {..., "resource": "https://api.salesforce.com"}}'
Workaround 2: Direct DB Update (requires DB access)
UPDATE gateways
SET oauth_config = json_set(oauth_config, ' $.resource' , ' https://api.salesforce.com' )
WHERE name = ' Salesforce Hosted v2' ;
Problems with workarounds :
Require technical expertise beyond typical admin users
Not discoverable (error message doesn't mention API/DB workaround)
Poor UX - error says "fix oauth_config" but UI doesn't allow it
Proposed Solution
Option 1: Add OAuth Resource Field to UI (Recommended)
Changes needed :
Frontend : mcpgateway/templates/admin.html (3 locations)
Add new form field after "Scopes" field
Backend : mcpgateway/admin.py:12070-12090
Extract oauth_resource from form
Validation Fallback : mcpgateway/services/token_validation_service.py:155
Change fallback to extract origin instead of using full path
Pros :
✅ Users can explicitly configure resource
✅ Fallback behavior improved for auto-configuration
✅ Backward compatible (existing configs keep working)
✅ Aligns with OAuth best practices (RFC 8707)
Option 2: Hybrid Approach (Best Balance)
Combine explicit configuration + improved fallback + smart blocking:
Add UI field for explicit configuration
Improve fallback to use origin extraction
Soften validation : Only block if resource was explicitly configured and mismatched
Pros :
✅ Best UX - explicit configs get fail-fast, auto-configs are permissive
✅ Maintains security for intentional configurations
✅ Doesn't break auto-configurations with imperfect fallback
✅ Provides diagnostic value without being draconian
Testing Requirements
Before Merge: Required Tests
1. Unit Tests (tests/unit/mcpgateway/services/test_token_validation_service.py)
2. Integration Tests (tests/e2e/test_oauth_audience_validation.py)
3. Admin UI Tests (tests/playwright/test_oauth_ui.py)
4. Regression Tests
5. Manual Testing Checklist
Documentation Updates Required
1. Update docs/docs/architecture/oauth-design.md
Remove outdated "Known Gap" section (line 131)
Add new "Token Claim Validation" section
2. Create docs/docs/manage/oauth-resource-configuration.md
New guide explaining OAuth resource parameter (RFC 8707)
When to configure explicitly vs auto-derivation
Common patterns for different providers
3. Update docs/docs/manage/oauth-troubleshooting.md
Add "Token audience mismatch" error section with diagnosis and fixes
Related Issues & PRs
Acceptance Criteria
Functional
Code Quality
Documentation
UX
References
Summary
The OAuth token audience validation added in PR #3941 fails for real-world OAuth providers (Salesforce, Azure AD, etc.) because:
resourcefield inoauth_configis not exposed in the Admin UIgateway.url(including path) as the expected audienceThis causes legitimate OAuth flows to fail with "Token audience mismatch" errors that users cannot fix via the UI.
Severity: HIGH - Regression bug that breaks OAuth functionality for common enterprise IdPs
Root Cause Analysis
Timeline
oauth-design.md:131) explicitly documented as "Known Gap" that audience/scope validation did not existCause → Effect Chain
Affected Code Locations
1. Token Validation (The Check)
File:
mcpgateway/services/token_validation_service.py:1552. Gateway Service (The Block)
File:
mcpgateway/services/gateway_service.py:1586-16013. Admin UI Form (The Gap)
File:
mcpgateway/templates/admin.html:5689-59674. Backend Form Handler (The Gap)
File:
mcpgateway/admin.py:12070-120905. URL Normalization (Insufficient)
File:
mcpgateway/routers/oauth_router.py:_normalize_resource_url()Steps to Reproduce
Prerequisites
Reproduction Steps
Register an MCP server gateway with OAuth via Admin UI:
https://api.salesforce.com/platform/mcp/v1/platform/sobject-allhttps://login.salesforce.comhttps://login.salesforce.com/services/oauth2/authorizehttps://login.salesforce.com/services/oauth2/token<your-client-id><your-client-secret>api refresh_tokenComplete OAuth authorization:
Attempt to fetch tools:
Actual Behavior
Error message:
Why it fails:
["https://orchestrate-agentforce-dev-ed.develop.my.salesforce.com", "https://api.salesforce.com"]"https://api.salesforce.com/platform/mcp/v1/platform/sobject-all"(full gateway URL)User cannot fix: Error says to "fix oauth_config (resource/...)" but UI doesn't expose this field
Expected Behavior
Option A: Admin UI should expose "OAuth Resource" field
https://api.salesforce.comhttps://api.salesforce.com∈ token aud listOption B: Fallback should extract origin from gateway URL
https://api.salesforce.com(not the full path)Option C: Validation should be advisory, not blocking
Impact Assessment
Affected Users
Workarounds
Workaround 1: API Update (requires technical expertise)
Workaround 2: Direct DB Update (requires DB access)
Problems with workarounds:
Proposed Solution
Option 1: Add OAuth Resource Field to UI (Recommended)
Changes needed:
Frontend:
mcpgateway/templates/admin.html(3 locations)Backend:
mcpgateway/admin.py:12070-12090Validation Fallback:
mcpgateway/services/token_validation_service.py:155Pros:
Option 2: Hybrid Approach (Best Balance)
Combine explicit configuration + improved fallback + smart blocking:
Pros:
Testing Requirements
Before Merge: Required Tests
1. Unit Tests (
tests/unit/mcpgateway/services/test_token_validation_service.py)2. Integration Tests (
tests/e2e/test_oauth_audience_validation.py)3. Admin UI Tests (
tests/playwright/test_oauth_ui.py)4. Regression Tests
5. Manual Testing Checklist
Documentation Updates Required
1. Update
docs/docs/architecture/oauth-design.md2. Create
docs/docs/manage/oauth-resource-configuration.md3. Update
docs/docs/manage/oauth-troubleshooting.mdRelated Issues & PRs
Acceptance Criteria
Functional
Code Quality
Documentation
UX
References