Skip to content

fix(OAuth): honor token_endpoint_auth_method in OAuth token exchange#4717

Open
bogdanmariusc10 wants to merge 3 commits into
mainfrom
4706-bug-authorization-code-token-exchange-ignores-token_endpoint_auth_method-breaking-dcr-with-strict-oauth-21-providers-eg-datadog
Open

fix(OAuth): honor token_endpoint_auth_method in OAuth token exchange#4717
bogdanmariusc10 wants to merge 3 commits into
mainfrom
4706-bug-authorization-code-token-exchange-ignores-token_endpoint_auth_method-breaking-dcr-with-strict-oauth-21-providers-eg-datadog

Conversation

@bogdanmariusc10
Copy link
Copy Markdown
Collaborator

🔗 Related Issue

Closes #4706


📝 Summary

This PR fixes a critical OAuth 2.1 compatibility issue where ContextForge ignored the token_endpoint_auth_method setting during authorization code token exchange, causing failures with strict OAuth providers like Datadog.

Problem: When DCR registers a client and the authorization server defaults to token_endpoint_auth_method: "client_secret_basic" (RFC 7591 §2 default), the subsequent token exchange always sent credentials in the POST body (client_secret_post), resulting in 400 invalid_client errors from strict OAuth 2.1 providers.

Solution:

  • Updated exchange_code_for_token() to read and honor token_endpoint_auth_method from credentials
  • Added logic to propagate token_endpoint_auth_method from DCR-registered clients to the OAuth config
  • Implemented proper HTTP Basic Authentication when client_secret_basic is specified
  • Added fallback handling for public clients (Basic Auth requested but no secret available)

Impact: Enables ContextForge to work with strict OAuth 2.1 providers (Datadog, and others) that enforce the registered authentication method.


🏷️ Type of Change

  • Bug fix
  • Feature / Enhancement
  • Documentation
  • Refactor
  • Chore (deps, CI, tooling)
  • Other (describe below)

🧪 Verification

Check Command Status
Lint suite make lint ✅ Pass
Unit tests make test ✅ Pass
Coverage ≥ 80% make coverage ✅ Pass

✅ Checklist

  • Code formatted (make black isort pre-commit)
  • Tests added/updated for changes
  • Documentation updated (if applicable)
  • No secrets or credentials committed

📓 Notes

Technical Details

Files Modified:

  1. mcpgateway/services/oauth_manager.py (lines 639-665)

    • Added token_endpoint_auth_method detection from runtime credentials
    • Implemented conditional authentication: Basic Auth header vs POST body
    • Added graceful fallback for public clients
  2. mcpgateway/routers/oauth_router.py (line 447)

    • Propagate token_endpoint_auth_method from DCR registered_client to oauth_config
    • Ensures the setting persists across OAuth flow stages
  3. Test Updates:

    • Fixed 2 DCR tests to include token_endpoint_auth_method attribute
    • Added new test for Basic Auth fallback scenario (public client)
    • Achieved >95% diff coverage

Already Working Correctly

  • _exchange_code_for_tokens() (PKCE path) - already honored the setting
  • refresh_token() - already honored the setting
  • DCR registration - already sends and stores the setting

Why Other Providers Didn't Fail

Auth0, Okta, Google, Microsoft are lenient per RFC 6749 §2.3.1 and accept either authentication method. Datadog and other strict OAuth 2.1 servers enforce the registered method, exposing this bug.

Testing Against Datadog

To verify the fix works with Datadog MCP server:

  1. Configure gateway with issuer: "https://mcp.datadoghq.com"
  2. Enable DCR auto-registration
  3. Trigger OAuth flow - DCR will register with client_secret_basic
  4. Token exchange will now correctly use HTTP Basic Authentication
  5. Flow completes successfully (previously failed with 400 invalid_client)

Fixes #4706

When DCR registers a client with token_endpoint_auth_method set to
'client_secret_basic' (RFC 7591 default), the token exchange now
correctly uses HTTP Basic Authentication instead of always sending
credentials in the POST body.

Changes:
- oauth_manager.py: Updated exchange_code_for_token() to read and honor
  token_endpoint_auth_method from credentials
- oauth_router.py: Propagate token_endpoint_auth_method from DCR
  registered client to oauth_config
- Added test coverage for Basic Auth fallback when client_secret missing
- Updated DCR tests to include token_endpoint_auth_method attribute

This ensures compatibility with strict OAuth 2.1 providers like Datadog
that enforce the registered authentication method.

Signed-off-by: Bogdan-Marius-Catanus <bogdan-marius.catanus@ibm.com>
@bogdanmariusc10 bogdanmariusc10 added bug Something isn't working SHOULD P2: Important but not vital; high-value items that are not crucial for the immediate release labels May 12, 2026
@bogdanmariusc10 bogdanmariusc10 added the api REST API Related item label May 12, 2026
Bogdan-Marius-Catanus added 2 commits May 12, 2026 13:06
Signed-off-by: Bogdan-Marius-Catanus <bogdan-marius.catanus@ibm.com>
Signed-off-by: Bogdan-Marius-Catanus <bogdan-marius.catanus@ibm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api REST API Related item bug Something isn't working SHOULD P2: Important but not vital; high-value items that are not crucial for the immediate release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: Authorization-code token exchange ignores token_endpoint_auth_method, breaking DCR with strict OAuth 2.1 providers (e.g. Datadog)

1 participant