Skip to content

Flows concepts — Flow, Stage, Block, Action

Four words show up everywhere in the Flows editor — Flow, Stage, Block, Action. Once you see how they nest, everything else slots into place.

  • Flow — the ordered set of steps for one authentication event. Your tenant has a Login flow, a Registration flow, a Password Reset flow, and so on. Each Flow runs end-to-end every time that event happens.
  • Stage — a labelled section inside a Flow. The Login flow has stages like Pre-Login, Post-Auth, Post-Login. Stages give you a place to insert your own logic without rewriting the platform's steps.
  • Block — one step inside a Stage. Blocks are the LEGO pieces — Password Check, MFA, Risk Evaluate, Issue Session, Run Custom Action, and so on. The platform ships ~46 blocks; you compose them.
  • Action — JavaScript you write that runs inside a Run Custom Action block. This is where you put logic the built-in blocks don't cover.

Put together: a Flow contains Stages, a Stage contains Blocks, and a Block (specifically the Run Custom Action block) can contain one of your Actions.

The platform walks the Flow top to bottom, stage by stage, block by block. Each block reads from a shared state map, does its job, and writes its outputs back. The next block reads what was written and so on.

If any block returns deny or hits an unrecoverable error, the Flow halts. Otherwise it runs to a terminal block — Issue Session on a successful login, Allow on a permitted operation, or Deny if a policy rejected the request.

A simplified Login flow:

Login flow
├─ Stage: Pre-Login
│ ├─ Block: Identity Lookup
│ └─ Block: Password Check
├─ Stage: Post-Auth
│ ├─ Block: Risk Evaluate
│ ├─ Block: Decision (route on risk)
│ ├─ Block: MFA (only if the decision routed here)
│ └─ Block: Run Custom Action — "tag-corporate-vs-self-serve"
└─ Stage: Post-Login
├─ Block: Run Custom Action — "welcome-new-user"
└─ Block: Issue Session

Three stages. Six blocks. Two custom actions slot into Run Custom Action containers.

A Block is a built-in capability. The platform owns its code, audits it, and stays accountable for it. You configure it through form fields in the editor.

An Action is JavaScript you author. You write a few lines, hit save, and your code runs server-side inside a sandbox the platform manages. Actions are how you handle anything the built-in blocks don't cover — domain allowlists, tagging users by company, calling your own webhook, injecting custom claims, denying disposable email signups.

Rule of thumb: if a Block does what you need, use the Block. If not, drop in a Run Custom Action block and write an Action. Don't write JavaScript for things blocks already handle.

The platform ships system Flows for the events that happen on every tenant:

  • Login — verifying a returning user. Lifts the session to AAL1 (and AAL2 if MFA verified).
  • Registration — creating a new account.
  • Password Reset — emailing a recovery link and accepting a new password.
  • MFA Enrollment — adding a second factor to an existing account.
  • MFA Step-up — re-verifying a factor for a sensitive operation.
  • Logout — invalidating sessions.

Each system Flow has its own default stages and a sensible default block layout. You edit the layout from Flows → pick a flow → Edit.

Three top-level state namespaces. You'll see them every time you pop open the {} picker in the editor.

  • event.* — everything the platform knew when this Flow started, plus what it's learned since. The user's email and ID; the application calling in; the request's IP, country, user-agent, VPN/Tor flags; the transaction's OAuth scope and locale. Read-only.
  • step.<block-name>.* — outputs of an earlier block in the same Flow. step.password-check.verified is whether Password Check passed; step.fraud-signal.body.score is the score your webhook block returned. Read-only.
  • session.* — the session that gets minted at a terminal block. Read it after Issue Session runs; not before.

Phase 2 will add secrets.* for outbound API keys. Today, secrets in webhooks go in your block config (and pipe through the {} picker the same way).

Click the curly-braces icon next to any text field — URL, header, body, or a Decision block's when expression — and the picker opens. It groups everything you can reference:

  • Event context — 50-plus paths under event.*, grouped by category (user, request, transaction, client, tenant, authentication).
  • Step outputs — fields from each upstream block, keyed by the block's label.
  • Session — fields available after the terminal block runs (grey until then).

The picker is the discovery surface. The reference pages below are the contract.