Merged
Size
L
Change Breakdown
Feature70%
Refactor30%
#28027feat(core): Add JWKS resolver for fetching and parsing JWK Set URLs (no-changelog)

JWKS key sources now fetched and cached automatically

JWKS key sources now fetched and cached automatically

n8n gains the ability to fetch signing keys directly from external identity provider JWKS endpoints, with automatic caching based on server hints.

n8n instances configured to trust keys from external identity providers previously hit a wall: JWKS-type key sources were recognized but silently skipped during refresh cycles, leaving the trusted_key table empty despite the configuration. This PR removes that limitation by adding a dedicated resolver that fetches remote JWKS endpoints, validates the signing keys within, converts them to PEM-encoded material for database storage, and respects the cache expiry hints sent by the identity provider.

When a JWKS source is encountered during refresh, the new resolver retrieves the JWK Set from the configured URL, filters out encryption-only keys, symmetric keys, and anything without a proper key ID. For keys that pass validation, the algorithm is inferred from the key type and curve when not explicitly declared — RSA becomes RS256, P-256 curves map to ES256, and so on. Each valid key is converted to standard PEM format and stored alongside its issuer, audience, and role metadata.

The observed cache TTL is computed from three sources in order of priority: the Cache-Control max-age header from the JWKS endpoint, the configured cacheTtlSeconds on the source itself, or a default of 3600 seconds. This value is clamped between 60 seconds and 24 hours, then persisted back to the source configuration so the next refresh cycle respects the identity provider's guidance on how long those keys remain valid.

This work completes Phase 2a of the OAuth 2.0 Token Exchange initiative, which began with database infrastructure for trusted keys and continued with a DB-backed service featuring leader refresh. The JWKS resolver bridges external key sources and the internal TrustedKeyData format used by the trusted_key table.

View Original GitHub Description

Summary

Adds a JwksResolverService that fetches JWKS endpoints, validates and filters signing keys, converts them to PEM-encoded key material, and determines cache TTL from Cache-Control headers. This is the bridge between external identity provider JWKS URLs and n8n's internal TrustedKeyData format used by the trusted_key table.

This is part of the OAuth 2.0 Token Exchange initiative (Phase 2a — Embed flow). The previous PRs added the DB infrastructure for trusted keys (#28097) and the DB-backed TrustedKeyService with leader refresh (#28136). This PR implements the JWKS resolution layer so that jwks-type key sources are no longer skipped during refresh — they now fetch, parse, and persist keys from remote JWKS endpoints.

Key implementation decisions

  • JwksResolverService is a standalone @n8n/di service with a resolveKeys() method that accepts a JwksKeySource config and returns resolved keys + TTL + skipped key diagnostics.
  • Algorithm inference: When a JWK lacks an explicit alg field, the service infers it from kty/crv (RSA → RS256, EC P-256 → ES256, EC P-384 → ES384, EC P-521 → ES512, OKP Ed25519 → EdDSA).
  • Key filtering: Skips keys without kid, encryption-only keys (use: "enc"), symmetric keys (kty: "oct"), and keys with unsupported algorithms. Returns detailed skip diagnostics for observability.
  • TTL computation: Cache-Control max-age > source.cacheTtlSeconds > default (3600s), clamped to [60s, 24h]. The observed TTL is persisted back to the source config so refresh scheduling respects it.
  • TrustedKeyService integration: resolveKeysForSource() is now async, dispatches to resolveKeysForJwksSource() for JWKS sources, and persists the observed cacheTtlSeconds on the source entity for future refresh interval computation.
  • JwtAlgorithmSchema exported from token-exchange.schemas.ts so the resolver can validate algorithms against the canonical set.
  • Removed the old integration test that asserted JWKS sources are skipped (they are now fully supported).

How to test manually

To test end-to-end with a real JWKS endpoint (requires a running instance):

  1. Configure a jwks-type trusted key source pointing to an IdP's /.well-known/jwks.json

For example:

export N8N_ENV_FEAT_TOKEN_EXCHANGE=true
export N8N_TOKEN_EXCHANGE_TRUSTED_KEYS='[{"type": "jwks","url": "https://dev-3nz2ealgrt07hg24.eu.auth0.com/.well-known/jwks.json","issuer": "https://dev-3nz2ealgrt07hg24.eu.auth0.com"}]'
  1. Start n8n with the give envvars
  2. Verify keys appear in the trusted_key table with correct PEM material and algorithm and the jwks source in the trusted_key_source table is correct.

Related tickets

closes https://linear.app/n8n/issue/IAM-518 closes

Review checklist

  • PR title and summary are descriptive. (conventions)
  • Docs updated or follow-up ticket created.
  • Tests included.
  • I have seen this code, I have run this code, and I take responsibility for this code.
© 2026 · via Gitpulse