Skip to content

Flows & Actions — overview

Flows + Actions is the surface for tenant-defined sign-in logic. The platform ships sensible defaults for every sign-in / sign-up / password-reset path; Actions are your hook to insert custom behaviour at specific points.

Four words to know — Flow, Stage, Block, Action — and how they nest (full concept page):

  • Flow — the ordered set of steps for one authentication event (login, registration, password reset, MFA enrolment, token refresh, logout). Your tenant ships with system flows; you can also create custom flows.
  • Stage — a labelled section inside a Flow (e.g. Pre-Login, Post-Auth, Post-Login). Stages are where you insert your own logic.
  • Block — one step inside a Stage. The platform ships ~46 built-in blocks (Password Check, Risk Evaluate, MFA, Issue Session, Run Custom Action, and so on).
  • Action — JavaScript you write that runs inside a Run Custom Action block. Decides to continue / block / redirect / demand MFA. Configurable per-tenant.

A Flow is a top-down sequence of Stages. Each Stage holds Blocks — built-in platform steps and, optionally, Run Custom Action blocks where your Actions run. Blocks share a state map as they execute; the next Block reads what the previous one wrote.

Login flow
├─ Stage: Pre-Login
│ ├─ Block: Identity Lookup
│ └─ Block: Password Check
├─ Stage: Post-Auth
│ ├─ Block: Risk Evaluate
│ └─ Block: Run Custom Action ◀── your Action runs here
└─ Stage: Post-Login
├─ Block: Run Custom Action ◀── your Action runs here
└─ Block: Issue Session

If any Block returns deny or errors, the Flow halts. Otherwise it runs to a terminal Block — Issue Session on a successful login.

  • Block sign-in with a reason. The user sees the reason; sign-in halts.
  • Demand MFA even when the policy wouldn't normally. Useful for risk-based step-up logic.
  • Decorate the token with a custom claim. Adds subscription_tier: enterprise (or whatever) to the access token.
  • Send a webhook (via your own infrastructure, not the platform's). E.g., post to your internal Slack on admin sign-ins.
  • Redirect to a specific URL after success. Useful for "send Beta users to the staging environment".

What you CAN'T do:

  • Read or modify the user's password or MFA factor secrets.
  • Make synchronous calls to slow external systems (your Action's per-trigger time budget is a few seconds).
  • Persist state across runs (each invocation is stateless).

System flows and their editable Stages (more in triggers-and-steps developer concept):

  • LoginPre-Login, Post-Auth, Post-Login.
  • RegistrationPre-Create, Post-Create.
  • Password resetPre-Send (before reset email goes out).
  • MFA enrolmentPre-Create (before factor is recorded).
  • MFA verifyPost-Success, Post-Failure.
  • Token refreshPre-Issue (before refreshed token is minted).

A few recurring shapes:

  • Domain allowlist — block sign-ins from emails not in your customer's allowed domains.
  • Welcome email post-signup — fire a notification to your CRM after a new user is created.
  • Slack alert on admin sign-in — your security team wants to know when admin accounts authenticate.
  • Custom claim decoration — add tier / region / department to every issued token.
  • Risk-based step-up — if the user's session score crosses a threshold, demand fresh MFA before letting them proceed.

Authentication → Flows. Pick a Flow. The editor shows each Stage and its Blocks. Add a Run Custom Action block to a Stage, then name one of your saved Actions. Click an existing Run Custom Action block to swap, configure, or remove its Action.

The Actions you can attach are pre-built (platform-shipped templates) or custom (TypeScript / JavaScript you author). See Custom actions and Flow recipes for ready-made starting points.

Tenant admins write Actions in JavaScript / TypeScript. The platform exposes a small SDK and a sandboxed runtime; your code runs server-side under platform control.

A minimal Action skeleton:

export async function execute(input) {
const email = input.user?.email
if (email?.endsWith('@cymmetri.com')) {
return { kind: 'continue' }
}
return {
kind: 'block',
reason: 'Sign-in is restricted to Cymmetri employees.',
code: 'domain_not_allowed',
}
}

Authoring details are in Actions → New action in the console. The full programming model — input shape, output shape, ID conventions, observability — is in the developer-facing pipelines concept.

Every Action execution records:

  • flow.action_executed — actor (the platform; the Flow run), Action slug, outcome (continue / block / error), duration.
  • flow.run_completed — the parent Flow's outcome.

Per-Action logs (your console.log output) are captured against the run; visible in the Flow detail page → Recent runs.

  • For "send a webhook on every login" — use a webhook subscription instead. Cleaner; lighter; survives Action engine outages.
  • For business logic that runs frequently in your own application — keep it in your application, not in an Action.
  • For anything async that takes more than a few seconds — Actions have tight time budgets.

Actions are for fast, sync decisions about sign-in. Everything else is webhooks + your own backend.