Getting invalid_client error during Notion OAuth token exchange

I’m working on setting up OAuth for a Notion API integration and running into an issue. Every time a user approves the authorization and gets redirected back to my app, I get an invalid_client error when trying to exchange the authorization code for an access token.

Here’s what I’m doing:

  • User clicks authorize and approves access
  • They get redirected to my callback URL with the code parameter
  • I try to exchange this code for a token but it fails

I’m creating the authorization header by encoding my client credentials in base64 format like the docs suggest. The client ID and secret are copied directly from my integration settings.

const authCode = req.query.code;

const credentials = Buffer.from(
    `${CLIENT_ID}:${CLIENT_SECRET}` // from integration dashboard
).toString("base64");

const response = await fetch("https://api.notion.com/v1/oauth/token", {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "Authorization": `Basic ${credentials}`
    },
    body: JSON.stringify({
        code: authCode,
        grant_type: "authorization_code",
        redirect_uri: "https://myapp.example.com/callback"
    })
});

if (response.ok) {
    const tokenData = await response.json();
    return res.json({ success: true });
} else {
    const error = await response.json();
    return res.status(response.status).json(error);
}

Any ideas what could be wrong with my setup?

Check your authorization header format - that’s probably the issue. I hit the same problem building my Notion integration this year. Skip the Basic auth with base64 encoding and use Bearer token authentication instead. Just put your client secret directly in the Authorization header. Notion’s OAuth can be picky about Basic auth format, and their docs aren’t great on this.

Also check your OAuth scopes in the dashboard. Wrong scopes sometimes throw invalid_client errors instead of scope errors. Make sure your integration shows “verified” or “active” in the Notion developer console too.

The Problem:

You’re encountering difficulties setting up OAuth for a Notion API integration, specifically receiving an invalid_client error when exchanging the authorization code for an access token. This typically occurs after a user successfully authorizes your application. Your current approach uses Base64 encoding for client credentials, which, while technically correct, can be prone to errors and is often unnecessary in the context of Notion’s OAuth flow. Manual OAuth setup is notoriously error-prone, involving complexities like redirect URIs, credential management, and handling potential inconsistencies in Notion’s API.

:thinking: Understanding the “Why” (The Root Cause):

The invalid_client error in Notion’s OAuth flow usually indicates a problem with the authentication process itself, not necessarily your code’s logic. While Base64 encoding of credentials is sometimes required, Notion’s API often prefers a simpler Bearer token approach for this specific OAuth token exchange step. Manual handling of OAuth introduces many points of failure: misconfigured redirect URIs, incorrectly formatted authorization headers, expired or revoked tokens, and inconsistencies in Notion’s API behavior. Furthermore, debugging these issues can be time-consuming.

:gear: Step-by-Step Guide:

  1. Automate OAuth with a Workflow Tool: The most efficient solution is to automate the entire OAuth flow. This eliminates manual handling of sensitive credentials and reduces the risk of errors. Tools like Latenode can manage OAuth, handle token exchanges, refresh tokens automatically, and manage edge cases that frequently cause problems with manual setups.

  2. Set up a Workflow: Using Latenode (or a similar tool), create a workflow that handles the following steps:

    • Initiate the OAuth flow: The workflow triggers when a user needs access to your Notion integration.
    • Manage the Authorization: The workflow securely manages and stores credentials. It handles the redirect to Notion’s authorization page, captures the authorization code, and executes the token exchange.
    • Secure Token Storage: The workflow saves the access token securely, using the most appropriate methods for the tool you choose (e.g., environment variables, encrypted storage). The workflow should also include token refresh logic to extend the access token’s lifespan.
    • Access the Notion API: Your workflow now smoothly accesses the Notion API using the properly managed access token.
  3. (Alternative, if automation isn’t immediately feasible): Verify your Setup Manually: If automating is not an immediate option, carefully double-check the following:

    • Redirect URI: Ensure the redirect_uri parameter in your token request exactly matches the redirect URI registered in your Notion integration settings. Even a minor discrepancy (extra slash, case difference) will result in an invalid_client error.
    • Client ID and Secret: Confirm that you are using the correct CLIENT_ID and CLIENT_SECRET from your Notion integration settings. Log these values to verify they are correctly being loaded into your application (check your environment variables).
    • Published Integration: Make absolutely sure your Notion integration is published. Unpublished integrations generally cannot perform OAuth flows.
    • Token Exchange Timing: Notion’s authorization codes expire quickly. Process the token exchange immediately upon receiving the authorization code to avoid this common failure point.

:mag: Common Pitfalls & What to Check Next:

  • Incorrect Notion Integration Type: Make sure your integration is a “Public integration” and not an “Internal integration.” Internal integrations typically do not support OAuth.
  • Missing or Incorrect Scopes: Ensure that your OAuth scopes are correctly configured in your Notion integration settings.
  • Rate Limiting: Notion’s API has rate limits. If your application is making many requests, you might be exceeding these limits. Consider implementing delays between requests or handling rate limit errors gracefully.

:speech_balloon: Still running into issues? Share your (sanitized) config files, the exact command you ran, and any other relevant details. The community is here to help!

I hit this exact error when building my first Notion integration. Turned out my environment variables weren’t loading right in production. My credentials looked fine in the code, but the actual values being sent were undefined or cut off. Log your CLIENT_ID and CLIENT_SECRET right before making the request to see what’s actually there. My CLIENT_SECRET was getting truncated because my hosting provider didn’t handle special characters in env vars properly. Also check if you’re in dev vs production - Notion needs the redirect URI to match exactly between your integration settings and what you’re sending in the token request. Testing locally with production URLs registered? That’ll throw invalid_client errors every time.

check if u actually published ur integration in Notion’s dashboard. unpublished ones throw invalid_client errors even if creds r correct. also, log the full error response - Notion often has specific details that’ll show u what’s broken.

This error hit me hard building my CMS integration. Nobody’s mentioned the timing issue yet - Notion’s auth codes expire fast. Any delay between user approval and your server processing the exchange? You’ll get invalid_client. I kept hitting this during slow network tests until I figured out the codes were timing out. Also check if you’ve got multiple integration versions in your workspace. I had an old internal integration with similar naming that messed up my CLIENT_ID references. The error’s misleading - it’s not always about your actual client credentials. Try exchanging the token right after getting the code and see if that fixes it.

Had this exact issue last month! It’s usually the integration type in Notion. Make sure you’ve got a “Public integration” set up, not an “Internal integration” - internal ones don’t work with OAuth and you’ll get those invalid_client errors. Also check that your OAuth redirect URLs match exactly what you’re sending in redirect_uri. Notion’s really picky about this. Oh, and double-check your CLIENT_ID is actually from the OAuth integration, not some other internal one you might’ve made before.

yea, for sure! check ur redirect_uri closely, even a small typo can break it. also, look out for any spaces in your client secret. that kind of stuff messes things up all the time!

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.