MCP Server Trigger: Requiring re-auth

Describe the problem/error/question

I have a workflow with an ‘MCP Server Trigger’ using n8n User Auth (OAuth2) and ‘Require Workflow Execute Permission’ enabled.
I then have my various ‘Execute Sub-workflow’ nodes to present my other workflows as tools.

My ‘codex mcp list’ shows:
Name Url Bearer Token Env Var Status Auth
personal-tools https://redacted.app.n8n.cloud/mcp/available-tools - enabled OAuth

This all works great for an hour or so but then it will fail with a 401 Unauthorized or the tools simply won’t load in a new session because the refresh token is rejected by n8n.

Why is the refresh token not working? Does it get invalidated if one of my tools returns a certain response? e.g. Google might return a ‘429 Too Many Requests’ at times.

Any suggestions would be great as this is the only reason I would use n8n

What is the error message (if any)?

Codex tries to renew an expired token using the refresh token but n8n is rejecting it.
failed to refresh OAuth tokens for server personal-tools:
OAuth refresh token was rejected:
Server returned error response: invalid_grant: Invalid refresh token

Please share your workflow

Information on your n8n setup

  • n8n version: n8n@2.39.10 Stable
  • Running n8n via: Cloud

Hey @CodeZeno, while you wait for a response, here are some things that might help:

Suggested resources

Automatically matched to your question.

Docs:

Forum:

@Epicop, @achamm, @Mutasem - you’ve helped with similar issues before, can you take a look?

Automatically suggested by n8n’s community bot. It’s a pilot - please share feedback here.

@CodeZeno

This sounds like a regression issue as a fix was released on 2.31.0. You may want to file a bug report. In the meantime, can you use Header Auth or API Key instead of n8n User Auth.

Hi @CodeZeno, a Google 429 shouldn’t invalidate your n8n MCP login. Those are separate credentials.

In 2.39.10, the access token lasts one hour, while the refresh token lasts 30 days. n8n replaces the refresh token each time it’s used, so trying the old one again returns invalid_grant.

Close other Codex sessions using this server, then run:

codex mcp logout personal-tools
codex mcp login personal-tools

Keep n8n User Auth enabled and test with just one Codex session. Make another tool call after the hour passes. This checks whether the failure still happens without other sessions sharing the login.

What does codex --version return, and does that single-session test still fail?

Pretty sure the 429s aren’t it. Those happen inside the workflow run, they don’t touch the OAuth tokens for the MCP connection. The fact that it dies after about an hour is the tell, that’s when the access token expires and Codex tries its first refresh.

Looked into this and it seems like a Codex thing more than n8n. There are a bunch of open issues on the codex repo about it (#46028 and #14144 are the main ones). Basically if you’ve got more than one Codex session open, one of them refreshes the token, and then another one tries to use the old refresh token, which is already spent, so n8n rejects it. And once that happens Codex just keeps retrying the dead token, so new sessions fail too.

Few things I’d try:

  • run it with just one Codex session open and see if it makes it past the hour
  • when it breaks, do codex mcp logout personal-tools, then login again, and restart every open session, not just the one you’re in
  • update Codex, they’re working on this

If you just need it to work for now, you can switch the MCP trigger to Bearer auth and point Codex at the token in ~/.codex/config.toml:

[mcp_servers.personal-tools]
url = "https://your-instance.app.n8n.cloud/mcp/available-tools"
bearer_token_env_var = "N8N_MCP_TOKEN"

Then set the token in your shell profile: export N8N_MCP_TOKEN=“your-token” (same one you put on the trigger). No refresh = nothing to break. You do lose the per-user n8n auth though, so the execute permission setting won’t work the same. For personal tools that’s probably fine.

If it still breaks with one session on the latest version, then it’s probably on the n8n side and worth opening an issue there.

n8n issues short-lived access tokens (around 1 hour). The client (Codex) correctly tries to refresh them, but n8n often rejects the refresh token with invalid_grant. It’s not caused by your tools returning 429s or other errors… those don’t invalidate the OAuth session. The refresh token itself is either expiring too quickly or getting revoked on the n8n side.

I suggest you:

Switch to Access Token auth (recommended for reliability)
In Settings → Instance-level MCP → Connection details, use the personal Access Token instead of OAuth. It’s longer-lived and doesn’t need refresh. Update your Codex config to use Bearer with that token.

If you must stay on OAuth

•  Re-authorize in Codex every time it fails (or set a reminder every \~50–60 min).

•  Make sure you’re on the latest n8n (some MCP OAuth refresh fixes landed in later 2.x builds).

•  In the MCP Server Trigger, try turning off “Require Workflow Execute Permission” temporarily to test if the stricter permission check is contributing.

Quick workaround
Keep the OAuth connection, but add a simple scheduled workflow that just pings the MCP endpoint every 45 minutes so the token stays warmer (doesn’t always help, but some people report it reduces the rejections).

Access Token is the cleanest long-term solution for this exact use case. The OAuth refresh path for MCP clients is still a bit fragile on n8n’s side.