temporalio/temporal
Security
This page summarises the authentication, authorization, and trust boundaries the server enforces. Every concrete extension point is pluggable — operators inject their own implementations via temporal.ServerOption.
Trust boundaries
graph LR
Client[SDK / CLI / UI<br/>untrusted] -->|TLS + JWT| FE[Frontend]
FE -->|TLS + mTLS| H[History]
FE -->|TLS + mTLS| M[Matching]
H -->|TLS + mTLS| M
H -->|TLS + cluster cert| Other[Peer cluster]
Workers[Internal Worker] -->|TLS + service cert| FE- Public ingress is the Frontend. Everything outside the cluster talks here.
- Internal traffic (Frontend ↔ History ↔ Matching, replication between clusters) is mutually-authenticated TLS in production.
- The Internal Frontend variant exists specifically so cluster-internal traffic can be routed away from the public-facing Frontend.
Authentication
TLS is configured per gRPC listener under the tls: block of YAML config. The implementation lives in common/rpc/encryption/.
Two TLS surfaces:
- Server TLS — every gRPC server (Frontend, History, Matching) runs TLS.
- Client TLS — internal clients in
client/carry mTLS certificates so peers can identify them.
JWT authentication is handled by the ClaimMapper and Authorizer interfaces in common/authorization/. The default noopAuthorizer accepts everything; production deployments inject a JWT-based one.
// from cmd/server/main.go
authorizer, _ := authorization.GetAuthorizerFromConfig(&cfg.Global.Authorization)
claimMapper, _ := authorization.GetClaimMapperFromConfig(&cfg.Global.Authorization, logger)
audienceMapper, _ := authorization.GetAudienceMapperFromConfig(&cfg.Global.Authorization)The flag --allow-no-auth is required when running with the noop authorizer; otherwise the server warns loudly that future versions will reject this configuration.
Authorization
The Authorizer interface receives a Claims plus the target namespace and API name. Standard implementation patterns:
- JWT scopes — claims contain a list of
namespace:operationpermissions. - Per-namespace ACL — claims map to a role with a stored permission set.
- Custom plugins — operators implement the interface with their internal IAM system.
Source: common/authorization/. The interceptor that enforces it is wired into Frontend's gRPC handler stack.
Per-namespace authorization
Namespaces are the primary administrative boundary. Most production policies are written per-namespace; the authorizer receives the resolved namespace ID along with the claims so it can answer cleanly. Special "system" namespaces (e.g. temporal-system) host internal workflows and have their own policy.
Replication trust
Cross-cluster replication uses mutual TLS. Each peer cluster's address and certificate are stored in the cluster_metadata table; the cluster bootstrap reads them and constructs gRPC clients with the right credentials. See common/cluster/ and common/rpc/encryption/.
Sensitive data handling
- Payload encryption is the SDK's responsibility, not the server's. Workflows can encrypt/decrypt payloads using a
DataConverter; the server only sees opaque bytes. - Logs and metrics are filtered by
common/log/tag/— workflow IDs and namespaces are emitted, payloads are not. - Visibility search attributes are user-supplied and are visible in queries; sensitive material should not be a search attribute.
Rate limits as a security control
Several rate limiters exist — see common/quotas/. They enforce per-namespace, global, and per-API limits. Beyond DoS protection they also bound the blast radius of a misbehaving client.
Common pitfalls
- Forgetting
--allow-no-auth— the server runs but logs warnings every minute. - Cluster certificate rotation — needs to land on every cluster simultaneously; operationally awkward.
- Custom authorizers throwing panics — wrap every authorizer call in a recover, otherwise a single bad token can crash the host.
Where to read more
- Frontend service — request-handling pipeline including auth.
- Replication — cross-cluster trust.
- Reference → configuration — the
tls:andauthorization:blocks.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.