You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/production-deployment/self-hosted-guide/security.mdx
+99Lines changed: 99 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -339,6 +339,105 @@ Related read:
339
339
340
340
-[How to secure a Temporal Service](/security)
341
341
342
+
### What is a TokenProvider Plugin? {#token-provider}
343
+
344
+
The Token Provider component is a pluggable component that attaches an authentication token to outbound cross-cluster RPCs.
345
+
Where the `ClaimMapper` and `Authorizer` plugins protect the receiving end of a request, `TokenProvider` protects the sending end.
346
+
When a Temporal Service replicates Workflows, Schedules, or Namespaces to a peer cluster, `TokenProvider` supplies the bearer token that the peer's `ClaimMapper` validates.
347
+
348
+
A typical approach pairs a JWT-emitting `TokenProvider` on the sender with the [default JWT `ClaimMapper`](#default-jwt-claimmapper) on the receiver.
`GetToken` is called for each outbound cross-cluster connection.
359
+
360
+
-`rpcAddress` is the receiver cluster's `host:port`. Providers commonly use this value as the JWT's `aud` claim to scope each token to a specific receiver.
361
+
-`expiresAt` lets the credential cache rotate tokens before they expire. Return `time.Time{}` if the token never expires.
362
+
363
+
#### Required claims on the receiver
364
+
365
+
Cross-cluster RPCs target the receiver's `AdminService`, which the default `Authorizer` only admits with `Claims{System: RoleAdmin}`.
366
+
Tokens carrying lower roles are rejected.
367
+
368
+
With the default JWT `ClaimMapper`, the token must carry a `permissions` claim with the entry `temporal-system:admin`.
369
+
370
+
```
371
+
{
372
+
"permissions":[
373
+
"temporal-system:admin"
374
+
]
375
+
}
376
+
```
377
+
378
+
A custom `ClaimMapper` can recognize any JWT shape, such as an OAuth-style `scp` scope or a custom claim, and translate it into the same `Claims{System: RoleAdmin}` result.
379
+
380
+
#### Stream lifecycle
381
+
382
+
Cross-cluster replication runs over long-lived gRPC streams.
383
+
The token is attached when a stream is opened, and the receiver's `ClaimMapper` and `Authorizer` evaluate it at that point.
384
+
Already-open streams are not re-checked when the token later expires.
385
+
Rotation and revocation therefore only take effect when a stream is reestablished, for example after a reconnect or a process restart.
386
+
387
+
#### TokenCredentials caching
388
+
389
+
Tokens returned by `GetToken` are cached per outbound connection by `auth.TokenCredentials`.
390
+
The credential refreshes proactively within a configurable grace window before expiry.
391
+
If a fetch fails before the token is hard-expired, the credential falls back to the last cached token.
392
+
393
+
Configure the refresh behavior through `global.authorization.remoteClusterAuth.graceWindow`, a Go duration string such as `30s` or `5m`.
394
+
The default is `30s`.
395
+
396
+
#### Transport security
397
+
398
+
`auth.TokenCredentials` requires transport security, so the gRPC runtime refuses to attach the credential to a plaintext dial.
399
+
Configuring `WithTokenProvider` therefore requires also configuring TLS for the destination, either through [`global.tls.remoteClusters`](/references/configuration) in the YAML config or by passing a custom provider through [`temporal.WithTLSConfigFactory`](/references/server-options#withtlsconfigfactory).
400
+
401
+
:::note
402
+
403
+
If `WithTokenProvider` is set but no remote-cluster TLS source is configured, the Temporal Service fails to boot with a directed error message.
404
+
This catches the misconfiguration at startup rather than on the first cross-cluster RPC.
405
+
406
+
:::
407
+
408
+
#### Fail-closed mode
409
+
410
+
Set `global.authorization.remoteClusterAuth.require: true` to require a non-empty token on every outbound remote-cluster RPC.
411
+
When `require` is `true`, the Temporal Service refuses to start if no `TokenProvider` is configured, and the credential returns `Unauthenticated` rather than sending an empty `authorization` header.
412
+
413
+
#### JWT helpers
414
+
415
+
For providers that emit JWTs, `auth.ParseJWTExpiry(token string) time.Time` extracts the `exp` claim without verifying the signature.
416
+
This lets a `TokenProvider` return the JWT's own expiry as the `expiresAt` so cache rotation tracks the token's real lifetime.
417
+
418
+
#### Configuration
419
+
420
+
Configure your `TokenProvider` with the [`temporal.WithTokenProvider`](/references/server-options#withtokenprovider) server option.
421
+
Pair it with the receiver-side plugins so peers validate what the sender attaches.
When `TokenProvider` is not configured, outbound cross-cluster RPCs carry no `authorization` header.
439
+
This is the default for deployments that don't replicate to peers, or that rely on transport-level (mTLS) authentication alone.
440
+
342
441
## Data Converter {#data-converter}
343
442
344
443
Each Temporal SDK provides a [Data Converter](/dataconversion) that can be customized with a custom [Payload Codec](/payload-codec) to encode and secure your data.
Copy file name to clipboardExpand all lines: docs/references/configuration.mdx
+75Lines changed: 75 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -210,6 +210,81 @@ global:
210
210
- `internode.client.rootCaFiles`
211
211
- `frontend.server.clientCaFiles`
212
212
213
+
### authorization
214
+
215
+
The `authorization` section configures the Temporal Service's authentication.
216
+
It selects the pluggable components that validate incoming gRPC tokens, the signing keys to trust, and the credentials this server attaches to outbound cross-cluster replication RPCs.
217
+
218
+
It contains two structural subsections that mirror the direction of traffic:
219
+
220
+
- [`jwtKeyProvider`](#jwtkeyprovider): Supplies the signing keys used to verify inbound JWTs.
221
+
- [`remoteClusterAuth`](#remoteclusterauth): Controls the bearer tokens attached to outbound cross-cluster RPCs.
222
+
223
+
The top-level fields select and tune the inbound plugins:
224
+
225
+
- `authorizer`- _string_ - _Default:_ `""`.
226
+
Selects the inbound authorizer. Empty string disables authorization (the no-op authorizer permits every request); `default` enables Temporal's built-in role-based authorizer. The value is case-insensitive.
227
+
- `claimMapper`- _string_ - _Default:_ `""`.
228
+
Selects the `ClaimMapper` that extracts roles from a verified token. Empty string disables claim mapping; `default` enables the built-in JWT `ClaimMapper`.
229
+
- `audience`- _string_ - _Default:_ `""`.
230
+
Required `aud` claim value that inbound JWTs must contain. When empty, audience validation is skipped.
gRPC metadata header from which the `ClaimMapper` reads the bearer token.
233
+
234
+
See [How to secure a Temporal Service](/self-hosted-guide/security) for the conceptual model behind `ClaimMapper`, `Authorizer`, and `TokenProvider` and how the plugins fit together.
235
+
236
+
A minimal example that enables JWT-based inbound auth using Temporal's defaults:
237
+
238
+
```yaml
239
+
global:
240
+
authorization:
241
+
jwtKeyProvider:
242
+
keySourceURIs:
243
+
- https://idp.example.com/.well-known/jwks.json
244
+
refreshInterval: 1m
245
+
authorizer: default
246
+
claimMapper: default
247
+
audience: temporal-frontend
248
+
```
249
+
250
+
#### jwtKeyProvider
251
+
252
+
Configures the source of signing keys used by the default `ClaimMapper` to verify inbound JWTs.
253
+
254
+
- `keySourceURIs`- _list of strings_.
255
+
URLs to fetch JWKS-formatted public keys from. The default `ClaimMapper` fetches and caches the union of keys returned by each URI.
How often the key set is refetched. Zero (the default) disables periodic refresh, so keys are loaded once at startup and never rotated.
258
+
259
+
#### remoteClusterAuth
260
+
261
+
Controls outbound bearer tokens carried on cross-cluster RPCs by a [`TokenProvider`](/self-hosted-guide/security#token-provider).
262
+
This block has no effect unless a `TokenProvider` is also configured via [`temporal.WithTokenProvider`](/references/server-options#withtokenprovider).
263
+
264
+
- `require`- _boolean_ - _Default:_ `false`.
265
+
When `true`, every outbound cross-cluster RPC must carry a non-empty token; the credential returns `Unauthenticated` rather than sending an empty `authorization` header.
266
+
The Temporal Service refuses to start when `require` is `true` but no `TokenProvider` is configured.
0 commit comments