Security model
Trust boundaries, credentials, authorization, tenant isolation, secret sealing, egress controls, webhooks, and a production-hardening checklist.
Security in an orchestrator is mostly about who may cause which side effect. A workflow definition can make HTTP calls, query a configured database, publish messages, invoke models and wait for callbacks. A worker can report arbitrary output. An operator can retry old work. Treating all three as ordinary CRUD would miss the places where authority actually changes hands.
This page describes the security boundaries node-flow enforces and the deployment decisions it cannot make for you.
node-flow does not make an untrusted workflow author safe to give arbitrary infrastructure access. It makes that access explicit and operator-owned: definitions refer to named destinations; operators configure the address and credential out of band.
The trust boundaries
The important separations are:
| Boundary | What crosses it | What does not |
|---|---|---|
| Browser → API | Session cookie plus CSRF proof on writes | Password after login; API keys in dashboard markup |
| Worker → API | A scoped credential, worker id and lease token | Authority to complete a task whose lease moved elsewhere |
| Definition → runner | Destination name and task input | Database URLs, broker credentials, SMTP passwords |
| Store → task | A resolved secret value in memory | Plaintext in task input, history, search or API responses |
| Namespace → namespace | Platform administration only | Definitions, runs, credentials or ordinary principals |
Identity: choose one mechanism per caller
Human sessions
Email/password, OIDC SSO and SAML SSO all end in a server-side session row. The
browser receives an HttpOnly session cookie and a separate CSRF cookie. A
state-changing request must send the CSRF value back in X-CSRF-Token.
Why two tokens? HttpOnly protects the session token from JavaScript, while
the readable CSRF token proves that the caller is code running on the intended
origin rather than a cross-site form submission. SameSite is defence in
depth, not the only check.
Sessions can be revoked individually or all at once. Passwords are hashes, not reversible credentials. OIDC and SAML provision the account on first sign-in; they do not silently grant groups or administrator scopes.
API keys
API keys begin with nf_ and are shown once. The database stores a hash, so
there is no endpoint that can recover a lost key. Use them for scripts and
systems that cannot perform a token exchange.
curl -H "Authorization: Bearer $NF_API_KEY" \
http://localhost:3000/v1/auth/whoamiCreate separate keys for separate deployments. Scope a worker to queue access;
do not hand it admin because doing so is convenient during development.
Service accounts
A service account has a client id and secret. Exchange those for a short-lived
JWT at POST /v1/auth/token; send the access token as a bearer token. Rotating
or deleting the service account stops the next exchange without requiring a
long-lived token in every client.
Workload identity
OIDC workload identity maps an external issuer, audience and subject to a node-flow principal. mTLS maps the verified certificate identity. Both remove stored application secrets, but neither grants authority by itself: the binding still names the scopes and namespace.
NODE_FLOW_OIDC_ISSUERS is for machines presenting an existing token.
NODE_FLOW_SSO_PROVIDERS is for humans completing a browser flow. They are
intentionally separate configuration surfaces.
Authorization: scopes, grants and tags
Authorization is evaluated after authentication and namespace resolution.
- The principal must belong to the namespace, unless it is a platform administrator using a platform-only endpoint.
- A matching scope must allow the operation.
executions:readandexecutions:startare different capabilities. - If the credential has resource grants, the operation must match one.
- If a resource is tagged and tag grants are in use, the caller must match the resource's tags.
Groups collect scopes and tag grants for human users. Resource grants are the
narrower tool for machine credentials—for example, one service account may
start invoice_* workflows but not modify their definitions.
Denials are deliberate. Do not turn a 403 into a broader key until
GET /v1/auth/whoami shows which identity, namespace and scopes the server
actually resolved.
Namespace isolation
Nearly every API path contains /ns/{namespace}. The credential also belongs
to a namespace, and the two must agree. A namespace is the tenant boundary for:
- workflow and task definitions;
- executions, task payloads and logs;
- secrets, environment values and integrations;
- users, groups, keys and service accounts;
- schedules, event handlers, forms, schemas and saved views;
- quotas, audit records and AI indexes.
The Conductor compatibility paths do not contain a namespace, so the credential supplies it. This is why sharing one compatibility credential between tenants is not supported.
Secrets are sealed, not redacted
NODE_FLOW_SECRET_KEYS is a comma-separated key ring in id:base64key form.
The first key seals new values; all keys may open existing values. This enables
rotation without a flag day:
# 1. Add the new key first. Keep the old key second while data is re-sealed.
NODE_FLOW_SECRET_KEYS='2026-09:BASE64_NEW,2026-03:BASE64_OLD'
# 2. Rotate stored ciphertext through the API or operator workflow.
# 3. Remove the old key only after every value names the new key id.Without a key ring, the server refuses to store a secret. It does not fall back to plaintext. Reads list metadata, never values. Resolution happens when a system task executes, and the resolved value is not written into task input, output, history or logs.
Back up the key ring separately from Postgres. A database backup without the key is intentionally insufficient to recover secrets; losing every key is also irrecoverable.
Outbound network and destination controls
The HTTP task blocks loopback, link-local and private destinations by default,
including redirects that land on one. This prevents a workflow from reaching
cloud instance metadata or an internal control plane.
- Prefer
NODE_FLOW_HTTP_ALLOWED_HOSTSfor narrow exceptions. - Set
NODE_FLOW_HTTP_ALLOW_PRIVATE=trueonly when every workflow author is trusted to reach the private network visible to the server. - Apply an egress policy at the container or cluster boundary as a second layer. Application URL checks do not replace a network policy.
SQL, gRPC, SMTP, brokers and AI providers use named operator configuration.
The workflow supplies datasource: "reporting", not a connection string. The
same rule prevents credentials appearing in definitions and prevents an author
from choosing a destination behind the server's network perimeter.
Webhooks and replay resistance
Inbound workflow webhooks use an unguessable token in the URL as authority. Treat the whole URL as a secret: do not put it in public issue trackers or analytics. Where a webhook verifier is configured, verify the provider's signature as well.
Outbound WEBHOOK calls are signed and go through the transactional outbox.
The receiver should:
- verify the signature before parsing privileged fields;
- reject timestamps outside its replay window;
- deduplicate using the delivery or execution identifier;
- return success only after its own durable commit.
Workers have a similar replay control: the lease token is a fencing token. A result from an expired lease is rejected even when the task id is valid.
Production hardening checklist
Establish identity
- Generate a unique
NODE_FLOW_JWT_SECRETof at least 32 random characters. - Leave
NODE_FLOW_SEED_PASSWORDunset so the first password is generated and logged once; rotate it immediately. Then setNODE_FLOW_SEED=falsewhere identity is fully managed elsewhere. - Prefer OIDC or mTLS workload bindings over shared API keys.
- Give each workload its own credential and minimum scopes.
Protect data
- Configure a recoverable, separately backed-up
NODE_FLOW_SECRET_KEYSring. - Require TLS to managed Postgres and verify its CA.
- Use S3 with an instance role or workload identity for multi-node payloads.
- Encrypt database, object-store and backup volumes at rest.
- Set retention appropriate to the personal data carried in task inputs and outputs.
Constrain the network
- Terminate TLS at a trusted proxy and configure forwarded headers narrowly.
- Keep private HTTP access off; allow individual hosts where needed.
- Apply ingress and egress network policy to each role.
- Do not expose Postgres, metrics or health detail publicly.
- Keep gateway CORS origins exact; an empty list is the safest default.
Make changes observable
- Export the audit log and alert on identity, secret, permission and integration changes.
- Alert on repeated
401,403, signature failures and stale lease reports. - Keep trace export scrubbed: task payloads can contain customer data even when secrets are sealed correctly.
- Rehearse key rotation and credential revocation before an incident.
If a credential is exposed
| Credential | Immediate action | Follow-up |
|---|---|---|
| API key | Delete the key | Issue a replacement with narrower scopes; inspect audit and access logs |
| Service-account secret | Delete or rotate the account | Existing JWTs live until their short TTL; rotate the JWT signing secret only if every token must die immediately |
| Human password | Reset it and revoke all sessions | Review group membership, SSO state and audit events |
| Session cookie | Revoke that session or all sessions | Investigate browser and proxy logs; session expiry alone may be too slow |
| Secret master key | Add a new first key and re-seal immediately | Retire the old key after verification; assume copied database ciphertext is exposed |
| Webhook URL | Replace the webhook token | Reject old deliveries and review receiver deduplication |
Security controls are only useful when the refusal is visible. Preserve the error code, request id, principal id and audit event when investigating; avoid copying raw credentials or task payloads into a ticket.
Next
- Configuration lists every security-related environment variable and its exact shape.
- Self-hosting covers TLS, backups, health and production topology.
- The REST API explains authentication headers, scopes and grants with requests.
