temporalio / temporalio/temporal
ui-server: ListNamespaces/GetClusterInfo return 403 for namespace-scoped admin tokens (requires undocumented "temporal-system:" permission)
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 23.2k
- Forks
- 1.9k
- Avg merge
- 2d 8h
- Merged PRs (30d)
- 228
Description
Expected Behavior
A JWT-authenticated user with a namespace-scoped admin permission (via the default JWT claim mapper / default authorizer, e.g. "permissions": ["my-namespace:admin"]) should be able to load the Temporal Web UI without authorization errors, since they are a full admin of that namespace.
Actual Behavior
ui-server's own backend calls to ListNamespaces and GetClusterInfo (issued on every page load to populate the namespace list / version banner) return 403 Request unauthorized / PermissionDeniedFailure — even for a user holding admin on every namespace that exists. This is not obvious from the docs: a token that is a full admin of all namespaces still cannot use the UI at all, because these two specific calls are gated on a separate, undocumented permission scope.
Steps to Reproduce the Problem
- Start
temporal-serverwithglobal.authorizationconfigured:jwtKeyProviderpointing at a JWKS,claimMapper: "default",authorizer: "default",permissionsClaimName: "permissions". - Issue a JWT (correct
kidmatching the JWKS) with"permissions": ["my-namespace:admin"]. CallDescribeNamespaceonmy-namespacewith this token — succeeds, as expected for an admin. - Call
ListNamespacesorGetClusterInfowith the same token (directly againsttemporal-server, or viaui-serverconfigured withauth.enabled: falseandtemporalGrpcAddresspointed at the server, passing the token as anAuthorization: Bearerheader) — returns403 Request unauthorized, regardless of the namespace-scopedadminrole. - Reissue the token with
"permissions": ["my-namespace:admin", "temporal-system:read"]and repeat step 3 — now returns200 OK.
Specifications
- Version:
temporal-server1.31.2,ui-server2.53.3 - Platform: N/A (reproducible with local/dev persistence, no external dependencies)
Root Cause
ListNamespaces and GetClusterInfo are Scope: Cluster APIs. DefaultAuthorizer.Authorize only consults claims.System for Scope: Cluster requests — claims.Namespaces[...] is never checked for these, no matter the role held there. DefaultJWTClaimMapper only ever populates claims.System from a permission entry whose namespace segment is exactly the literal temporal-system (i.e. primitives.SystemLocalNamespace) — any other namespace-scoped permission, including admin on every namespace individually, has no effect on claims.System.
The result: any deployment using only namespace-scoped permissions (the natural/expected shape for the namespace:role permission format the docs describe) can never satisfy ListNamespaces/GetClusterInfo, so the Web UI is unusable for any user unless they are separately granted the specific, non-obvious temporal-system:read (or higher) permission — a requirement that does not appear to be documented in the JWT/authorization docs.
Suggested Fix / Ask
Either (a) document explicitly that temporal-system:<role> is required for any UI-facing token, since ui-server depends on ListNamespaces/GetClusterInfo internally, or (b) treat admin on the reachable/queried namespace as sufficient for ui-server's own calls, or (c) have ui-server degrade gracefully (skip cluster info / infer the namespace list from what is reachable) instead of surfacing a hard 403 when it lacks system-level read access.
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.
Research direction
Start by tracing ListNamespaces and GetClusterInfo through DefaultAuthorizer.Authorize and DefaultJWTClaimMapper, then inspect how ui-server invokes these calls. Reproduce the 403 with the namespace-scoped token described in the issue and verify the chosen behavior: documented temporal-system access, authorization through reachable namespaces, or graceful UI degradation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- authorization, backend-api-design
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100