temporalio / temporalio/temporal
Default JWT ClaimMapper: support nested/dotted claim paths (e.g. ext.permissions for Ory Hydra / JumpCloud)
@simvlad is already working on this.
Since Apr 16, 2026.
- Dominant language
- Go
- Stars
- 23.2k
- Forks
- 1.9k
- Avg merge
- 2d 8h
- Merged PRs (30d)
- 228
Description
Is your feature request related to a problem? Please describe.
The default JWT ClaimMapper cannot read claims that are nested inside an object (such as ext.permissions). It only supports top-level claim names via permissionsClaimName.
This is a blocker when using OIDC providers built on Ory Hydra (including JumpCloud, Ory itself, and others). Hydra-based providers place custom session data / scope-added claims under an ext (extensions) object in JWT access tokens — this is by design in Hydra and cannot be changed from the provider side.
Example JWT access token from JumpCloud:
{
"aud": [],
"client_id": "xxx",
"sub": "xxx",
"scp": ["openid", "email", "profile", "permissions"],
"ext": {
"memberOf": "Cloud Ops",
"permissions": "admin:default"
}
}
With the default config (permissionsClaimName: permissions), the ClaimMapper returns empty claims because the top-level permissions key doesn't exist. The Authorizer then denies every request with Request unauthorized. Debug logs in the frontend show no evidence of the token even being parsed successfully.
The ID token from Hydra does have top-level claims, but the Temporal Web UI forwards the access token (not the ID token) to the gRPC frontend via the standard authorization metadata. Setting authHeaderName: authorization-extras server-side doesn't help because the Web UI doesn't populate that metadata key.
Related but distinct:
- #7560 (regex parsing of permissions — different parsing problem)
- #8218 (configurable subject claim name — closed, different scope)
Describe the solution you'd like
Allow permissionsClaimName (and ideally other claim name configs) to accept a dotted path, e.g. ext.permissions, resolved against the parsed JWT claims map. Falls back to a flat key lookup for backward compatibility.
Example config:
authorization:
jwtKeyProvider:
keySourceURIs:
- https://oauth.id.jumpcloud.com/.well-known/jwks.json
permissionsClaimName: ext.permissions # <-- dotted path
authorizer: default
claimMapper: default
Implementation would be a small change in common/authorization/default_jwt_claim_mapper.go to traverse dotted paths when extracting the permissions claim.
Describe alternatives you've considered
- Custom ClaimMapper plugin — requires maintaining a custom Temporal server build and Docker image for a feature that is common to all Hydra-based providers.
- Switching to an OIDC provider that places custom claims at the top level — not practical for orgs already using JumpCloud as their IdP.
- OIDC token-exchange proxy — adds infrastructure complexity for what is effectively a 5-line code change in the server.
Additional context
- Temporal server version:
1.29.2 - Example affected providers: JumpCloud, Ory Hydra (self-hosted), any Hydra-based OIDC
- Ory Hydra reference: custom claims under
extis documented behavior —session.access_tokendata becomesextin the JWT
Happy to contribute a PR if this is a welcome change.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.