Gmail OAuth2 fails with 401 Unauthorized at callback - manual token exchange succeeds

Describe the problem/error/question

Gmail OAuth2 authentication consistently fails with 401 Unauthorized during the callback phase, despite Google Cloud being configured correctly. Manual token exchange using curl succeeds, proving the issue is within n8n’s OAuth implementation.

**Related issue:** Gmail OAuth2 credential fails during authorization on a self-hosted n8n instance (same symptoms, but I have additional debugging evidence)

What is the error message (if any)?

When the OAuth callback returns to n8n:

Status: 401 Unauthorized Response: {“status”:“error”,“message”:“Unauthorized”}

Browser shows: “Error: Unauthorized - Failed to connect. The window can be closed now.”
n8n debug logs show OAuth URL generation but **no error logs** when the callback fails.

Please share your workflow

N/A - This occurs during credential setup, before any workflow is created. The issue happens when clicking "Sign in with Google" in the Gmail OAuth2 API credential configuration.

Share the output returned by the last node

N/A - No workflow execution. The failure occurs during OAuth credential authorization.

Information on your n8n setup

  • n8n version: 2.4.6
  • Database (default: SQLite): SQLite
  • n8n EXECUTIONS_PROCESS setting (default: own, main): own, main
  • Running n8n via (Docker, npm, n8n cloud, desktop app): Docker
  • Operating system: macOS host running Docker (Ubuntu 24 container)

Docker Environment Variables:

  • N8N_HOST=0.0.0.0
  • N8N_PORT=5678
  • NODE_ENV=production
  • N8N_SECURE_COOKIE=false
  • N8N_EDITOR_BASE_URL=http://localhost:5678
  • WEBHOOK_URL=http://localhost:5678/
  • GENERIC_TIMEZONE=Europe/Berlin
  • TZ=Europe/Berlin
  • N8N_LOG_LEVEL=debug
    `

Google Cloud Configuration (verified working):

  • Gmail API: Enabled :white_check_mark:
  • OAuth Consent Screen: Testing mode
  • Test user added: [email protected] :white_check_mark:
  • OAuth Client Type: Web application
  • Authorized redirect URI: http://localhost:5678/rest/oauth2-credential/callback
  • Quotas: 0% usage, no limits reached

Steps to Reproduce

  1. Create new “Gmail OAuth2 API” credential in n8n Settings → Credentials
  2. Enter Client ID and Client Secret from Google Cloud Console
  3. Click “Sign in with Google”
  4. Browser redirects to Google - consent screen appears
  5. Click “Allow” to authorize all requested Gmail scopes
  6. Google redirects back to: http://localhost:5678/rest/oauth2-credential/callback?state=...&code=...&scope=...
  7. n8n returns 401 Unauthorized

What I’ve Verified

:white_check_mark: Manual Token Exchange Works

I captured the authorization code from the callback URL and manually exchanged it:

curl -X POST https://oauth2.googleapis.com/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "code=4/0ASc3gC0..." \
  -d "client_id=MY_CLIENT_ID" \
  -d "client_secret=MY_CLIENT_SECRET" \
  -d "redirect_uri=http://localhost:5678/rest/oauth2-credential/callback" \
  -d "grant_type=authorization_code"

Result: :white_check_mark: HTTP 200 Success - Google returned valid access_token and refresh_token

This proves:

  • Google Cloud configuration is correct
  • Client credentials are valid
  • Authorization code is valid
  • The problem is within n8n’s OAuth callback handler

:cross_mark: n8n Callback Consistently Fails

Browser network inspection shows n8n receives the same valid parameters from Google, but returns 401.

What I’ve Tried

  • :white_check_mark: Updated n8n: 2.1.4 → 2.4.6
  • :white_check_mark: Created multiple fresh OAuth credentials in Google Cloud
  • :white_check_mark: Generated new Client Secrets
  • :white_check_mark: Deleted and recreated credentials in n8n multiple times
  • :white_check_mark: Cleared browser cache (Safari and Chrome)
  • :white_check_mark: Verified Docker container time matches host time
  • :white_check_mark: Full Docker restart
  • :white_check_mark: Tested both Testing and Production OAuth consent modes
  • :white_check_mark: Created completely new Google Cloud project
  • :white_check_mark: Verified redirect URI matches exactly (no trailing slashes, correct port)

Nothing resolves the issue. The 401 error is consistent across all attempts.

Additional Context

  • Other OAuth credentials work (e.g., Google Gemini API with API keys)
  • Issue is specific to Gmail OAuth2
  • n8n debug logs show OAuth URL generation but no errors during callback
  • Same Google credentials work perfectly with manual curl
  • Multiple Google accounts tested - same result

Question

Is this a known issue with n8n’s Gmail OAuth2 implementation in version 2.4.6? The fact that manual token exchange succeeds but n8n’s callback fails suggests an issue in n8n’s OAuth handler code.

Are there any additional environment variables, debugging steps, or workarounds available?

Thank you!

@Jorg_Koerfer

Fix Gmail OAuth2 on Self-Hosted n8n

  1. Set n8n environment variables (Docker)
N8N_HOST=yourdomain.com
N8N_PORT=443
N8N_PROTOCOL=https
WEBHOOK_URL=https://yourdomain.com/

Restart n8n.

  1. Update Google OAuth redirect URI
https://yourdomain.com/rest/oauth2-credential/callback

For localhost testing:

http://localhost:5678/rest/oauth2-credential/callback

  1. Re-create Gmail OAuth2 credential in n8n
  • Enter Client ID & Secret

  • Authenticate → complete Google consent → credential saves

  1. Test workflow
  • Manual trigger → Gmail node should execute without errors

Gmail OAuth requires HTTPS in production; HTTP works only on localhost.

@devcodejourneyy Thank you for the response!

However, I’m already using localhost with HTTP as you suggested:

- N8N_EDITOR_BASE_URL=http://localhost:5678
- WEBHOOK_URL=http://localhost:5678/

And the redirect URI in Google Cloud is:

http://localhost:5678/rest/oauth2-credential/callback

According to your response, this should work for localhost testing. But it doesn’t - the 401 error persists.

The key evidence is that manual curl works perfectly with the exact same setup:

  • Same localhost URL
  • Same HTTP (not HTTPS)
  • Same Client ID and Secret
  • Same redirect URI

If it was a protocol issue (HTTP vs HTTPS), the manual curl would also fail. But it succeeds with HTTP 200.
This strongly suggests the issue is in n8n’s OAuth callback handler code, not the configuration.

My setup used to work but it suddenly stopped working, even with 2.1.4 so it is not related to n8n version, but it seems that something changed externally (Google Oauth?), the last successful execution of any workflow using gmail was on 23.01.2026.

Any other ideas would be appreciated!

SOLVED!

The issue was session validation failing during OAuth callback.

req.user was undefined during the OAuth callback, causing n8n to reject all OAuth attempts with 401 Unauthorized.

I already set the following and tested but it failed. However after several trials it ended up working again with:

Solution: Add this environment variable to docker-compose.yml:

- N8N_SKIP_AUTH_ON_OAUTH_CALLBACK=true

This skips the user session check during OAuth callbacks while maintaining security through CSRF token validation.

I also added encryption key as a parameter but it didn’t lead to the solution:

- N8N_ENCRYPTION_KEY= my key

Something changed with session management after the Docker container was recreated on January 27, 2026. Possibly related to:

  • Safari 26.2 update on January 11
  • Docker container recreated with different session handling
  • Cookie/session storage changes
1 Like

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