Skip to main content

Webhook Authentication

The platform and the workflow engine authenticate each other in both directions, and with two different secrets. Understanding the split explains why a forged webhook or a stray callback can't do damage — and it's a common point of confusion worth making precise.

Outbound: signing the dispatch (HS256 webhook JWT)

When the platform dispatches a run to the engine's webhook, it signs a short-lived JWT: HS256, 60-second expiry, signed with a per-engine webhook shared secret (from an environment variable keyed by engine slug). The token's payload carries the workflow_execution_id (as sub) and iss: circus, and it travels as an Authorization: Bearer header. The engine's Webhook node is configured to verify it with the same secret (HS256, passphrase key type). If the secret is unset, dispatch is sent unauthenticated — useful for local development, but you'd set it for anything real.

On the engine side, the Init node re-validates that token strictly (subject matches the execution, issuer is Circus, timestamps sane). Notably, a validation failure there does not trigger a /terminate — a forged or mismatched token can't be trusted to identify a real execution, so acting on it could hit the wrong run.

Inbound: authenticating callbacks (API Key)

When the engine calls back — logging steps, completing, terminating — it authenticates with an API Key: a JWT signed with workflow_jwt_secret, carrying a jti for revocation and expiring in 30 days. This is a different secret from the webhook signing secret, and it flows the other way. The machine-facing endpoints use their own middleware, separate from the operator JWT flow.

Why two secrets, two directions

The two-secret design mirrors the two-direction reality: signing a dispatch (platform proving itself to the engine) and authenticating a callback (engine proving itself to the platform) are distinct trust relationships, and conflating them would weaken both. It also sits inside the platform's broader authentication model, which keeps human and machine auth strictly separate. For the workflow-developer's side of configuring the webhook JWT in n8n, see the Workflow Developer package.