Token exchange identity resolution goes live

External tokens can now map directly to n8n users — first via identity lookup, then email matching, and as a last resort, automatic provisioning with personal projects included.
Token exchange in n8n just became functional. Previously a stub that threw "not implemented," the IdentityResolutionService now handles the full workflow for mapping external identity claims to internal users.
The resolution algorithm tries three paths in order: first, it checks if the external sub claim is already linked to a user via the token-exchange provider. If not found, it falls back to matching by email — useful when a user already exists in n8n but hasn't connected this external identity yet. When neither match succeeds, the service provisions a new user, creates a personal project, and links the identity — all in a single database transaction.
Role handling adds guardrails without blocking logins. Existing owners can never have their role changed via token exchange. Other existing users keep their current role if the claimed role isn't in the key's allowedRoles whitelist. New users default to global:member unless a valid role claim is present and permitted — if not, an error is thrown rather than leaving the user in an ambiguous state.
Three new audit events track the lifecycle: token-exchange-identity-linked when email fallback connects a new sub to an existing user, token-exchange-user-provisioned when JIT creates a fresh user, and token-exchange-role-updated when role changes propagate.
This lands in the @n8n/cli package as part of the OAuth 2.0 Token Exchange initiative (Phase 2a — Embed flow). External systems that issue tokens can now authenticate users into n8n without passwords, managing identity their way while n8n handles the user record.
View Original GitHub Description
Summary
Implements IdentityResolutionService that resolves verified external token claims (sub) to an n8n user. This replaces the skeleton stub that previously threw "not implemented".
Part of the OAuth 2.0 Token Exchange initiative (Phase 2a — Embed flow). External systems identify users by their own IDs (sub claim). This service maps those to internal n8n users — linking on first encounter and keeping profiles in sync on subsequent exchanges.
Resolution algorithm
- Known sub —
AuthIdentitylookup bysub+token-exchangeprovider → return linked user - Email fallback — no identity match but email matches existing user → create
AuthIdentitylink, return user - JIT provision — no match at all → create user + personal project +
AuthIdentityin a single transaction
Role handling
- Role claim validated against the key's
allowedRoleswhitelist global:ownercan never be assigned via token exchange (existing owners keep their role, new users are rejected)- Existing users keep their current role when the claimed role is invalid or not allowed — login is never blocked due to role mismatch
- New users get
global:memberby default when no role claim is present
Other changes
TokenExchangeService.verifyTokennow returns{ claims, resolvedKey }soembedLogincan passallowedRolesto identity resolution- Three new audit events:
token-exchange-identity-linked,token-exchange-user-provisioned,token-exchange-role-updated
How to test manually
- Configure a trusted key with
allowedRoles: ['global:member', 'global:admin'] - Generate a JWT with
sub,email, and optionalroleclaim signed by the trusted key - Call
POST /rest/auth/embedwith{ "token": "<jwt>" } - Verify:
- First call with a new
sub+ known email links the identity and returns the existing user - First call with a new
sub+ unknown email creates a new user with personal project - Subsequent calls with the same
subresolve via identity lookup (Path 1) - Role updates are applied when the claim is in
allowedRoles global:ownerrole claim is silently ignored for existing users and rejected for new users
- First call with a new
- Check audit events are emitted for linking, provisioning, and role changes
Related tickets
Review checklist
- PR title and summary are descriptive. (conventions)
- Docs updated or follow-up ticket created.
- Tests included.
- PR Labeled with
Backport to Beta,Backport to Stable, orBackport to v1(if the PR is an urgent fix that needs to be backported)