[TT-17312] Resolve JWT scope claim name from client-IdP registry#8296
Conversation
A registry-bound IdP can declare a non-default scope_claim_name (e.g. "scp"
for Entra/Azure AD, "roles"). When the API def sets no scope claim name, the
gateway now falls back to the bound IdP's claim before defaulting to "scope".
Without this, a registry-only API whose IdP emits scopes under a non-"scope"
claim would 403 ("no matching policy found") because the gateway read the
wrong claim.
- IdP gains ScopeClaimName (json: scope_claim_name), mirroring the dashboard
model.ClientIdP and the MDCB model (tyk-sink #794).
- Binding denormalises it at rebuild time so the JWT hot path needs no second
registry lookup.
- scopeClaimNameForRequest resolves with manual-wins precedence: API-def /
OAS -> registry binding -> "scope". Manual-config APIs stay byte-identical.
🎯 Recommended Merge TargetsBased on JIRA ticket TT-17312: Gateway: client IdP registry + JWT integration Fix Version: Tyk 5.14.0
Required:
📋 Workflow
|
|
This PR enhances the JWT middleware to resolve the scope claim name from the client-IdP registry. Previously, the gateway only checked the API definition or used a default value ( Files Changed Analysis
Architecture & Impact Assessment
JWT Scope Claim Resolution FlowsequenceDiagram
participant Client
participant Gateway
participant JWTMiddleware
participant IdPRegistry
Client->>+Gateway: Request with JWT
Gateway->>+JWTMiddleware: processCentralisedJWT(request)
JWTMiddleware->>JWTMiddleware: scopeClaimNameForRequest()
Note over JWTMiddleware: 1. Check API Definition for manual config
alt Manual config exists
JWTMiddleware-->>JWTMiddleware: Use value from API definition
else No manual config
Note over JWTMiddleware: 2. Check IdP Registry Binding
JWTMiddleware->>IdPRegistry: Get Matched Binding
IdPRegistry-->>JWTMiddleware: Return Binding
alt Binding has ScopeClaimName
JWTMiddleware-->>JWTMiddleware: Use value from Binding (e.g., "scp")
else Binding has no value
Note over JWTMiddleware: 3. Fallback to default
JWTMiddleware-->>JWTMiddleware: Use default value ("scope")
end
end
JWTMiddleware->>JWTMiddleware: Extract scopes from JWT using resolved claim name
JWTMiddleware-->>-Gateway: Validation successful
Gateway-->>-Client: 200 OK
Scope Discovery & Context ExpansionThis change is part of a larger, cross-repository feature to support custom scope claim names, with related changes in The impact is primarily contained within the JWT authentication flow for APIs associated with an Identity Provider through the registry. The change is backward-compatible, as the new logic only acts as a fallback and preserves the behavior of existing APIs with manual scope configurations. Further investigation could involve checking how the IdP registry is populated (e.g., via Dashboard API or MDCB RPC calls) to ensure the new Metadata
Powered by Visor from Probelabs Last updated: 2026-06-09T19:14:37.332Z | Triggered by: pr_updated | Commit: 5a4f32c 💡 TIP: You can chat with Visor using |
✅ Security Check PassedNo security issues found – changes LGTM. ✅ Architecture Check PassedNo architecture issues found – changes LGTM. ✅ Performance Check PassedNo performance issues found – changes LGTM. ✅ Quality Check PassedNo quality issues found – changes LGTM. Powered by Visor from Probelabs Last updated: 2026-06-09T19:14:36.086Z | Triggered by: pr_updated | Commit: 5a4f32c 💡 TIP: You can chat with Visor using |
🚨 Jira Linter FailedCommit: The Jira linter failed to validate your PR. Please check the error details below: 🔍 Click to view error detailsNext Steps
This comment will be automatically deleted once the linter passes. |
|



Description
A registry-bound IdP can declare a non-default
scope_claim_name(e.g.scpfor Entra/Azure AD,roles). Until now the gateway resolved the scope claim name only from the API def / OAS, defaulting to"scope". So a registry-only API whose IdP emits scopes under a non-scopeclaim — with no manual scope config — would403(no matching policy found) because the gateway read the wrong claim.This wires the dashboard's new
scope_claim_namefield (TykTechnologies/tyk-analytics#5788) through the gateway registry so it's actually consumed.Changes
IdPgainsScopeClaimName(json:"scope_claim_name"), mirroring the dashboardmodel.ClientIdPand the MDCB model (tyk-sink#794). Picked up automatically on both feeds (Dashboard envelope + RPCunmarshalIdPs) — no transport change.Bindingdenormalises it from the IdP atrebuildtime, so the JWT hot path needs no second registry lookup (same approach already used forScopeToPolicy).scopeClaimNameForRequestresolves with manual-wins precedence: ClassicGetScopeClaimName/ OAS → registry binding →"scope". The fallback only fires when the API def sets nothing, so manual-config APIs stay byte-identical.Cross-repo
model.ClientIdP.ScopeClaimNamemodels.ClientIdP.ScopeClaimNameIdP.ScopeClaimNameVerified end-to-end: the MDCB RPC read path (
LoadClientIdPs→filterAndPruneClientIdPs→pruneIdP) uses full-document loads and shallow struct copies, so the field is carried through with no projection dropping it.How this has been tested
New tests (TDD, race-clean):
TestIdPRegistry_RebuildCarriesScopeClaimName— propagation into the binding.TestScopeClaimNameForRequest— the three-tier resolution order (manual wins → binding → default).TestIdPRegistry_JWT_ResolvesScopeClaimNameFromRegistry— end-to-end: token with scopes underscp, no manual scope claim → 200.TestIdPRegistry_JWT_NoScopeClaimNameRejects— counterpart proving the same setup with no IdPscope_claim_namefalls through to"scope"and 403s, pinning down that the registry fallback is what flips the result.Types of changes