Run the roles separately

Use Temporal UI with separate roles

Management authenticates the user while an edge reaches Temporal and opens authorized payloads.

For: cluster operators.

Management authenticates the user while an edge reaches Temporal and opens authorized payloads.

Temporal's UI

/temporal/ on the management port is Temporal's own console, for admins, in one server and with the roles apart. With several Temporal backends it goes through the edge's router: each tenant's namespace shows the workflows of its own backend, and after a move those of both, under the names the platform gives them. The namespace list shows the default backend's; open another tenant's namespace by its name.

The UI shows payloads in the clear when the edge can open them. Its page sends each payload to a codec on its own origin, /temporal/codec/decode, which opens the tenant layer (with encrypted payloads), data subjects' payloads and what External Storage keeps, as the edge's /codec endpoint does for the Temporal Cloud UI.

Like the UI, it is for admins, who have the content permission on every tenant; a member without the admin role is refused even with the content permission. Every decode is an audit entry (payload.decode).

It takes the session you signed in with only from the UI's own page: a request from another origin, or without the X-Namespace header the UI sends, is refused. With the roles apart, management checks that, then hands the request to an edge, which holds the keys.

Every answer under /temporal/ carries a Content-Security-Policy of the server's own, since the UI runs on the console's origin, beside any policy the UI's server sends (a browser enforces both).

The UI's page runs only the start-up script this server ships, by its hash, and the modules that script loads; no other script runs, not even one served from this origin.

Any other HTML under /temporal/, such as the markdown the UI renders in a frame of its page, runs no script at all (it is sandboxed) and only this origin's pages may frame it.

The page loads its styles, fonts and images from this origin (images also as data: URIs), starts no worker, sends requests only to this origin (its API and the codec above), is never shown in a frame (frame-ancestors 'none'), and is not sniffed for another content type (X-Content-Type-Options: nosniff).

So a codec server set in the UI's own settings on another address is not reached from this page; use the codec on its own origin, which is set already.

On this page
Copyright © 2026