// docs / authentication

Authentication

Two layers, kept separate: signing into the Openflow dashboard is a normal session login; the Node-RED editor that sits behind it never asks for a password. SSO into the editor is automatic, by capability token.

Two layers

  • The dashboard (the manager's React UI) authenticates a user. It owns the session and the platform roles.
  • The editor (the per-instance Node-RED) authenticates the same user against a per-instance capability token, transparently, via the magic-token model.

You log in once. Clicking Launch on an instance opens the editor authenticated. No per-editor account, no per-editor password.

Signing into Openflow

Three sign-in methods, all landing on the same cookie session:

Email + password

Built in. Passwords are scrypt-hashed (16-byte salt, 64-byte key) and stored in users.password_hash. The first user to register becomes the platform admin. Subsequent password accounts are created by admins from the Admin tab.

Google OAuth

Optional. Set GOOGLE_OAUTH_CLIENT_ID and GOOGLE_OAUTH_CLIENT_SECRET in the manager .env. The login page gains a "Sign in with Google" button. Users are matched by email; an existing password user picks up the Google ID on their first OAuth sign-in.

Passkey

WebAuthn, ECDSA P-256 or RSA, discoverable credential. Users register one from the Profile tab, sign in from the login page with a single click. See below.

Passkeys

Openflow ships with full passkey support: register from Profile → Security, sign in from the login page's Sign in with Passkey button. The browser presents any passkey bound to the relying party (the Openflow apex domain), the user picks, and they're signed in.

Discoverable-credential flow is used, so the user doesn't have to type their email first; the passkey carries the identity. Backed by @simplewebauthn/server.

TOTP 2FA

From Profile → Security. Scan the QR with your authenticator app (1Password, Authy, the Apple keychain, whatever). On the next sign-in, the password form prompts for a six-digit code; the recovery codes generated at enrollment are the backup if you lose the device.

TOTP gates the password sign-in only; passkey sign-in skips the prompt because the passkey is itself a possession factor.

Editor SSO (the magic-token model)

When you click Launch on an instance, the manager mints a single-use access token (sha256-hashed in Postgres, 1-minute expiry) and returns a URL with ?access_token=…. The Node-RED container's settings.js intercepts the token on arrival, validates it against the manager's /auth/validate-token endpoint, and signs you in.

To keep you signed in across restarts, the shim immediately swaps the cookie value for the per-instance master token (the long-lived OPENFLOW_MAGIC_TOKEN from the container's env, stable for the instance's lifetime, 30-day cookie). Subsequent requests carry that. The shim also rewrites the access_token in WebSocket upgrade URLs so the /comms reconnect after a restart authenticates cleanly.

operational note The magic token lives in the container env. Rotating it means recreating the container. The cookie carries the live value, so after a rotation users need to click Launch again to pick up the new token.

Admin & super admin

rolegranted bycan
is_adminanother admin, from the Admin tabcreate and edit users, configure platform settings, see the audit log, change templates
is_super_adminset directly in Postgreseverything an admin can, plus inspect any project / any instance regardless of membership

The super admin bit is deliberately not exposed in the UI. To set it the first time:

$ psql -d openflow -c \
    "UPDATE users SET is_super_admin = true WHERE email='you@example.com'"

After the first super admin, additional ones can be promoted from the Admin tab.