OAuth2 for Beginners: Connecting APIs Without the Pain
What You’ll Need
- n8n Cloud or self-hosted n8n instance
- Hetzner VPS or Contabo VPS for self-hosting
- A code editor (VS Code recommended)
- OAuth2-enabled service account (Google, GitHub, or Spotify)
- Basic understanding of HTTP requests and JSON
Table of Contents
- Understanding OAuth2 Flow
- Setting Up Your First OAuth2 Application
- Implementing OAuth2 in n8n
- Common OAuth2 Patterns and Troubleshooting
- Getting Started
Understanding OAuth2 Flow
I remember the first time I tried to integrate with an API that required OAuth2. I expected a simple username and password, and instead got hit with authorization codes, token endpoints, and refresh tokens. It felt like overkill until I realized: OAuth2 isn’t designed for your app to hoard user credentials—it’s designed so you never touch them.
Here’s what actually happens:
- User clicks “Connect” → They’re redirected to the OAuth provider (Google, GitHub, etc.)
- User logs in and grants permission → The provider knows they approved your app
- Provider sends back a code → Your app trades this code for an access token
- Access token lets you act on their behalf → But only for what they permitted
The genius part? Your app never sees their password. They revoke access whenever they want. And providers can monitor what your app does.
OAuth2 has four main flows, but we’re focusing on the Authorization Code Flow—the one you’ll use 90% of the time for web apps and automation platforms.
Setting Up Your First OAuth2 Application
Let’s walk through registering an OAuth2 app with Google—the most common starting point.
Step 1: Create a Google Cloud Project
Head to Google Cloud Console . Click the project dropdown at the top and select “New Project.”
Name it something memorable:
Project Name: My Automation Bot
Organization: (optional)
Hit Create. Google takes 30 seconds to spin it up.
Step 2: Enable the Google Drive API
Once in your project, go to APIs & Services → Library. Search for “Google Drive API” and click Enable.
Do the same for Google Sheets API and Gmail API. We’ll use these later.
Step 3: Create OAuth2 Credentials
Navigate to APIs & Services → Credentials. Click + Create Credentials → OAuth Client ID.
Google will ask you to configure a consent screen first. Click Configure Consent Screen:
User Type: External
App name: My Automation Bot
User support email: your-email@gmail.com
Developer contact: your-email@gmail.com
Add scopes for the APIs you enabled. For Gmail, add:
https://www.googleapis.com/auth/gmail.readonlyhttps://www.googleapis.com/auth/gmail.send
Save and continue.
Now go back to Credentials → + Create Credentials → OAuth Client ID → Web application.
Add Authorized Redirect URIs:
http://localhost:3000/callback
https://yourdomain.com/callback
https://n8n.yourdomain.com/callback
Google generates a Client ID and Client Secret. Save these immediately—you won’t see the secret again.
💡 Fast-Track Your Project: Don’t want to configure this yourself? I build custom n8n pipelines and bots. Message me with code SYS3-HUGO.
Implementing OAuth2 in n8n
Now let’s wire this into n8n . I’ll show you both the visual workflow builder and the raw configuration.
Method 1: Using n8n’s Built-In OAuth2 Credentials
The easiest path: n8n has pre-configured OAuth2 for major services. Here’s how:
- Create a new workflow in n8n Cloud or your self-hosted instance
- Add a node → Search for “Gmail”
- Click Authenticate when prompted
- Authorize the pop-up that opens
- Done. n8n handles the token exchange automatically.
Under the hood, n8n stores your refresh token encrypted and rotates access tokens before they expire.
Method 2: Custom OAuth2 with HTTP Requests
Sometimes you need to wire up a custom API. Here’s the complete flow using n8n’s HTTP Request node.
Create a workflow with these nodes in sequence:
Node 1: Webhook (Trigger)
This receives the authorization code from the OAuth provider:
{
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [100, 200],
"webhookId": "your-webhook-id",
"method": "GET",
"path": "oauth-callback"
}
Node 2: Set Variables
Extract the authorization code from the query parameter:
{
"name": "Set Authorization Code",
"type": "n8n-nodes-base.set",
"typeVersion": 3,
"position": [400, 200],
"assignments": [
{
"name": "authCode",
"value": "={{ $query.code }}"
},
{
"name": "state",
"value": "={{ $query.state }}"
}
]
}
Node 3: Exchange Code for Token
This is the critical step. We POST to the OAuth provider’s token endpoint:
{
"name": "Get Access Token",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [700, 200],
"method": "POST",
"url": "https://oauth.example.com/token",
"headers": {
"Content-Type": "application/x-www-form-urlencoded"
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "grant_type",
"value": "authorization_code"
},
{
"name": "code",
"value": "={{ $node[\"Set Authorization Code\"].json.authCode }}"
},
{
"name": "client_id",
"value": "YOUR_CLIENT_ID"
},
{
"name": "client_secret",
"value": "YOUR_CLIENT_SECRET"
},
{
"name": "redirect_uri",
"value": "https://n8n.yourdomain.com/webhook/oauth-callback"
}
]
}
}
Node 4: Store Token Securely
Use n8n’s Credential system instead of plaintext storage. Create a new Credential:
Settings → Credentials → + Create:
{
"credentialType": "oAuth2Api",
"name": "Custom OAuth2",
"data": {
"clientId": "YOUR_CLIENT_ID",
"clientSecret": "YOUR_CLIENT_SECRET",
"accessToken": "={{ $node[\"Get Access Token\"].json.access_token }}",
"refreshToken": "={{ $node[\"Get Access Token\"].json.refresh_token }}",
"expiresIn": "={{ $node[\"Get Access Token\"].json.expires_in }}"
}
}
Node 5: Use the Access Token
Now you can make authenticated requests:
{
"name": "Get User Profile",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [1000, 200],
"method": "GET",
"url": "https://api.example.com/user/profile",
"headers": {
"Authorization": "Bearer {{ $credentials.oAuth2Api.accessToken }}"
}
}
Handling Token Refresh
Access tokens expire (usually after 1 hour). n8n automatically refreshes them, but here’s what happens behind the scenes:
{
"name": "Refresh Token If Needed",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [1300, 200],
"conditions": {
"nodeVersion": 2,
"conditions": [
{
"id": "condition_0",
"leftValue": "={{ Date.now() }}",
"rightValue": "={{ $credentials.oAuth2Api.expiresAt }}",
"operator": {
"type": "boolean",
"properties": {
"operation": "greaterThan"
}
}
}
]
}
}
If expired, call the refresh endpoint:
{
"name": "Refresh Access Token",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [1300, 400],
"method": "POST",
"url": "https://oauth.example.com/token",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "grant_type",
"value": "refresh_token"
},
{
"name": "refresh_token",
"value": "={{ $credentials.oAuth2Api.refreshToken }}"
},
{
"name": "client_id",
"value": "YOUR_CLIENT_ID"
},
{
"name": "client_secret",
"value": "YOUR_CLIENT_SECRET"
}
]
}
}
Common OAuth2 Patterns and Troubleshooting
Pattern 1: Multi-Tenant OAuth (SaaS)
If you’re building a platform where each user connects their own service:
- Store tokens per user in your database with encryption
- Add a user ID to the state parameter to match tokens on callback
- Use Namecheap to register a domain, then set up a reverse proxy with SSL to handle redirect URIs securely
Here’s the state parameter pattern:
{
"name": "Generate State",
"type": "n8n-nodes-base.set",
"typeVersion": 3,
"assignments": [
{
"name": "state",
"value": "={{ Buffer.from(JSON.stringify({ userId: 123, nonce: Math.random() })).toString('base64') }}"
}
]
}
Pattern 2: Background Token Refresh
For long-running workflows, refresh tokens proactively every 50 minutes:
{
"name": "Schedule Token Refresh",
"type": "n8n-nodes-base.cron",
"typeVersion": 1,
"triggerTimes": {
"mode": "everyX",
"value": 50,
"unit": "minutes"
}
}
Common Errors and Fixes
“Invalid redirect URI”
- Ensure the redirect URI in Google Console exactly matches what n8n sends
- Include protocol (http/https) and port if applicable
- No trailing slashes
“Invalid client secret”
- You copied it wrong. Go back to Google Console and regenerate.
- Check for hidden whitespace.
“Token expired”
Want to automate this yourself?
Start with n8n Cloud (free tier available) or self-host on a Hetzner VPS for full control.
📬 Get Weekly Automation Tips
One email per week with tutorials, tools, and workflows. No spam, unsubscribe anytime.