How to Build a SaaS on n8n: Handling OAuth Credentials for Multiple Users
n8n has quietly become one of the most practical backends for building SaaS products fast. It gives you a visual workflow engine, a built-in HTTP server (via webhooks), hundreds of pre-built integrations, and a JavaScript-based expression layer powerful enough to handle real business logic. For founders and developers who want to ship a product without spending six months writing infrastructure code, n8n as a SaaS backend is a legitimate and increasingly popular choice.
But as soon as your n8n-powered SaaS needs to act on behalf of individual users - reading their emails, posting to their Slack, syncing their calendar - you hit the hardest problem in multi-tenant SaaS architecture: credential isolation. Each user has their own OAuth tokens. n8n's credential system was not designed to handle them. This article explains the full architecture: how to build a SaaS on n8n, what the multi-tenant credential problem actually looks like, and how to solve it properly using CredBridge.
Why n8n Is a Great SaaS Backend
Before diving into the problem, it is worth understanding why serious builders are choosing n8n as a SaaS backend in the first place - because the approach is less obvious than it might seem.
Speed of Development
With n8n, you can wire together a Stripe webhook, a database write, a Slack notification, and an email send in under an hour. The same flow would take days or weeks to build from scratch in Node.js or Python. For early-stage products, this matters enormously. The visual workflow builder makes it easy to iterate, debug, and hand off to non-engineers.
Built-in Integration Library
n8n ships with nodes for hundreds of services - Airtable, Notion, HubSpot, Salesforce, Google Workspace, Microsoft 365, and more. Each node handles the API quirks, pagination, and authentication mechanics for you. For a SaaS that needs to integrate with many third-party services, this is a massive accelerator.
Webhook-Native Architecture
n8n Webhook nodes give you a production-ready HTTP endpoint in seconds. You define the path, configure authentication if needed, and you have a URL that accepts POST requests, processes them through your workflow, and returns a response - all without writing server code. This is the foundation of an n8n SaaS backend.
Programmable Logic Without Leaving the Platform
The Code node (formerly Function node) gives you full Node.js access. You can write complex data transformations, call npm-compatible libraries, and implement branching logic. Combined with n8n's expression language (which uses {{ }} syntax throughout), you can handle most real-world business logic without a separate codebase.
The Architecture of an n8n-Powered SaaS
A well-structured n8n SaaS backend follows this general pattern:
User's Browser / Mobile App
→ API call (REST or GraphQL) to n8n Webhook
→ n8n Workflow: authenticate request, execute business logic
→ Third-party APIs, databases, queues
→ HTTP Response back to client
Core Architectural Components
1. Webhook Triggers as API Endpoints
Each n8n workflow with a Webhook trigger becomes an API endpoint. You organize your backend into workflows by domain - one workflow for user signup, one for subscription management, one for sending reports, one for syncing external data. Each webhook URL is the entry point for that piece of functionality.
POST https://your-n8n.com/webhook/user/signup
POST https://your-n8n.com/webhook/reports/generate
POST https://your-n8n.com/webhook/calendar/sync
2. Request Authentication
Use the Webhook node's built-in authentication options (Header Auth, Basic Auth) or implement your own token verification in the first node. A common pattern is to pass a session token in the Authorization header and validate it against your user database (Supabase, PlanetScale, or a simple Airtable table for early-stage products).
3. Business Logic Nodes
Chain together nodes to implement your product's logic. Conditional branching with IF nodes, looping with Split in Batches, data transformation with Code nodes. The visual representation makes it easy to follow the execution path.
4. Response Node
Use the Respond to Webhook node to return structured JSON to the caller. This is what makes n8n a proper API backend - not just a fire-and-forget automation tool.
{
"success": true,
"data": {
"report_id": "rpt_abc123",
"generated_at": "2026-02-26T14:00:00Z",
"events_processed": 42
}
}
5. Error Handling
n8n's error workflow feature lets you define a global error handler that catches failures across all workflows. For a SaaS backend, this is where you log errors, trigger alerts, and return standardized error responses to clients.
The Biggest Technical Challenge: Credential Isolation Between Users
Here is where n8n's SaaS potential runs into a hard architectural wall.
Your SaaS connects users' Google, Microsoft, or Slack accounts. Each user authenticates once via OAuth. You get their access token and refresh token. Now you need to use those tokens in your workflows - reading their calendar, sending from their email, posting to their Slack - but always keeping User A's tokens strictly separate from User B's.
This is credential isolation. It is the defining technical challenge of multi-tenant OAuth SaaS.
Why n8n's Credential System Cannot Handle This
n8n's credential store is designed for infrastructure credentials - the credentials of the n8n instance operator. When you add an API key or OAuth token to n8n's credential store, it is available to any workflow running on that instance. The credential is selected at design time, when you build the workflow.
There is no native mechanism in n8n to:
- Store one credential per user (N users = N credentials is the only option, and it breaks at scale)
- Select a credential at runtime based on incoming request data
- Automatically refresh an OAuth token that is stored outside n8n's credential store
The n8n documentation itself acknowledges this: credentials are static workflow configuration, not dynamic runtime data. This is a reasonable design choice for n8n's primary audience (automation builders working on behalf of themselves or a single client), but it is a fundamental mismatch with multi-tenant SaaS requirements.
Current Approaches and Why They Fall Short
The n8n community has developed several workarounds. Each has real drawbacks that compound as your user base grows.
Approach 1: One Workflow Per User
The most direct mapping of n8n's model to a multi-tenant requirement: create a copy of every workflow for every user, with their specific credential selected in each copy.
How it works:
- User signs up
- You manually (or programmatically via n8n API) create a workflow copy, updating the credential reference to that user's credential record
- Each user gets their own isolated set of workflows
The drawbacks:
- At 100 users, you have hundreds of workflows. At 1,000 users, thousands.
- n8n's performance degrades significantly with very large numbers of workflows
- Every product change requires updating every user's workflow - a scripting problem you now have to maintain
- Debugging is a nightmare because errors are spread across hundreds of identical-looking workflows
- n8n API rate limits make programmatic workflow creation slow
- This is not SaaS architecture. This is scripted duplication.
Approach 2: Environment Variables Per Tenant
Store tokens in environment variables on the n8n server, namespaced by user:
GOOGLE_TOKEN_USER_001=ya29.abc...
GOOGLE_TOKEN_USER_002=ya29.xyz...
Reference them in workflows with $env.GOOGLE_TOKEN_USER_001.
The drawbacks:
- You need to restart the n8n process to add new environment variables
- Environment variables are flat strings - no structure, no metadata, no expiry tracking
- Token refresh is entirely your problem. When a Google token expires, you need to update the environment variable, which means restarting n8n
- This approach breaks at around 10–20 users and is completely unworkable at 100+
- Environment variables are visible to all workflows on the instance - no isolation
Approach 3: Sub-Workflows With Per-Credential Variants
Use n8n's Execute Workflow node to call sub-workflows, where each sub-workflow variant is configured with a specific user's credential.
How it works:
- Main workflow receives request, looks up user ID
- Routes to the correct sub-workflow for that user via a Switch/IF node
- Sub-workflow has the user's credential hardcoded
The drawbacks:
- Still requires N sub-workflows for N users
- The routing logic in the main workflow must be updated every time a user is added
- More maintainable than pure duplication, but still fundamentally O(N) infrastructure
- The "right" sub-workflow for a new user cannot be created automatically without external tooling
Approach 4: Hardcoded Tokens in HTTP Request Nodes
Pass OAuth tokens as parameters (stored in a database) and use HTTP Request nodes with dynamically-constructed Authorization headers, bypassing n8n's credential system entirely.
How it works:
- Fetch user's token from a database node at the start of the workflow
- Use the token in HTTP Request nodes with
Authorization: Bearer {{ $json.access_token }}
The drawbacks:
- Token refresh is your responsibility. You need to write refresh logic - check expiry, call the OAuth token endpoint, store the new token - in your workflow or an external function
- Security surface is larger: tokens flow through workflow execution data (visible in n8n's execution logs)
- Your token storage (database) needs to be secured, backed up, and available - that is infrastructure you now own
- Error handling for token failures is entirely custom - no standard mechanism
The Clean Architecture: CredBridge as the Token Layer
CredBridge is the missing piece that makes n8n a production-ready SaaS backend for OAuth-dependent products. It sits between your users' OAuth tokens and your n8n workflows, providing:
- A hosted OAuth flow - your users authenticate on their Google/Microsoft/Slack consent screens, tokens go directly to CredBridge, users never see n8n
- Secure token storage - every token is stored encrypted, keyed by
tenant_id(your user identifier) - Automatic token refresh - CredBridge handles expiry and refresh transparently; your workflow always gets a valid token
- A simple runtime API - one HTTP call from n8n gets the right token for the right user
Here is the architecture:
User onboarding:
User → OAuth consent (Google / Microsoft / Slack)
→ CredBridge callback stores tokens
→ Returns tenant_id to your app
→ Your app saves tenant_id in your user database
Workflow execution:
API call from your frontend → n8n Webhook
{ user_session_token, payload }
→ n8n validates session, resolves tenant_id from user database
→ HTTP Request → CredBridge: GET /v1/token?tenant_id=X&provider=google
→ CredBridge returns: { access_token: "ya29.xxx" }
→ HTTP Request → Google / Microsoft / Slack API
→ Respond to Webhook with result
One workflow. One token store. Every user gets the right credentials at runtime.
Full n8n Workflow Configuration Example
Here is a concrete example: a SaaS feature that fetches the user's latest 10 emails from Outlook and returns them as structured data.
Workflow Nodes
Node 1: Webhook Trigger
- Path:
/api/emails/recent - Authentication: Header Auth (validates
Authorization: Bearer SESSION_TOKEN) - Method: POST
Receives:
{
"user_id": "usr_7f3a2b",
"limit": 10
}
Node 2: Resolve Tenant ID (HTTP Request to your user database or Supabase)
{
"method": "GET",
"url": "https://your-api.com/internal/users/{{ $json.user_id }}/tenant",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{ "name": "Authorization", "value": "Bearer {{ $env.INTERNAL_API_KEY }}" }
]
}
}
Returns: { "tenant_id": "credbridge_tenant_abc123", "email": "user@company.com" }
Node 3: Get Microsoft Token (HTTP Request to CredBridge)
{
"method": "GET",
"url": "https://api.credbridge.io/v1/token",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{ "name": "X-CredBridge-Key", "value": "={{ $env.CREDBRIDGE_API_KEY }}" }
]
},
"sendQuery": true,
"queryParameters": {
"parameters": [
{ "name": "tenant_id", "value": "={{ $('Resolve Tenant ID').item.json.tenant_id }}" },
{ "name": "provider", "value": "microsoft" }
]
}
}
Returns: { "access_token": "eyJ0eXAiOiJKV1Qi...", "expires_in": 3599 }
Node 4: Fetch Recent Emails (HTTP Request to Microsoft Graph)
{
"method": "GET",
"url": "https://graph.microsoft.com/v1.0/me/mailFolders/inbox/messages",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{ $('Get Microsoft Token').item.json.access_token }}"
}
]
},
"sendQuery": true,
"queryParameters": {
"parameters": [
{ "name": "$top", "value": "={{ $('Webhook').item.json.limit }}" },
{ "name": "$select", "value": "subject,from,receivedDateTime,bodyPreview" },
{ "name": "$orderby", "value": "receivedDateTime desc" }
]
}
}
Node 5: Transform Response (Code node)
const messages = $input.item.json.value;
return messages.map(msg => ({
id: msg.id,
subject: msg.subject,
from: msg.from.emailAddress.address,
received_at: msg.receivedDateTime,
preview: msg.bodyPreview
}));
Node 6: Respond to Webhook
{
"respondWith": "json",
"responseBody": {
"success": true,
"emails": "={{ $json }}"
},
"responseCode": 200
}
The client's frontend receives a clean JSON response with the user's 10 most recent emails - fetched from the correct Microsoft account using the token CredBridge resolved at runtime - with zero per-user workflow configuration.
Visualizing the Architecture
┌─────────────────────────────────────────────────────────┐
│ YOUR SaaS FRONTEND │
│ React / Next.js / mobile app │
│ POST /api/emails/recent { user_id: "usr_7f3a2b" } │
└─────────────────────────┬───────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ n8n WEBHOOK TRIGGER │
│ Validates session token │
│ Single workflow handles ALL users │
└──────────┬────────────────────────────────┬────────────┘
│ │
▼ ▼
┌──────────────────────┐ ┌─────────────────────────┐
│ YOUR USER DATABASE │ │ CREDBRIDGE API │
│ user_id → tenant_id │ │ tenant_id → OAuth token│
│ (Supabase, PG, etc) │ │ Auto-refresh included │
└──────────────────────┘ └────────────┬────────────┘
│
▼
┌─────────────────────────┐
│ GOOGLE / MICROSOFT / │
│ SLACK API │
│ (correct user's data) │
└─────────────────────────┘
Production Considerations for n8n SaaS Backends
Execution Isolation
n8n runs workflows in isolated execution contexts, but by default stores all execution data (including API responses that may contain token values) in the database. For a SaaS handling sensitive user data, configure n8n to:
- Use the "Do not save" option for successful execution data (Settings > Workflows > Save successful production executions)
- Enable encryption for the n8n database
- Use environment variables (not hardcoded values) for all secrets
Concurrency
n8n's default concurrency setting for workflow executions is limited. For a SaaS with many concurrent users, increase the N8N_CONCURRENCY_PRODUCTION_LIMIT environment variable. The exact limit depends on your server resources.
Webhook Response Times
n8n webhook workflows have execution overhead. For latency-sensitive endpoints, keep workflows short and avoid synchronous calls that add latency. Alternatively, use the "Respond immediately" option and process asynchronously.
Rate Limiting Your API Endpoints
n8n does not natively rate-limit incoming webhook requests. Put a reverse proxy (nginx, Caddy, or Cloudflare) in front of your n8n instance to implement rate limiting per user/IP before requests hit your workflows.
Monitoring
Use n8n's built-in execution history for debugging, but add external monitoring (Better Uptime, Grafana, or a simple cron that pings a health check webhook) to detect when workflows stop responding.
Why CredBridge Is the Right Tool for This Job
The alternatives - one workflow per user, environment variables, sub-workflow routing, or DIY token management in a database - all share the same flaw: they put the credential management burden on you, and that burden grows linearly with your user count.
CredBridge inverts this. The token management is external, automatic, and independent of your workflow count. Whether you have 5 users or 500, your n8n workflow looks exactly the same: receive request, fetch tenant token from CredBridge, call the third-party API, return result.
This is what clean multi-tenant OAuth architecture looks like when built on top of n8n.
Get Started With CredBridge
If you are building a SaaS on n8n and your product needs to act on behalf of individual users' Google, Microsoft, or Slack accounts, CredBridge is the infrastructure layer that makes it work properly.
Solo plan - $19/month: Up to 10 tenants. Ship your MVP and prove the concept with your first cohort of users.
Agency plan - $49/month: Up to 50 tenants. Scale your SaaS to a paying customer base without rebuilding your credential architecture.
Start at credbridge.io - integrate CredBridge into your n8n SaaS backend and get your first user's OAuth token flowing in under 15 minutes.
Related: How to automate Google Calendar for 50+ clients with one n8n workflow | How to manage Slack automations for multiple workspaces with one n8n workflow | Microsoft Outlook automation for agencies with n8n