Execution tokens
HMAC-signed execution-scoped tokens — issuance, claims, lifetime, and how they enable workers to act on behalf of a running execution.
An execution token is a JWT the server mints for one specific workflow execution. The worker carries it back to the server whenever a running workflow needs the API — to fetch a secret, read a config, dispatch a sub-workflow, or write a checkpoint. The token names both the execution and the principal who started it, so every callback is attributable to a real caller, not the worker. The provider is always registered; the server mints tokens at dispatch time when auth is enabled.
How they are issued
The server mints a token at dispatch time. From flux/security/execution_token.py:
exec_token = mint_execution_token(
subject=principal.subject, # the principal who triggered this run
principal_issuer="flux",
execution_id=ctx.execution_id,
on_behalf_of=f"schedule:{name}", # what caused the dispatch
)
The token is persisted on the ExecutionContextModel row and shipped down the SSE stream in the dispatch payload. The worker reads it via ctx.set_exec_token(...) (flux/worker.py) and uses it for every server-bound call during the run. flux/server.py mints at three points: POST /executions, scheduled triggers, and resume dispatch.
What is inside
A standard HS256 JWT with these claims:
| Claim | Meaning |
|---|---|
iss | Always flux-server |
sub | Subject identifier of the original principal |
principal_issuer | Provider that issued the principal (flux, OIDC issuer URL, …) |
exec_id | The execution this token is scoped to |
scope | Always execution — distinguishes it from API-key JWTs |
act.on_behalf_of | Free-form label such as schedule:nightly-rollup |
iat / exp | Issued-at and absolute expiry |
jti | 32-hex token ID for log correlation |
ExecutionTokenProvider.authenticate requires exp, iss, sub, scope, exec_id, and principal_issuer to be present, then looks the principal up in the registry. A disabled or missing principal rejects the token even if the signature is valid.
Lifetime
Execution tokens have a fixed TTL, not an execution-bound one. The default is 604800 seconds (seven days):
[flux.security]
execution_token_ttl = 604800
The TTL is read at mint time. Tokens are not re-issued when a workflow pauses or runs past its TTL — if a paused execution resumes after expiry, callbacks fail authentication.
The signing secret
The HMAC secret is separate from the encryption key. Resolution order:
FLUX_EXECUTION_TOKEN_SECRETenvironment variable.security.execution_token_secretinflux.toml.- In debug mode only, an ephemeral 64-hex secret generated at first mint and held in memory.
- Otherwise,
RuntimeErrorat first use.
Production servers must set the secret explicitly. The debug fallback is reset on every process restart, which invalidates every outstanding token.
Audit trail
ExecutionTokenProvider returns a FluxIdentity whose subject is the original principal — not the worker — and whose metadata carries token_type: "execution", the exec_id, the principal_id, and the jti. Permission checks use the caller’s roles, and audit entries can be joined back to both the execution and the principal that started it.
Failure modes
- Token expires mid-run. Long-pause workflows whose TTL elapses before resume fail callbacks with
Execution token expired. Raiseexecution_token_ttlif you run workflows that pause longer than the default. - Signing secret rotated. Changing
execution_token_secretinvalidates every in-flight token immediately — running workers will see 401s on checkpoint. Drain executions before rotating. - Cross-execution use. The token is bound to one
exec_idand one principal. The server still authenticates the principal, but theexec_idin token metadata will not match the targeted execution, so anyexec_id-scoped permission check rejects the call.