How to Use Different OAuth Credentials Per Client in n8n (Without Duplicating Workflows)
If you've ever built n8n workflows for more than two clients, you've hit the wall. You set up a beautiful automation - syncing Google Calendar, sending Outlook emails, posting to Slack - and then Client #2 comes along. Same workflow. Different account. And n8n forces you to... duplicate the entire thing.
This isn't a fringe edge case. It's one of the most upvoted, most discussed, most frustrating limitations in the entire n8n ecosystem. Community threads about this have been open since 2021 with tens of thousands of cumulative views and no native fix in sight (on non-enterprise plans).
This article explains exactly why the problem exists, every real workaround people actually use, and the cleanest solution available today.
Why n8n Credentials Are Static By Design
When you connect a Google Calendar node in n8n, you select a credential from a dropdown. That credential is resolved at design time - meaning it's baked into the workflow definition itself. When the workflow runs, n8n looks up that specific credential by ID and uses it. Full stop.
There's no expression syntax like {{ $json.clientId }} that you can drop into the credential selector. The field simply doesn't support it. This is a deliberate architectural choice: credentials are treated as a security boundary, not as runtime variables.
The result? One credential = one account. One workflow = one client. If you have 50 clients, you need 50 copies of the same workflow - one per credential.
The community has been asking for "select credentials via expression" since at least 2021. Feature requests like this one have accumulated hundreds of upvotes. The answer from n8n has consistently been: this is planned for Enterprise via External Secrets. For everyone else, you're on your own.
The Workarounds People Actually Try
Before we get to the clean solution, let's be honest about what people attempt. These are real strategies from the n8n community, and they each have real tradeoffs.
Workaround 1: Duplicate the Workflow (The Default Pain)
The most common "solution" is also the worst one at scale. You duplicate the workflow for each client and swap the credential in each copy.
What it looks like at 5 clients: manageable What it looks like at 20 clients: painful What it looks like at 50 clients: unmaintainable chaos
The moment you find a bug, you're fixing it 50 times. The moment you want to add a new feature, you're updating 50 workflows. Copies drift. You forget to update some. Clients report different behavior. You spend an hour figuring out which copy has the fix.
Workaround 2: Sub-Workflows as an Abstraction Layer
A more sophisticated approach: build a "master" workflow that handles all the logic, and call it from client-specific "router" workflows that pass the right credential context.
This reduces duplication of logic, but you still need one entry-point workflow per client. The credential problem just moves one level up. And debugging across sub-workflow chains in n8n is... not fun.
Workaround 3: Separate n8n Instances Per Client
Some agencies go nuclear and run an entirely separate n8n instance per client. Each instance has its own database, credential store, and webhook URLs. Maximum isolation.
This actually works well for very high-value, security-sensitive clients. But the operational overhead is significant: you're now managing N Docker containers, N databases, N deployment pipelines. It doesn't scale economically below enterprise contracts.
Workaround 4: HTTP Request Node + External Token Store
This is the workaround that actually makes sense, and it's the pattern CredBridge is built on.
The idea: instead of using n8n's native credential system for OAuth tokens, you store the tokens in an external service and fetch them at runtime via an HTTP Request node at the start of your workflow.
[Webhook Trigger]
↓
[HTTP Request: GET token from external API]
→ tenantId: {{ $json.clientId }}
→ Returns: { access_token: "ya29...." }
↓
[Google Calendar Node using {{ $node["Get Token"].json.access_token }}]
This breaks the static credential model. Now your workflow is genuinely dynamic: the tenant ID comes in with the webhook payload, you fetch the right token for that tenant, and inject it into all downstream nodes via expression.
The challenge? Building and maintaining that external token store yourself is non-trivial. You need to handle:
- Secure token storage (AES-256 encryption at rest)
- OAuth flow for each client (the redirect dance, code exchange)
- Automatic token refresh before expiry
- Error handling when a client's token gets revoked
- A UI for clients to connect their accounts
This is basically building a mini-Nango from scratch.
The Clean Solution: CredBridge
CredBridge is built specifically for this pattern. It's the external token store + OAuth flow manager that the HTTP Request workaround needs, without you having to build it.
Here's how it works in practice:
Step 1: Set Up Your OAuth App Once
In the CredBridge dashboard, you paste the client_id and client_secret from your Google, Microsoft, or Slack app. You configure it once, for your app - not per client.
Step 2: Send Clients a Connect Link
For each client (tenant), CredBridge generates a unique connect URL. You send it to your client. They click it, go through the standard OAuth flow, and their token is stored encrypted in CredBridge. That's the last time they need to do anything.
Step 3: One HTTP Request Node. One Workflow. All Clients.
At the start of your n8n workflow, add a single HTTP Request node:
Method: GET
URL: https://credbridge.app/api/token
Headers:
X-API-Key: your-credbridge-api-key
Query Parameters:
tenantId: {{ $json.clientId }}
Response: { "access_token": "ya29.A0ARrdaM..." }
Now use that token across every downstream node:
Authorization: Bearer {{ $node["Get Token"].json.access_token }}
Every client that triggers your workflow gets their own token injected automatically. One workflow. All clients. No duplication.
What CredBridge Handles For You
- Token refresh: Google access tokens expire after 1 hour. CredBridge refreshes them transparently before you hit that wall.
- Revocation alerts: If a client disconnects their account or their token gets permanently invalidated, you get an email alert so you can ask them to reconnect.
- Encryption: All tokens are stored AES-256 encrypted at rest. CredBridge never logs raw tokens.
- Multi-provider: Google (Gmail, Calendar, Drive), Microsoft (Outlook, Calendar), Slack - the three providers that cover 90%+ of agency use cases.
Before vs. After: A Real Comparison
Let's say you manage calendar automations for 30 clients. Here's what your life looks like:
| Situation | Duplicate Workflows | CredBridge |
|---|---|---|
| Add a new client | Duplicate workflow, swap credential (10 min) | Send connect link, done (2 min) |
| Fix a bug | Fix in 30 workflows (~2 hours) | Fix once, applied everywhere (5 min) |
| Add a new feature | Update 30 workflows | Update 1 workflow |
| Client revokes access | Workflow fails silently | Email alert, client prompted to reconnect |
| Token expires mid-run | Workflow errors out | Auto-refreshed transparently |
| Monthly maintenance | Review 30 workflows | Review 1 workflow |
At 30 clients with one bug fix per month, the duplicate-workflow approach costs roughly 8 hours/month in maintenance alone. That's time that could go toward landing new clients.
Works With Self-Hosted n8n and n8n.cloud
CredBridge works with any n8n setup. The HTTP Request node approach doesn't depend on n8n's internal credential system at all - it's just a standard API call. Whether you're on a self-hosted Hetzner VPS, a Docker container on DigitalOcean, or n8n.cloud, the pattern is identical.
It also works with Make (formerly Integromat) - any platform that can make an HTTP request to fetch a token before using it.
FAQ
Isn't this what n8n External Secrets is for? External Secrets is an n8n Enterprise feature that integrates with secret vaults like HashiCorp Vault or AWS Secrets Manager. It solves the secrets-at-rest problem but doesn't solve the multi-tenant OAuth problem - you'd still need to manage one credential per client in the vault. CredBridge specifically solves the multi-tenant OAuth flow problem, including the connect-once UX for clients and automatic token refresh.
What if I only have 3-5 clients? At that scale, workflow duplication is painful but manageable. CredBridge starts making clear sense at 10+ clients, where the maintenance overhead of duplicates becomes a real cost.
Is it no-code? Yes. No SDK, no server setup, no backend required. Dashboard to manage clients, a connect link to send them, one HTTP Request node in n8n. That's it.
Get Started
CredBridge starts at $19/month for up to 10 tenants - less than the hourly rate of the time you'd spend maintaining duplicate workflows.
First month is free. No credit card required to start.
Start your free trial at credbridge.app →
Sources consulted:
- n8n Community: Possible to do multi-tenant workflows that can reference credentials dynamically?
- n8n Community: Select credentials via expression (Feature Request)
- n8n Community: Dynamic Credential Selection via Expressions for Multi-Tenant Workflows
- Lune.dev: How can I dynamically reference multi-tenant credentials in n8n workflows?