Skip to content

Supabase MCP repeatedly requires reauthentication: OAuth token refresh failed during initialize #13852

Open

Description

@markussmueller

What version of Codex CLI is running?

codex-cli 0.111.0

What subscription do you have?

Unknown

Which model were you using?

Unknown

What platform is your computer?

Darwin 25.3.0 arm64 arm

What terminal emulator and version are you using (if applicable)?

Ghostty

What issue are you seeing?

My Supabase MCP integration seems to require reauthentication repeatedly.

After previously authenticating Supabase MCP, Codex sometimes starts with this error instead of refreshing the existing auth session:

⚠ MCP client for `supabase` failed to start: MCP startup failed: handshaking with MCP server
  failed: Send message error Transport
  [rmcp::transport::worker::WorkerTransport<rmcp::transport::streamable_http_client::StreamableHttp
  ClientWorker<rmcp::transport::auth::AuthClient<reqwest::async_impl::client::Client>>>] error:
  Auth error: OAuth token refresh failed: Failed to parse server response, when send initialize
  request

⚠ MCP startup incomplete (failed: supabase)

The practical result is that I have to authenticate Supabase again and again, even though the expected behavior seems to be token refresh or stable session reuse.

What steps can reproduce the bug?

  1. Configure the Supabase MCP server in Codex CLI and authenticate it successfully.
  2. Use Codex normally for some time, or return in a later session after the auth/token has aged.
  3. Start Codex again.
  4. Observe that Supabase MCP sometimes fails during startup with the refresh/initialize error above.
  5. Reauthenticate Supabase MCP to get it working again, until the cycle repeats.

I have not pinned down a minimal deterministic repro beyond the repeated pattern above.

What is the expected behavior?

If the stored auth session is still refreshable, Codex should refresh it successfully and start the Supabase MCP server without manual intervention.

If the auth session is invalid, Codex should report that clearly rather than failing during MCP initialize with a parse error.

Additional information

This looks related to the broader MCP OAuth / handshake issues that have been reported before, but I could not find an existing issue with this exact Supabase error string.

Potentially related reports:

The key detail here is the combination of:

  • Supabase MCP
  • repeated reauthentication requirement
  • OAuth token refresh failed
  • Failed to parse server response
  • failure while sending the MCP initialize request

If maintainers want, I can provide more environment details or try with additional logging enabled.

