MCP OAuth2 API credential does not support HubSpot MCP OAuth v3 token exchange

Bug: MCP OAuth2 API credential does not support HubSpot MCP OAuth v3 token exchange

Hi everyone,

I’m trying to connect the HubSpot Remote MCP Server using the new MCP OAuth2 API credential in n8n.

I’ve narrowed the issue down by comparing the requests generated by MCP Inspector (which works) and n8n (which fails).

Environment

  • n8n version:
  • Credential type: MCP OAuth2 API
  • HubSpot Remote MCP Server

OAuth Configuration

Authorization URL

https://mcp.hubspot.com/oauth/authorize

Token URL

https://mcp.hubspot.com/oauth/v3/token

Grant Type

PKCE

Authentication

Body

Scope

oauth

Expected behavior

The OAuth flow should complete successfully and store the access token.

Actual behavior

The browser successfully authenticates with HubSpot and redirects back to n8n with an authorization code.

The token exchange fails with:

{
  "status": "BAD_CLIENT_SECRET",
  "message": "missing or invalid client secret",
  "error": "invalid_client"
}

Earlier in debugging I also saw:

  • BAD_CLIENT_ID (fixed by correcting the OAuth endpoints)
  • Unsupported content type (fixed by using /oauth/v3/token)

The remaining failure occurs during the token exchange.


Investigation

To compare the requests, I temporarily changed the Token URL to a webhook endpoint so I could inspect the request that n8n generates.

n8n sends

Headers

Content-Type: application/x-www-form-urlencoded
Authorization: Basic <base64(client_id:client_secret)>

Body

grant_type=authorization_code
code=...
redirect_uri=...
code_verifier=...

Even when Authentication = Body is selected, n8n still sends the Authorization Basic header and does not include client_id or client_secret in the body.


MCP Inspector (working)

Headers

Content-Type: application/x-www-form-urlencoded

Body

grant_type=authorization_code
code=...
code_verifier=...
redirect_uri=...
resource=https://mcp.hubspot.com/
client_id=...
client_secret=...

This request succeeds.


Differences

Compared to the working MCP Inspector request, n8n appears to:

  • Send Authorization: Basic even when Authentication = Body is selected.

  • Omit client_id from the form body.

  • Omit client_secret from the form body.

  • Omit the OAuth resource parameter:

    resource=https://mcp.hubspot.com/
    

Questions

  1. Is Authentication = Body currently implemented for the MCP OAuth2 API credential?
  2. Is there currently any way to include the OAuth resource parameter in the token request?
  3. Is HubSpot Remote MCP currently supported by the MCP OAuth2 credential?

Happy to provide additional logs or test a fix if needed.

n8n Instance Details:
Version: 2.10.2
Licence: Sustainable Use License + n8n Enterprise License
Self-Hosted

Thanks!

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

Suggested resources

Automatically matched to your question.

Docs:

Forum:

@barn4k - 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.

Hi @Akshobhya_Shukla147

Since no existing GitHub issue was found for this exact bug , here is what you should do:

  1. File a GitHub issue at n8n-io/n8n with your exact comparison — your request diff between MCP Inspector and n8n is already in perfect bug-report format.

  2. Key points to include in the issue:

  • Authentication = Body sends Authorization: Basic header instead of body params

  • client_id and client_secret are omitted from the form body

  • No way to inject a custom resource parameter into the token request

  • HubSpot MCP server as a concrete failing test case

  1. Short-term workaround: Consider using an HTTP Request node with manual OAuth token handling — fetch the token via a custom HTTP Request node using Body auth and the resource param, then store and inject it manually into your MCP node credential.

Got it. About using the HTTP Request node, I am a bit reluctant in implementing that as I will have to replicate the entire OAuth flow with refresh token handling.

We have taken a look at this and it looks like it might be fixed in a recent release, Please update and see if you are still running into the same problem.

Did not notice that, good catch!!!

ok, I’ll check

Hi @Akshobhya_Shukla147 Welcome!
HubSpot requires MCP clients on the remote server to implement OAuth 2.1 with PKCE and refresh token rotation with single-use refresh tokens, so mcp.hubspot.com stays a moving target even after the token exchange itself is sorted out.
For a path that skips the OAuth flow completely, run HubSpot’s own MCP server yourself against a private app access token instead of the remote one:

PRIVATE_APP_ACCESS_TOKEN=<your-private-app-token> npx -y @hubspot/mcp-server

Start it in HTTP transport mode alongside your n8n container, then point the MCP Client Tool at that endpoint using Bearer or Header Auth. Private app tokens are static, so there is no authorization step and no refresh token to rotate.

I updated the image to n8n version: 2.32.5 and I was able to connect. Thanks.