Fixing n8n Gmail OAuth2 Unauthorized Errors on Railway: Redirect URI Mismatch
Who this is forEngineers and automation builders who self-host n8n on Railway with a custom domain and cannot reconnect a Gmail OAuth2 credential.
Gmail OAuth2 credentials in n8n sometimes fail with an Unauthorized error during reconnection, even when the Google Cloud project, consent screen, and client credentials all look correct. The failure is easy to misdiagnose as an expired token, and it can waste hours. This article explains how a mismatch between the redirect URI registered in Google Cloud Console and the callback URL n8n actually generates causes the error on a Railway-hosted instance with a custom domain. You will learn how to confirm the mismatch and fix it with two environment variables or a single Google Cloud change.
Summary
When reconnecting a Gmail OAuth2 credential in n8n returns Unauthorized, the cause is that the approved redirect URI in Google Cloud Console is registered under the custom domain (n8n.ggplab.xyz), but n8n redirects during the OAuth callback to the Railway default domain (*.up.railway.app).
Environment
| Item | Value |
|---|---|
| n8n hosting | Railway |
| Custom domain | n8n.ggplab.xyz |
| Railway default domain | *.up.railway.app |
| Gmail credential | OAuth2 (Google Cloud Console) |
Symptoms
- Running a Gmail node in an n8n workflow returns the error
The provided authorization grant ... is invalid, expired, revoked. - Attempting to reconnect the credential (Reconnect) and selecting a Google account returns
{"status":"error","message":"Unauthorized"}. - The webhook itself works normally (200 OK,
Workflow was started).
Because the webhook works, the n8n instance and its public routing are healthy. The failure is isolated to the OAuth flow.
Root Cause Analysis
What I checked (all normal)
- The redirect URI
https://n8n.ggplab.xyz/rest/oauth2-credential/callbackis registered in the OAuth redirect URIs in Google Cloud Console. - The Gmail API is enabled.
- The OAuth consent screen is configured correctly.
- The Client ID and Client Secret are correct.
Since every item on the Google side checked out, the problem had to be in the URL n8n was sending.
Actual cause
When n8n builds the OAuth2 callback URL, it does not use the browser’s address bar. Instead, it builds the callback from the n8n server’s WEBHOOK_URL or other internal environment variables.
On Railway, you can attach a custom domain (n8n.ggplab.xyz), but if n8n’s environment variables (N8N_EDITOR_BASE_URL or WEBHOOK_URL) are still set to the Railway default domain, n8n does not know its own external address. The result is a mismatch:
Actual callback URL: https://xxx.up.railway.app/rest/oauth2-credential/callback
Registered URI: https://n8n.ggplab.xyz/rest/oauth2-credential/callback
→ Mismatch → Google returns Unauthorized
Core mechanism
[User] Opens n8n.ggplab.xyz in the browser
↓
[n8n] Clicks "Sign in with Google"
↓
[n8n] Builds the OAuth callback URL from N8N_EDITOR_BASE_URL
→ https://xxx.up.railway.app/rest/oauth2-credential/callback ← the problem
↓
[Google] Compares it with the registered redirect URI
→ Only https://n8n.ggplab.xyz/... is registered
→ Mismatch → Unauthorized
The browser reached n8n through the custom domain, but n8n itself generated the callback with the internal domain. Google only sees the URL n8n sends, so it rejects the request.
Fix
Set n8n’s base URL environment variables in Railway to the custom domain:
N8N_EDITOR_BASE_URL=https://n8n.ggplab.xyz
WEBHOOK_URL=https://n8n.ggplab.xyz
Alternatively, add the Railway default domain callback to the authorized redirect URIs in Google Cloud Console:
https://xxx.up.railway.app/rest/oauth2-credential/callback
The environment variable fix is the better choice. It makes n8n consistently generate URLs under the domain users actually visit, and it keeps the Google Cloud configuration to a single entry. Adding the Railway default domain works, but it leaves a second public address registered with Google, which you then have to maintain.
Lessons
- A custom domain is not the same as the app’s internal idea of its domain. An app behind a reverse proxy or CDN may not know its own external URL. You have to tell it explicitly with environment variables.
- When debugging OAuth redirect URIs, inspect the
redirect_uriparameter. Check the browser’s network tab for theredirect_uriparameter sent to Google. This shows the exact URL n8n generated and usually reveals the cause immediately. - When something that worked suddenly stops working, check both the token and the infrastructure. An expired OAuth refresh token (seven days in testing mode) and a redirect URI mismatch produce similar symptoms, both showing
Unauthorized. It is tempting to suspect the token first, but you should also review the history of infrastructure changes, such as domain or hosting changes.
Related Issues
- n8n official documentation: Environment Variables
- When hosting n8n on Railway, setting
N8N_EDITOR_BASE_URLis required.
Bottom line
A Gmail OAuth2 Unauthorized error during reconnection on a Railway-hosted n8n instance with a custom domain is most likely a redirect URI mismatch, not a bad token. Set N8N_EDITOR_BASE_URL and WEBHOOK_URL to the custom domain so the callback URL matches what is registered in Google Cloud Console. Check the redirect_uri parameter first to confirm the diagnosis before changing anything else.
Sources
Frequently asked questions
- Why does n8n return Unauthorized when I reconnect a Gmail OAuth2 credential on Railway?
- The OAuth callback URL is built from n8n's base URL environment variables. If those point to the Railway default domain while Google Cloud Console only lists the custom domain as a redirect URI, Google rejects the request with Unauthorized.
- How do I fix the redirect URI mismatch in n8n on Railway?
- Set N8N_EDITOR_BASE_URL and WEBHOOK_URL to your custom domain, such as https://n8n.ggplab.xyz. Alternatively, add the Railway default domain callback URL to the authorized redirect URIs in Google Cloud Console.
Want the full system? The Claude Code & Codex Skills guidebook collects the skills and subagents behind this blog, from $19.
Some links are affiliate links. If you sign up through them, BuildnWrite may earn a commission at no extra cost to you.
BuildnWrite helps teams build AI agents that keep running. About BuildnWrite ›