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:

ClaimMeaning
issAlways flux-server
subSubject identifier of the original principal
principal_issuerProvider that issued the principal (flux, OIDC issuer URL, …)
exec_idThe execution this token is scoped to
scopeAlways execution — distinguishes it from API-key JWTs
act.on_behalf_ofFree-form label such as schedule:nightly-rollup
iat / expIssued-at and absolute expiry
jti32-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:

  1. FLUX_EXECUTION_TOKEN_SECRET environment variable.
  2. security.execution_token_secret in flux.toml.
  3. In debug mode only, an ephemeral 64-hex secret generated at first mint and held in memory.
  4. Otherwise, RuntimeError at 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