An Action is a reusable piece of custom logic that runs at a specific trigger point inside a Flow. Two flavours:
- Platform-shipped templates — pre-built Actions for common needs. Drop in; configure via form; save.
- Custom Actions — TypeScript / JavaScript you author yourself. Upload; configure schema; attach.
The Actions list
Section titled “The Actions list”Authentication → Actions. Lists every Action available in your tenant.
Each row:
- Name — the Action's name.
- Kind —
template(platform-shipped) orcustom(yours). - Compatible triggers — the trigger slots this Action can be attached to.
- Attached — how many flow slots currently use this Action.
Platform templates
Section titled “Platform templates”The platform ships these out of the box. The list grows over releases:
- domain-allowlist — block sign-ins from emails outside an allowed list.
- domain-blocklist — block sign-ins from emails on a denied list.
- rate-limit-by-ip — refuse requests above a per-IP threshold.
- rate-limit-by-user — refuse repeated attempts on the same user account.
- decorate-token — add a custom claim to the issued token.
- webhook-emit — POST to a URL when this slot fires.
- slack-notify — post to a Slack incoming webhook (a specialised webhook-emit).
- block-by-risk-score — block when the risk engine's score exceeds a threshold.
- demand-mfa-by-risk-score — force MFA even when policy wouldn't normally.
- redirect-by-group — redirect specific group members to specific URLs after sign-in.
Each template ships with a configuration form. No code; just fill in fields.
Custom Actions
Section titled “Custom Actions”When templates don't cover your case, write your own. The flow:
- Open Actions → New action.
- Pick a starter template (or "Empty Action" for fully custom).
- The editor opens with a TypeScript skeleton.
- Write the logic.
- Configure the Action's metadata (name, slug, compatible triggers, config schema).
- Save. The Action is now available to attach to flow slots.
The full programming model + the platform's runtime sandbox is documented in the developer-facing pipelines concept. For a hands-on walkthrough, see Your first custom action. For ready-made starting points, see Flow recipes — each recipe names the Blocks and Action code needed for a specific goal.
What an Action looks like (minimal)
Section titled “What an Action looks like (minimal)”// src/index.ts in the Action packageexport async function execute(input) { // input: { trigger, user, request, state, context } // return: { kind: 'continue' | 'block' | 'demand_mfa' | 'redirect' } return { kind: 'continue' }}The skeleton is filled in by the editor; you customise the logic.
Versioning
Section titled “Versioning”Each Action has a version field on its metadata. When you edit + save, the version bumps. Flows reference Actions by version — a Flow attached to domain-allowlist v1.0.0 keeps running v1.0.0 even after you publish v1.1.0.
To roll out a new version to an attached flow:
- Publish the new version (v1.1.0).
- Open the flow.
- Update the version pinned to the slot.
- Save the flow.
The flow now runs v1.1.0. Existing in-flight sign-ins continue on whatever version started them; new sign-ins use the new version.
This pattern is the cheap insurance against "the Action update broke production for 10 minutes". You stage new versions; you roll out per-flow when you've verified the staging.
Visibility
Section titled “Visibility”Actions are tenant-scoped. The Actions in tenant A's catalogue are not visible to tenant B. There's no cross-tenant Action sharing today.
If you have many tenants running the same Action, you'll author it in each — or use the management API to script the upload across tenants.
Every Action execution + every Action edit lands in audit:
flow.action_attached— Action added to a flow slot.flow.action_detached— removed.flow.action_updated— config changed.flow.action_executed— ran during a flow.flow.action_published— new version published.
The combination lets you reconstruct "why did sign-ins start failing yesterday at 14:00?" — usually a flow.action_attached or flow.action_updated entry near that timestamp.