Activity

  1. added
    bugSomething isn't working
    CLIIssues related to the Codex CLI
    mcpIssues related to the use of model context protocol (MCP) servers
    authIssues related to authentication and accounts
    on Mar 7, 2026
  2. github-actions commented on Mar 7, 2026

    @github-actions
    Contributor
  3. markussmueller commented on Mar 7, 2026

    @markussmueller
    Author

    I reviewed the bot suggestions and I don't think either is a true duplicate:

    This issue is specifically about Supabase MCP auth refresh failing during startup:

    Auth error: OAuth token refresh failed: Failed to parse server response, when send initialize request

    The distinctive behavior here is that Supabase appears to require repeated manual reauthentication instead of refreshing the stored auth session.

    So there may be some shared initialize/handshake surface area, but I don't think this should be closed as a duplicate of either suggested issue.

  4. markussmueller commented on Mar 7, 2026

    @markussmueller
    Author

    Additional data point: I previously contacted Supabase support about this, and they indicated they believe this is on the Codex side rather than the Supabase side.

    They specifically pointed me to #6020 as a related Codex MCP startup/handshake issue affecting other MCP servers as well.

    I still don't think this issue is a strict duplicate of #6020, because the observable failure here is specifically:

    Auth error: OAuth token refresh failed: Failed to parse server response, when send initialize request

    and the user-facing behavior is repeated manual reauthentication for Supabase.

    But this does seem like more evidence that the root cause may live in the Codex MCP client / rmcp auth+initialize path rather than in Supabase alone.

  5. thedaviddias commented on Mar 9, 2026

    @thedaviddias

    Faced the issue today where:

    • /mcp shows that Supabase MCP is enabled
    • but Codex says "OAuth token refresh failed: Failed to parse server response"
    • restarting, enabling/disabling the supabase MCP in the settings didn't trigger the auth window

    Compared to other tools like Claude Code, the experience is really not great. Codex should trigger opening the auth page if the token needs to be refreshed.

  6. gabrieuz commented on Mar 11, 2026

    @gabrieuz

    codex mcp login supabase solve the problem to me.

  7. venkat0304 commented on May 9, 2026

    @venkat0304

    I am running below command every other day to authenticate with supabase. But, on claude code i connected like a 2 months back and its still working. Wondering how to make the connection work without breaking.

    codex mcp login supabase

    ID 019e0e56-91e1-7932-ab6c-2953ce75cee6

  8. alexgshaw commented on May 17, 2026

    @alexgshaw

    Also running into this issue

  9. jmo-sg commented on May 20, 2026

    @jmo-sg

    This issue affects me and I use both Codex and Claude. I often have to restart Codex after manual reauthentication which is a real time waster. Claude does not suffer this issue.

  10. Starvingg commented on May 24, 2026

    @Starvingg

    Any update on this issue? The MCP Server connection is buggy. Sometimes it works if explicitly asked. But if Codex gives me a plan with Supabase as a consideration, it should run the Migration file that was created.

  11. 1 remaining item

  12. zeevenn commented on Jul 16, 2026

    @zeevenn

    some issue

  13. mvjpalsson commented on Jul 24, 2026

    @mvjpalsson

    Same issue. Claude doesnt' have this issue, only Codex/ChatGPT in my experience.

  14. hemao612 commented on Jul 27, 2026

    @hemao612

    Same issue. Claude doesnt' have this issue, only Codex/ChatGPT in my experience.

  15. StillNotYet commented on Jul 28, 2026

    @StillNotYet

    Confirmed still reproducible in Codex Desktop on macOS 26.5.2 arm64 with the bundled codex-cli 0.146.0-alpha.3.1.

    I reproduced this through the app-server MCP status path after the stored Supabase OAuth token had expired. The relevant logs are:

    MCP OAuth refresh failed; reauthorization required by RMCP compatibility policy
    OAuth token refresh failed: Failed to parse server response
    failed to refresh OAuth tokens for server supabase
    refresh_reason: expiry
    

    The resulting Supabase MCP status had authStatus oAuth, with no serverInfo and no tools loaded.

    The remote Supabase MCP is project-scoped and configured with read_only=true. No new login was initiated during this diagnostic. The stored OAuth credentials were found and a refresh was attempted, but the refresh response failed to parse. This indicates that the issue persists beyond 0.111.0 and is not simply caused by credentials failing to persist locally.

  16. m13v commented on Jul 28, 2026

    @m13v

    the 'just reauth on refresh failure' path is where a retryable error goes quiet. Failed to parse server response during initialize is a transport/bad-body problem, not proof the session is invalid, but if refresh treats any failure as auth-dead it drops a still-refreshable token and surfaces 'reauthenticate' as the handled state. so the loud retryable case gets laundered into the quiet 'session expired' one and you can't tell which actually happened. logging the refresh http status separately from the parse step, before deciding to drop the token, is what keeps the two apart.

  17. azolotov commented on Jul 30, 2026

    @azolotov

    Additional data point from July 30, 2026: this is still reproducible with codex-cli 0.146.0 on Darwin 25.5.0 arm64, and in my case reauthentication did not restore the MCP even for a fresh startup.

    I tested a custom MCP server protected by Supabase OAuth 2.1:

    1. Ran codex mcp logout <server>.
    2. Ran codex mcp login <server> and completed the browser flow successfully.
    3. Confirmed that the Codex MCP Credentials Keychain item was updated.
    4. Started a fresh Codex session four seconds later.

    The startup logs show that Codex successfully loaded the newly updated credential:

    keyring.load success, service=Codex MCP Credentials
    

    It then immediately failed:

    failed to refresh OAuth tokens for server <server>:
    OAuth token refresh failed: Failed to parse server response
    

    The MCP request subsequently returned 401 with No authorization provided, and Codex omitted the server entirely—no tools were loaded. The message is presented as a startup warning, but the MCP is actually unavailable.

    I also confirmed that both the protected-resource metadata and Supabase authorization-server metadata endpoints return HTTP 200 with valid JSON. Discovery succeeds and advertises the standard Supabase /auth/v1/oauth/token endpoint with refresh_token support.

    So this does not appear to be only an aged or missing credential: a newly issued credential is loaded successfully, then immediately enters the refresh path and fails to parse the response. Repeating logout / login does not resolve it.

  18. m13v commented on Sep 2, 2026

    @m13v

    the tell is a brand-new token going straight to refresh on startup instead of being used once. that's why logout/login can't fix it: the fresh credential still passes through the same parse step that drops it, so reauth just re-enters the same failure and reports it as a soft startup warning.

  19. Cypherlibe commented on Sep 9, 2026

    @Cypherlibe

    Confirmed on Codex CLI 0.153.4, installed through Homebrew on macOS.

    User-observed behavior

    • Two project-scoped hosted Supabase MCP servers authenticated with OAuth.
    • Both repeatedly require manual codex mcp login, approximately daily. Login restores access temporarily.
    • Multiple Codex terminal sessions are used; concurrency has not been established as the cause.
    • Pi also connects to Supabase through OAuth and does not exhibit this recurring failure. This is a client comparison, not proof that both clients share credentials or identical refresh conditions.
    • A launcher-managed CODEX_HOME was introduced only recently; the recurring problem predates that change.

    Diagnostic reproduction

    Started codex app-server --stdio with:

    RUST_LOG=codex_rmcp_client=debug,codex_core::mcp_connection_manager=debug
    

    The two project-scoped server URLs were supplied as process-local configuration overrides. After initialize, requested mcpServerStatus/list, without a model turn or database tool call.

    For both servers, the safely filtered logs contained:

    Failed to parse server response
    failed to refresh OAuth tokens
    

    Both status entries returned:

    {"authStatus":"oAuth","serverInfo":null,"tools":{}}

    No interactive login was initiated during the reproduction. The diagnostic process was stopped afterward.

    We have not captured the token endpoint HTTP status, content type, or underlying deserialization error, so we cannot distinguish a rejected refresh token from an incompatible/error response or a transport issue.

    Is there a known fix or an OAuth-preserving workaround for this on 0.153.4? Is there a supported way to expose the token endpoint HTTP status, content type, and sanitized parse-error category without logging access tokens, refresh tokens, client secrets, or the raw response body?

    Happy to test a targeted fix. Keeping OAuth rather than switching to a permanent PAT is important for this workflow.

  20. m13v commented on Sep 9, 2026

    @m13v

    the 'sanitized parse-error category' is where your own probe loses the signal: an OAuth invalid_grant comes back as 400 with a JSON error field that carries no token, yet a blanket body-redaction drops it along with the secrets. so a genuinely dead refresh token and a gateway serving non-JSON both flatten to the same status + 'parse failed'. logging the http status plus the top-level error code (not the raw body) is what keeps invalid_grant distinct from a transport/content-type problem.

  21. aiferrierco-hub commented on Sep 15, 2026

    @aiferrierco-hub

    Still reproducible on Windows with:

    • Codex Desktop 26.908.9136.0
    • codex-cli 0.154.0-alpha.6.2
    • Windows 11 Pro x64, build 10.0.26200
    • Project-scoped hosted Supabase MCP over OAuth

    At 2026-09-15T23:37:51.920Z, the connector again failed during client startup with:

    OAuth token refresh failed: Failed to parse server response
    

    The connector remains reported as OAuth, but no server tools load, so a read-only list_tables call cannot start.

    A previous instrumented reproduction on this machine showed:

    target: codex_rmcp_client::oauth::refresh_transaction
    refresh_reason: expiry
    serverInfo: null
    tools: {}
    

    Current checks:

    • Hosted Supabase MCP endpoint is reachable and returns the expected unauthenticated 401 with WWW-Authenticate.
    • Supabase OAuth authorization-server discovery returns 200.
    • The Codex OAuth lock existed but was not held during the probe.
    • The supported launcher resolved to C:\Users\J\AppData\Roaming\npm\codex.cmd.
    • Local records show the same parse failure recurring across multiple Codex versions from July through September 2026.
    • No connector URL, credentials, tokens, authorization headers, or response bodies were captured or changed.

    This remains consistent with a Codex/Supabase OAuth refresh-response compatibility problem rather than an endpoint outage. The underlying HTTP status, response content type, and sanitized top-level OAuth error code are still unavailable, so I cannot distinguish invalid_grant from a non-JSON or otherwise incompatible response.

    Is there now a supported diagnostic flag or fix that exposes those three sanitized fields without logging credentials or the raw response body?

  22. m13v commented on Sep 16, 2026

    @m13v

    the sanitized error-code field is the one that betrays you: it only populates if the body parsed as the expected OAuth JSON, which is the exact case failing here, so it reads null precisely when you need it. status and content-type survive a parse failure; the error code doesn't, and keying a fix off 'code present' re-buries the transport case.

  23. Cypherlibe commented on Sep 16, 2026

    @Cypherlibe

    Confirmed on Codex CLI 0.153.4, installed through Homebrew on macOS.

    User-observed behavior

    • Two project-scoped hosted Supabase MCP servers authenticated with OAuth.
    • Both repeatedly require manual codex mcp login, approximately daily. Login restores access temporarily.
    • Multiple Codex terminal sessions are used; concurrency has not been established as the cause.
    • Pi also connects to Supabase through OAuth and does not exhibit this recurring failure. This is a client comparison, not proof that both clients share credentials or identical refresh conditions.
    • A launcher-managed CODEX_HOME was introduced only recently; the recurring problem predates that change.

    Diagnostic reproduction

    Started codex app-server --stdio with:

    RUST_LOG=codex_rmcp_client=debug,codex_core::mcp_connection_manager=debug
    

    The two project-scoped server URLs were supplied as process-local configuration overrides. After initialize, requested mcpServerStatus/list, without a model turn or database tool call.

    For both servers, the safely filtered logs contained:

    Failed to parse server response
    failed to refresh OAuth tokens
    

    Both status entries returned:

    {"authStatus":"oAuth","serverInfo":null,"tools":{}}
    No interactive login was initiated during the reproduction. The diagnostic process was stopped afterward.

    We have not captured the token endpoint HTTP status, content type, or underlying deserialization error, so we cannot distinguish a rejected refresh token from an incompatible/error response or a transport issue.

    Is there a known fix or an OAuth-preserving workaround for this on 0.153.4? Is there a supported way to expose the token endpoint HTTP status, content type, and sanitized parse-error category without logging access tokens, refresh tokens, client secrets, or the raw response body?

    Happy to test a targeted fix. Keeping OAuth rather than switching to a permanent PAT is important for this workflow.

    Follow-up on my earlier report: I reproduced the failure on both project-scoped Supabase MCP servers using an isolated diagnostic launcher built from Codex rust-v0.154.0’s native MCP client, with the existing macOS Keychain credentials.

    Both refresh attempts returned:

    HTTP 422
    Content-Type: application/json
    {"message":"Required parameter: client_secret"}
    
    

    The diagnostic emitted only the HTTP status, an allowlisted content type, and a fixed category matching that exact message. No credentials or raw response bodies were logged. No database tools were called. This identifies the underlying rejection in my case and supports #43216: missing DCR client authentication material during refresh. The generic “Failed to parse server response” hides the provider’s nonstandard error response.

    Is a Codex-side persistence/restoration fix planned alongside modelcontextprotocol/rust-sdk#1255?

  24. m13v commented on Sep 16, 2026

    @m13v

    persisting the DCR client_secret so refresh stops 422ing quietly swaps one failure class for another: any server that registered with token_endpoint_auth_method=none will now be rejected for sending an unexpected secret, and DCR's client_secret_expires_at means a restored registration can hand back an already-expired client that fails invalid_client. so the persistence fix has to branch on the stored token endpoint auth method and re-register on client expiry, not just always attach the saved secret on refresh.

  25. mrjw717 commented on Sep 29, 2026

    @mrjw717

    Corroborating root-cause evidence: Supabase token endpoint returns 422 client_secret required on refresh

    Reproduced on codex-cli 0.157.1, Linux. When the stored refresh token is used directly against Supabase's token endpoint:

    POST https://api.supabase.com/v1/oauth/token
      grant_type=refresh_token&refresh_token=<rt>&client_id=<id>   (public PKCE client, no secret)
    
    HTTP 422
    {"message":"Required parameter: client_secret"}
    

    Codex sends the refresh without a client_secret (its MCP OAuth clients are registered as public PKCE clients — a new client_id is issued per codex mcp login). The 422 body is not an OAuth-standard error response, so Codex surfaces it as OAuth token refresh failed: Failed to parse server response, followed by "access token is expired and refresh failed; reauthorization required".

    Observed cadence, fully deterministic across four days:

    • Login (authorization-code + PKCE) succeeds fine.
    • Access token works for its full 24h TTL.
    • At first refresh (T+24h), every Supabase entry fails as above → interactive re-login required daily.
    • Stripe MCP OAuth entries under the same Codex install refresh and persist correctly on their 1h rotation, so this is specific to Supabase's endpoint requirements, not general Codex refresh.

    Suggested fixes: send client_secret when the dynamic client registration response provides one (and persist it alongside client_id in .credentials.json), or fall back to re-registering a confidential client against Supabase. Also worth making the refresh error path surface the upstream status/body verbatim instead of "Failed to parse server response".

  26. mrjw717 commented on Sep 30, 2026

    @mrjw717

    WORKAROUND: pre-registered OAuth clients fix both the Supabase daily-reauth and Stripe rotation failures

    Codex supports pinned OAuth clients per server — this is what makes other harnesses survive for months. Recipe that works on 0.159.x:

    1. Register your own client with the provider (outside Codex):

      • Supabase: POST https://api.supabase.com/platform/oauth/apps/register (returns client_id + client_secret; confidential client fixes the client_secret 422 on refresh)
      • Stripe: POST https://access.stripe.com/mcp/oauth2/register (public PKCE client; a stable client_id also fixes the Stripe refresh-token rotation invalidations, since Codex otherwise mints a new throwaway client per login)
    2. In the server's project/global config:

    [mcp_servers.supabase.oauth]
    client_id = "<registered id>"
    client_secret = "<registered secret>"
    callback_url = "http://127.0.0.1:4444/callback/<codex's per-server path>"
    1. Gotchas discovered the hard way:
      • Codex honors callback_url ONLY if its path equals the per-server callback path Codex generates internally (visible in any previous codex mcp login URL, e.g. .../callback/WDOqzugHeRjy). Mismatched path → Codex silently ignores it and sends its own random port, which providers reject (invalid_redirect_uri / redirect_uri not allowed).
      • Both providers match redirect URIs strictly, including port (no RFC 8252 loopback port-ignoring), so the registered URI must be the exact fixed-port callback URL.
      • Supabase access tokens then refresh with client_secret_post as a confidential client — the 24h death loop is gone.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    authIssues related to authentication and accountsbugSomething isn't workingmcpIssues related to the use of model context protocol (MCP) servers

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions