I’m running multiple n8n instances (dev / rec / prod) and using Microsoft Entra ID credentials to query Microsoft Graph (list chats by userId, chat members, etc.).
When I deploy a workflow from n8n-dev to n8n-rec, the workflow systematically fails on the first scheduled run with: “refreshToken is required” / ERR_ASSERTION.
The only way to recover is to manually open the credential and click “Reconnect” on the target instance. After a few hours or the next deploy, the issue comes back.
I suspect this is the combination of three known behaviors, but I’d like confirmation from the n8n team and best-practice guidance for a multi-environment setup.
What I think is happening
-
Credentials are not transferred with workflow exports. The workflow JSON only contains a credential reference (id + name), not the encrypted token blob. This is expected behavior.
-
Source Control & Environments explicitly excludes credentials. Per the official docs ( External secrets | n8n Docs ): “The feature doesn’t support using different credentials in different instances.”
-
Microsoft Entra uses refresh token rotation. Each refresh call invalidates the previous refresh_token and issues a new one. So if the same credential record exists on two instances (dev + rec), whichever instance refreshes first burns the other’s token, resulting in “refreshToken is required” on the second one. This is documented in issue #26453 ( Microsoft Outlook OAuth2 token refresh fails after ~1 hour on n8n Cloud, masked by dummy.stack.replace error · Issue #26453 · n8n-io/n8n · GitHub ): “Microsoft Entra ID replaces refresh tokens with a fresh token upon every use. If n8n doesn’t save the new refresh token, subsequent refresh attempts may fail.” It is also reproduced on the Entra ID node specifically in community thread #193787 ( Entra ID node reconnection issues ) and issue #14426 (Microsoft Entra Component auth failure. · Issue #14426 · n8n-io/n8n · GitHub).
The node is an HTTP Request node pointing to https://graph.microsoft.com/v1.0/users/{id}/chats with a Microsoft Entra ID (Azure Active Directory) API predefined credential type.
Workflow
WORKFLOW INPUT → LIST CHAT BY USERID (HTTP Request, Graph API, fails here) → SPLIT OUT LIST VALUE → LOOP OVER CHATS → FILTER CHAT BY TOPIC → if true: GET CHAT MEMBERS → USERS INFOS / if false: OFF TOPIC CHAT NAME → END OF LOOP.
Welcome @Rodolphe24 to our community! I’m Jay and I am a n8n verified creator.
Your root cause analysis is exactly right. Microsoft Entra ID uses refresh token rotation, so whichever environment calls the token endpoint first invalidates the token on the other. The fix is to treat each environment as a completely separate OAuth app - create a distinct App Registration in Azure for dev and another for rec, each with its own Client ID/Secret and its own redirect URI pointing to that environment’s n8n instance. Never share the same credential record across instances. Once you’ve set that up, each environment manages its own refresh cycle independently and the token invalidation stops.
Good morning @Rodolphe24
I would also avoid promoting workflows expecting the credential to go along with it. What I usually do in these scenarios is keep the same logical name for the credential across dev/rec/prod, but reconnect/create the credential locally on each instance using that environment’s App Registration. This way the workflow remains easy to promote via Source Control, but each environment maintains its own OAuth state and its own token refresh cycle. It’s also worth checking if the imported workflow is pointing to the correct credential in the target environment after the pull/deploy.
Thanks for the input — that’s actually the pattern I’m already running:
-
Same logical credential name across dev/rec/prod
-
Separate Azure App Registration per environment
-
Each credential reconnected locally on its own instance
After the deploy, the workflow does point to the correct credential on the target.Before publishing the workflow i’ve already launched it with success.That why i don’t understand…
@Rodolphe24
I would investigate two things: whether the credential is actually receiving a refresh token at the time of reconnection, especially with the correct offline_access/admin consent, and whether all containers/workers of the same instance use the same N8N_ENCRYPTION_KEY.
Hi , thank you for your feedback. Could this be related to an issue with an n8n worker? When I run the workflow manually, it works correctly. However, when I trigger the main workflow using a scheduler node after publishing it, I encounter a refresh token error.
Yes, this is almost certainly a worker issue. When a scheduled workflow runs via a worker, the worker needs the exact same N8N_ENCRYPTION_KEY as the main instance to decrypt stored credentials. If they differ, the token decryption fails and you get a refresh token error. Check your worker’s environment variables and confirm N8N_ENCRYPTION_KEY matches the main instance. Also make sure the worker has access to the same database where the credentials are stored - a worker connecting to a different DB won’t see the token at all.
Observation about refreshToken error
I performed several tests related to the refreshToken is required error:
-
Test 1:
On the n8n-rec instance with read-only permissions, launching the workflow fails with the following error:
refreshToken is required
-
Test 2:
On the n8n-rec instance with read/write permissions, launching the workflow produces the same error:
refreshToken is required
-
Test 3:
After manually reconnecting Microsoft Entra ID on the n8n-rec instance with read/write permissions, the workflow launches successfully without any error.
The error never appends in n8n-dev instance with read/write permissions,workflows published.
@Rodolphe24 Great test breakdown. Your Test 3 result makes sense — when you manually reconnect the credential on n8n-rec, Microsoft issues a fresh OAuth token that includes offline_access scope (needed for refresh token). The old credential stored in n8n-rec likely had an expired or scope-limited token from when it was first set up.
The key takeaway: if reconnecting on n8n-rec with read/write works, the original credential was missing the offline_access scope. To avoid this recurring, make sure your Azure App Registration has that scope enabled and re-authorize on each instance separately.
- Create separate App Registration in Azure: One for Dev, one for Rec, one for Prod.
- Inject your client configuration into your different n8n server instances using standard environment variables:
MICROSOFT_CLIENT_ID
MICROSOFT_CLIENT_SECRET
MICROSOFT_TENANT_ID
- In your HTTP Request node, switch the Authentication type to Generic Credential Type → OAuth2.
- In the credential configuration fields, use n8n expressions to reference your environment variables:
- Client ID:
{{$env.MICROSOFT_CLIENT_ID}}
- Client Secret:
{{$env.MICROSOFT_CLIENT_SECRET}}
Because n8n evaluates environment variables natively per instance, your workflow JSON remains identical across Dev, Rec, and Prod, but each instance talks to its own isolated Azure container.
Let me know if this works for you, else, I have another solution.
ok , thanks for your feedback i 'm going to test that out.
Hello , thanks for your feedback , it can’t be possible because i have to use the specific authentification based on microsoft graph : Microsoft Entra ID (Azure Active Directory) API which based on oauth2 too
Glad to hear my reply was helpful and selected as the solution – that really made my day!
If you run into any more questions around this topic (or other n8n setups), feel free to ping me, I’m happy to dig in further.
@Rodolphe24
After the deploy, before clicking “Reconnect”, does the REC credential still contain a valid OAuth state and is it the same credential used by the scheduled execution?
If possible please share the deployment method, the REC architecture (single instance or queue mode/workers/multiple containers), the evidence before reconnect, full log of the first scheduled execution after the deploy.