Skip to content

When to reach for Flows

Flows are the per-tenant customisation surface for sign-in logic. Every tenant ships with sensible defaults — a working Login flow, a Registration flow, a Password Reset flow — and you don't have to touch any of them. You reach for the editor when your policy or product demands something the defaults don't cover.

Three good reasons to open the Flows editor

Section titled “Three good reasons to open the Flows editor”

The default Login flow enforces MFA whenever a user has enrolled a factor. That's a reasonable start. But many teams want something more nuanced: "ask for the second factor only when the request looks suspicious." Suspicious might mean the IP is a Tor exit node, a VPN, an impossible-travel hop from the last login, or a cluster of recent failed attempts on the same account.

Flows give you the building blocks to express that policy. Drop a Risk Evaluate block in Post-Auth, wire a Decision block to route on the score, and the MFA block only fires when the risk threshold is crossed. Users on trusted networks or familiar devices sail through. Users who trigger the signal get challenged.

Registration is rarely just "create the user." Cymmetri, for example, tags every new account as either corporate or self-serve based on the email domain, then pushes an enriched profile to their CRM. Both of those happen inside a Run Custom Action block in the Registration flow's Post-Create stage.

Other things teams do here:

  • Reject disposable or role-based email addresses before the account is created.
  • Deny signups from countries on a sanctions list.
  • Assign a default plan tier or department to app_metadata based on the invitation token.
  • Fire a webhook to kick off an onboarding sequence.

Your application reads the JWT. If it needs to know whether the user is a paid subscriber, which region they belong to, or what department they're in, those fields have to get into the token somehow. The Set Custom Claim block in the Login flow's Post-Login stage writes any event.* or step.* value you reference into the token that gets issued.

You write the mapping once in the Flows editor. Every login from that point forward produces a token with the right claims, without touching your application code.

Business logic that runs on every user action

Section titled “Business logic that runs on every user action”

Flows fire on authentication events: login, registration, password reset, MFA enrollment. They don't run when a user clicks a button in your app or hits an API endpoint. If the logic you're considering runs on every request — authorization checks, feature flags, entitlement lookups — it belongs in your application's middleware, not in a Flow.

Put another way: Flows own the moment the user proves who they are. Your app owns everything that happens after.

"Post to Slack whenever a new user registers" is a popular one. You can do it in a Flow using a webhook block, and it will work — but a webhook subscription is a cleaner fit. Subscriptions are lighter, they retry independently of the auth path, and they survive Flow-engine restarts without affecting your users' sign-in experience. If the notification fails in a Flow, you have a decision to make about whether to block the user or swallow the error.

Reserve webhook blocks in Flows for enrichment calls that your auth logic actually depends on. Pure notifications belong in event subscriptions.

Anything async that runs over a few seconds

Section titled “Anything async that runs over a few seconds”

The Flow engine has a tight time budget. A block that calls an external API with a five-second response time will tip your Flow over the limit, and the user will see an error. Long-running tasks — background enrichment, report generation, anything that involves polling — belong in your own backend, triggered by an event subscription after the user is already authenticated.

When Cymmetri turns Flows on for a tenant, their customers experience something most auth platforms can't offer out of the box. Contracts you can make:

  • "We never challenge you for a second factor on a device you've used before." — a risk-aware Login flow.
  • "Your enterprise tier is detected automatically at signup — no coupon code, no manual upgrade." — an email-domain check in the Registration flow.
  • "Every access token already carries your department and cost-centre — your apps don't need to look them up." — custom claims in the Login flow.
  • "Accounts from free email providers aren't allowed in this workspace." — a disposable-email check in Registration.

The Flows editor is the surface that makes those contracts possible without a custom identity service.

Flows run with meaningful power, but they have hard limits. An Action cannot:

  • Read a user's password or password hash.
  • Read the raw value of an enrolled MFA factor or TOTP secret.
  • Persist JavaScript variables across separate Flow runs — state lives only for the duration of a single run.
  • Bypass the platform's audit log. Every Flow run is recorded.
  • Undo or modify what a built-in block already did in the same run.

These limits are structural, not configuration. They exist so that a misconfigured or compromised Action can't escalate past the boundaries the platform enforces.