n8n-nodes-entra-token
v0.1.0
Published
Microsoft Entra ID client-credentials for n8n, with the token cached and refreshed before it expires instead of after it fails
Downloads
156
Maintainers
Readme
n8n-nodes-entra-token
A Microsoft Entra ID client-credentials credential for n8n that caches the token and refreshes it before it expires, instead of after a request fails.
Drop-in for the HTTP Request node: pick it under Predefined Credential Type.
Why
n8n's built-in OAuth2 credential refreshes reactively. It sends whatever token it has stored, waits for the rejection, then fetches a new one. It also does not coordinate: seven items in one node produce seven separate token requests.
Measured on n8n 2.35.7, same workflow, same identity provider, six cycles of seven items each:
| | Token requests | Successful calls | Rejections | |---|---|---|---| | n8n's built-in path | 41 | 42 | 35 | | With this credential | 6 | 42 | 0 |
Same useful work. 85% fewer requests to the identity provider, and every 401 disappears because the token is renewed before it is needed.
Against a provider that rate-limits, those 41 requests are what earns a 429,
and a burst of them arrives precisely when tokens expire together.
Install
Self-hosted n8n, as a community node:
npm install n8n-nodes-entra-tokenOr Settings → Community nodes → Install and enter n8n-nodes-entra-token.
Configure
Create a credential of type Microsoft Entra ID (cached token).
| Field | Notes |
|---|---|
| Authority | Leave as is unless you are on a sovereign cloud, for example https://login.microsoftonline.us |
| Directory (Tenant) ID | The tenant GUID from your app registration overview |
| Application (Client) ID | |
| Client Secret | Stored encrypted by n8n like any other credential |
| Scope | Must end in /.default. Client credentials on the v2.0 endpoint reject delegated scopes with invalid_scope |
| Refresh Margin (Seconds) | Default 30. How early to renew |
Then in an HTTP Request node: Authentication → Predefined Credential Type → Microsoft Entra ID (cached token).
How it works
The token lives in this package, not in n8n's credential store.
authenticate is used in its function form, which n8n runs once per outgoing
request. That is the only hook that sees a request before it is sent, and
therefore the only place a refresh can happen ahead of expiry. The alternative
hook, preAuthentication, only runs when the stored token is empty or after a
rejection has already happened, which is too late by construction.
Three things the cache does:
Refresh early. Expiry is tracked from the expires_in Entra returns, on a
monotonic clock, and a token is treated as stale one margin before it expires. A
token with two seconds left is useless for a call that takes three, and the
margin also absorbs drift between your clock and Entra's.
Single-flight. When several requests find the token stale at the same moment, the first one fetches and the rest wait for that result. Seven callers, one token request. A waiter re-checks the cache after the lock frees, because a waiter that fetches immediately turns one stampede into seven sequential exchanges, which is worse than no coordination at all.
Key on the whole configuration. Authority, tenant, client, scope, and a hash of the secret. Rotating the secret takes effect on the next call rather than serving a token minted with the old one.
What it does not do
- It is per-process. Two n8n workers mean two caches and two token requests rather than one. A shared cache would fix that and would add a network hop, a serialization format, and a failure mode of its own.
- It does not recover from early revocation. If a token is revoked inside its
stated lifetime, requests fail until it expires on the clock. Reacting to that
needs a hook that sees responses, which the function form of
authenticatedoes not get. - The token request does not use n8n's HTTP helper. The function form is not
given the helper, and a verified community node may not add a runtime
dependency, so the exchange uses Node's global
fetch. Behind a corporate proxy that fetch is not proxy-aware, so the token request may fail where other n8n requests succeed. - It ships one credential, no nodes. Use it from the HTTP Request node.
Reproducing the numbers
Everything above was measured, not estimated. The harness is in spike/:
cd spike
python run_test.py --items 7 --cycles 6 --pause 25 --ttl 20It starts an instrumented fake identity provider, brings up n8n in Docker,
creates the credential and a workflow over the REST API, fires the workflow, and
reports how many token requests actually reached the provider. Point the compose
file at ./custom instead of ./custom-real to measure n8n's built-in path for
comparison.
Development
npm install
npm test # 9 checks on the cache logic, no framework, no network
npm run buildLicence
MIT
