OAuth2 credential with dynamic token URL only evaluated once in loop (tenant ID not re-evaluated)

The problem/error/question

I’m trying to loop through multiple Microsoft Entra tenants (customers) in n8n and retrieve license usage (or perform other tenant-scoped Graph operations) using client credentials.

I’ve created a Generic OAuth2 credential where the Access Token URL is set using an expression:

https://login.microsoftonline.com/{{$json["id"]}}/oauth2/v2.0/token

The credential uses a multi-tenant Enterprise Application (client ID + secret), and the workflow loops over tenant IDs using Split in Batches.

The issue I’m seeing is that only the first iteration of the loop evaluates the expression. After that, the credential appears to cache the token and/or token URL, so all subsequent requests use the same tenant’s access token, even though the input item ($json["id"]) changes.

My expectation is that for each loop iteration, the OAuth credential would:

  • Re-evaluate the Access Token URL expression

  • Request a new token scoped to the current tenant ID

Instead, it behaves as if the credential is evaluated once per workflow execution.

Is this:

  • A known limitation of OAuth credentials (expressions evaluated once)?

  • Token caching behaviour by design?

  • Or a bug?

A similar issue was discussed here but never resolved: Expression in credentials - only uses first item

Workflow:

Information on n8n setup

  • n8n version: 2.1.5

Thanks in advance for any assistance!

Hi @frzn,

The only way I can see this work, if I understand your problem correctly, is to do a token request manually inside the loop, before you make an api call.

Is my understanding correct that you have multiple client credentials and you are trying to call a service for each of them using their own auth?

Not sure if Im missing something

With Microsoft GDAP and a multi-tenant application that has already been admin-consented in each customer tenant, it’s valid to use the same client ID and client secret for all customers.
Authentication is tenant-scoped purely by the token endpoint being called, for example:

https://login.microsoftonline.com/{customerTenantId}/oauth2/v2.0/token

The client credentials do not change between tenants; only the token URL does.
The issue I’m seeing in n8n is not around credentials themselves, but that the OAuth2 credential appears to be evaluated once per workflow execution. The Access Token URL expression inside the credential is only resolved on the first loop iteration and then reused, so subsequent iterations continue using the first tenant’s token even though the input item ($json[“id”]) changes.
This makes it impossible to use a Generic OAuth2 credential for tenant-scoped client-credentials flows inside a loop.