Authentication Model: Human vs. Machine
The platform authenticates two fundamentally different callers — human operators and machines (workflow engines) — and treats them as separate concerns throughout: separate secrets, separate middleware, separate revocation. That separation is the core of the auth model.
Two token classes, two secrets
- Human operator auth uses JSON Web Tokens signed with
user_jwt_secret, delivered as an HttpOnly session cookie. This protects the operator UI and the Core API. - Machine auth uses API Keys — JWTs signed with
workflow_jwt_secret— for the engine↔platform machine API.
The two secrets are distinct and must never be identical (enforced at startup). Keeping them separate means compromising or rotating one class of credential never touches the other.
Revocation is JTI-based, per class
Both classes embed a jti (JWT ID) and revoke by denylisting the jti, not by storing raw tokens. Human JWT revocation and API Key revocation are separate flows over the same idea. For API Keys, only the jti, display fragments, and an expiry are stored — never the full secret (shown once at creation). Revocation is immediate, and keys also auto-expire in 30 days.
Account security
For human accounts, the model supports optional TOTP two-factor authentication (QR enrollment, hashed backup codes) and password changes gated on the current password plus a 2FA code when enabled. This account-security subsystem is kept separate from machine-auth/API-key logic — again, the human/machine split, all the way down.
Where it fits
Two consequences are worth naming. First, this is why the platform exposes distinct API surfaces with distinct middleware (see The Four API Surfaces) — the operator-JWT surfaces and the API-Key surface are different trust domains sharing one server. Second, the machine side extends into webhook authentication, where dispatch signing adds a third secret for the platform-to-engine direction. The unifying principle is simple: never let human sessions and machine credentials share a secret, a middleware, or a revocation path. (The platform is single-operator in this version; the model is built to stay clean rather than to imply multi-user, which is out of scope.)