MCP OAuth DCR: client_secret_post is incorrectly sent as HTTP Basic

Open 💬 0 comments Opened Aug 26, 2026 by marcelomalcher

What issue are you seeing?

Description

When authenticating an MCP server using OAuth Dynamic Client Registration (DCR), Codex does not honor the token_endpoint_auth_method returned by the authorization server.

If the DCR response specifies:

{
  "client_id": "<redacted>",
  "client_secret": "<redacted>",
  "token_endpoint_auth_method": "client_secret_post"
}

Codex sends the client credentials using an HTTP Authorization: Basic ... header. It also omits client_id and client_secret from the token request body.

For client_secret_post, the credentials should instead be included as form parameters in the token request body.

The authorization-code flow and local callback complete successfully, but the subsequent token exchange fails with:

Error: failed to handle OAuth callback
Caused by:
OAuth token exchange failed: Server returned error response:
invalid_request: Missing required parameters

The same MCP server authenticates successfully with Claude and LibreChat using OAuth 2.0.

Steps to reproduce

  1. Configure an MCP server whose OAuth authorization server supports Dynamic Client Registration.
  2. Have the DCR endpoint return a client registration containing:
  • client_id
  • client_secret
  • token_endpoint_auth_method: client_secret_post
  1. Run:

``shell
codex mcp login <server-name> --oauth-client-registration dcr
``

  1. Complete authorization in the browser.
  2. The browser reports that authorization was completed.
  3. Inspect the request sent by Codex to the token endpoint.

Actual behavior

Codex sends a request equivalent to:

POST /token
Authorization: Basic <redacted>
Content-Type: application/x-www-form-urlencoded

With a body similar to:

grant_type=authorization_code
&code=<redacted>
&redirect_uri=http://127.0.0.1:<port>/callback/<id>
&code_verifier=<redacted>
&resource=<mcp-resource>

The body does not contain client_id or client_secret.

The authorization server rejects the request because it expects client credentials in the form body, as specified by client_secret_post.

Expected behavior

When the DCR response specifies:

token_endpoint_auth_method=client_secret_post

Codex should send the token request without HTTP Basic client authentication and include the credentials in the form body:

grant_type=authorization_code
&code=<redacted>
&redirect_uri=<redirect-uri>
&code_verifier=<redacted>
&client_id=<client-id>
&client_secret=<client-secret>
&resource=<mcp-resource>

Controlled reproduction

I reproduced the behavior with a controlled OAuth server that captures the token request:

  • When the DCR response returns client_secret_post, Codex sends the credentials using HTTP Basic.
  • When only the returned method is changed to client_secret_basic, Codex sends the same HTTP Basic authentication and the exchange succeeds.

This suggests that Codex currently treats client_secret_post as client_secret_basic, rather than changing how the client credentials are encoded.

Additional context

The DCR request generated by Codex asks for:

{
  "token_endpoint_auth_method": "none"
}

However, the authorization server registers the client with a secret and returns:

{
  "token_endpoint_auth_method": "client_secret_post"
}

Codex appears to recognize that client authentication is required, but uses HTTP Basic instead of the authentication method returned in the DCR response.

The issue was initially observed with an InHire MCP server. The same server and user account work with Claude and LibreChat.

Related issues:

  • #40783
  • #35006

Environment

  • ChatGPT desktop app: 26.820.60940
  • Bundled Codex CLI: 0.150.0-alpha.8
  • OS: macOS 26.6.2 (25G83)
  • Architecture: Apple Silicon (arm64)

What steps can reproduce the bug?

  1. Configure an MCP server that uses OAuth 2.0 with Dynamic Client Registration (DCR).
  1. Configure the DCR endpoint to return:

``json
{
"client_id": "<client-id>",
"client_secret": "<client-secret>",
"token_endpoint_auth_method": "client_secret_post"
}
``

  1. Register the MCP server in Codex and run:

``shell
codex mcp login <server-name> --oauth-client-registration dcr
``

  1. Complete the authorization flow in the browser. The browser displays Authorization completed.
  1. Inspect the request sent by Codex to the OAuth token endpoint.
  1. Observe that Codex sends the client credentials through an Authorization: Basic <redacted> header and does not include client_id or client_secret in the form body.
  1. The token endpoint rejects the request with:

``text
invalid_request: Missing required parameters
``

The bug can also be isolated by changing only the DCR response from client_secret_post to client_secret_basic. Codex sends HTTP Basic authentication in both cases, but the exchange succeeds only for client_secret_basic.

What is the expected behavior?

_No response_

Additional information

_No response_

View original on GitHub ↗