// 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
| role | granted by | can |
|---|---|---|
is_admin | another admin, from the Admin tab | create and edit users, configure platform settings, see the audit log, change templates |
is_super_admin | set directly in Postgres | everything 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.