The Authentication family is the heart of any flow. These eleven blocks verify what users know (passwords), what they have (OTP codes, passkeys), and whether their second factor is enrolled and satisfied. The platform owns all secret handling end-to-end — your flow composes verifications, but it never touches a plaintext credential or a raw cryptographic key. That boundary is non-negotiable and enforced at every call site.
Use this page alongside the Flows concepts page and the {} picker in the editor. The picker shows you what's referenceable at each step; this page tells you what each block promises to write there.
Picking a block
Section titled “Picking a block”| You want to... | Reach for |
|---|---|
| Verify a returning user's password | Verify Password |
| Enroll a new credential at signup or during an admin-create path | Set Credential |
| Accept a new password at the end of a password reset | Update Password |
| Dispatch a one-time code to email or SMS | Send Channel OTP |
| Verify the code the user typed back | Verify Channel OTP |
| Authenticate a passkey or hardware key | WebAuthn Begin + WebAuthn Finish |
| Verify a second factor (TOTP, OTP, passkey, or SMS) | Multi-Factor Authentication |
| Look up whether the user has MFA enrolled, without acting on it | Check MFA Status |
| Enforce a specific factor at this exact point in the flow | Require MFA |
| Gate entry until the user has enrolled a factor | Require MFA Enrollment |
Core credential verification
Section titled “Core credential verification”Verify Password
Section titled “Verify Password”Block id: password_check · Available in: Login, Registration, Password Reset, MFA Enrollment, MFA Step-up
Verify the user's password credential. Lifts the session to AAL1 on success. This is the standard first factor for any password-based login flow — place it after Identity Lookup, then branch on step.<slug>.verified with a Decision block to route failures to a retry screen.
Reads from state
identifier— the user's email or username, resolved upstream by Identity Lookuppassword— submitted by the user via the SDK login form
Writes to state
step.<slug>.verified—truewhen the supplied password matched the stored credentialstep.<slug>.factor_id— internal identifier for the credential that matched
Use when — the user is logging in or re-authenticating with a password and you want AAL1 lifted on success.
Cautions — Password Check is fail-closed: if the credential store is unreachable, the block returns a deny rather than passing through. Pair with a rate-limiting block upstream (Brute Force Check) to limit repeated attempts.
Set Credential
Section titled “Set Credential”Block id: credential_set · Available in: Login, Registration, Password Reset, MFA Enrollment, MFA Step-up
Enrol a new credential for the user — password, TOTP, channel OTP, or passkey. This is the registration tail-end block, the user-facing MFA-enrolment block in the Security tab, and the mechanism behind an admin's "set initial password" path. The block is pause-capable: for TOTP it emits a QR-code pause, for WebAuthn a ceremony pause, for SMS / email OTP a "we sent a code" pause. The flow engine surfaces each pause to the SDK, the user fills the input, and the block resumes through Aegis's selfservice ceremony to finalise the credential.
Reads from state
user_id— the user being enrolled, set by Identity Create upstreampassword— for password-type enrolment, the new password submitted by the userphone— for SMS-OTP enrolment, the verified phone numberpipeline.run_id— opaque correlator the block uses to look up the Aegis ceremony triplet (flow_id,csrf_token,csrf_cookie) it stashed at begin-time. Minted at/start; never goes through the stage token'sstate.
Writes to state
step.<slug>.credential_id— identifier of the newly enrolled credential, present when the factor type returns onestep.<slug>.pause— typed pause envelope (kind: "credential_set",factor: <type>,challenge: …) the FE renders the next screen from
Configuration knobs
| Knob | Purpose |
|---|---|
factor_type_id | The factor to enrol — password, totp, sms_otp, email_otp, webauthn_platform, webauthn_security_key, backup_code, or the special string "any" |
available_factor_types | Optional allow-list to restrict the picker when factor_type_id is "any" |
optional | When true, the FE renders a "Skip for now" button on the pause screen; resuming with { action: "skip" } advances past the block without enrolment |
skip_if_enrolled | When true, the block becomes a no-op when the user already has a credential of this factor type (defensive default for registration-time enrolment that may run for re-imported users) |
Factor-picker mode (factor_type_id: "any"). Set Credential emits an additional picker pause before the per-factor pause. The user sees a card grid of factors they can enrol — the intersection of available_factor_types, the tenant-allowed factors, and what the user has not already got. The user picks one and the block proceeds with that factor; their per-profile preferred factor is pre-highlighted.
Use when — the user is completing registration and you need to persist their chosen password, the user is adding a method from the Security tab, or you want to gate access until a missing factor is enrolled.
Cautions — The audit log redacts the password field automatically. WebAuthn enrolment binds the credential to the origin the ceremony ran on; an enrolment at https://staging.acme.com cannot be verified from https://acme.com. For TOTP, the abandonment TTL is 15 minutes — if the user closes the page mid-enrolment, the secret is discarded and the next attempt mints a fresh one.
Update Password
Section titled “Update Password”Block id: password_update · Available in: Password Reset only
Replace the user's password. Self-service flows verify the old password upstream (using Verify Password) before this block runs; admin-reset flows skip that check. Update Password is intentionally scoped to the Password Reset flow — placing it in any other flow type is a validation error.
Reads from state
user_id— the user whose password is being replacedpassword— the new password submitted by the user
Writes to state
- (no declared outputs)
Use when — you are building or customising the Password Reset flow and need the credential replacement step.
Cautions — The audit log redacts the password field. For self-service resets, always place Verify Password first so the user proves they know the current password before replacing it. Admin-initiated resets may omit the upstream check.
OTP by channel
Section titled “OTP by channel”Send Channel OTP
Section titled “Send Channel OTP”Block id: channel_otp_send · Available in: Login, Registration, Password Reset, MFA Enrollment, MFA Step-up
Dispatch an OTP code to the user's verified channel — SMS or email. The platform resolves the channel binding through Aegis; this block does not see the recipient address directly. Pair it immediately with Verify Channel OTP so the user can submit the code on the same screen.
At publish time the platform cross-checks every sms_otp block against the active identity schema and rejects the publish if no phone trait is declared. The dialog explains what's missing and points at the offending block. Add the trait via Settings → Identity schema → Add trait → phone (or hit POST /api/v1/identity-schemas/active/traits with { "trait": "phone" }), republish the schema, then republish the flow. The two artefacts are versioned independently; the schema has to land first.
Reads from state
user_id— the user to dispatch the code to, resolved upstream
Writes to state
step.<slug>.otp_id— internal handle for the dispatched codestep.<slug>.masked_recipient— partially redacted address the OTP was delivered to (e.g.+1******1234), safe to display in UIstep.<slug>.expires_at— ISO 8601 timestamp after which the code is no longer valid
Use when — building a passwordless login flow, adding SMS step-up, or sending a one-time code during account recovery.
Cautions — This block is fail-open: if the delivery channel is unreachable, the block passes rather than halting the flow. Monitor delivery failures through the audit log. On admin-create paths the block is bypassed by default (the OTP send toggle is on by default for skip).
Verify Channel OTP
Section titled “Verify Channel OTP”Block id: channel_otp_verify · Available in: Login, Registration, Password Reset, MFA Enrollment, MFA Step-up
Verify an SMS or Email OTP code submitted by the user. Pairs with the Send Channel OTP block (which dispatched the code) and appends the factor to event.authentication.methods on success. The block is fail-closed — an unreachable credential store returns a deny rather than a pass.
Reads from state
user_id— the user submitting the codeotp_code— the code typed by the user, submitted via the SDK
Writes to state
step.<slug>.credential_id— identifier of the verified OTP credential, present when the factor type issues oneevent.authentication.methods— the array of verified factor types, updated to include this channel factor
Use when — you need to confirm that the user received and read the code sent by Send Channel OTP.
WebAuthn
Section titled “WebAuthn”WebAuthn authentication is a two-block operation: WebAuthn Begin issues a challenge to the browser, and WebAuthn Finish verifies the response. They must always appear together in the same flow, in that order. Splitting them across stages or omitting either half is a flow authoring error.
Begin WebAuthn Authentication
Section titled “Begin WebAuthn Authentication”Block id: webauthn_begin · Available in: Login, Registration, Password Reset, MFA Enrollment, MFA Step-up
Start a WebAuthn authentication ceremony. The platform returns a PublicKeyCredentialRequestOptions blob the SDK passes to navigator.credentials.get(). The resulting assertion is round-tripped back to the platform and consumed by WebAuthn Finish.
Reads from state
user_id— the user initiating the passkey ceremony
Writes to state
step.<slug>.session_id— opaque handle linking this ceremony to the finish step; the SDK round-trips it back. Transient: not persisted across the ceremony boundary.step.<slug>.options— the W3CPublicKeyCredentialRequestOptionsblob passed to the browser. Transient.
Use when — you want to support passkeys (Touch ID, Face ID, YubiKey, Windows Hello) as a login factor or second factor.
Cautions — Both outputs are transient. They are delivered to the SDK in the /submit response and must not be read by later blocks. Configure user_verification in the block's config panel (required for step-up; preferred for login).
Finish WebAuthn Authentication
Section titled “Finish WebAuthn Authentication”Block id: webauthn_finish · Available in: Login, Registration, Password Reset, MFA Enrollment, MFA Step-up
Complete a WebAuthn authentication ceremony. The platform verifies the AssertionResponse against the challenge issued by WebAuthn Begin and updates LastUsedAt on the credential. This block can deny if the assertion is invalid or the credential is not registered for this user.
Reads from state
user_id— the user whose passkey is being verifiedwebauthn_session— the session handle fromstep.<begin-slug>.session_id, round-tripped by the SDKwebauthn_assertion— the browser'sAuthenticatorAssertionResponse, submitted via the SDK
Writes to state
step.<slug>.credential_id— identifier of the passkey that was verified during the WebAuthn ceremonyevent.authentication.methods— updated to include the WebAuthn factor
Use when — immediately after WebAuthn Begin, as the second half of every passkey ceremony.
MFA orchestration
Section titled “MFA orchestration”Multi-Factor Authentication
Section titled “Multi-Factor Authentication”Block id: mfa · Available in: Login, Registration, Password Reset, MFA Enrollment, MFA Step-up
Verify a second authentication factor — TOTP, SMS-OTP, Email-OTP, or WebAuthn. The specific factor type is configured per-block; the AAL contribution to the session is resolved at runtime based on which factor the user passes. For step-up flows, place MFA after a Decision block that reads Check MFA Status output to confirm enrollment before challenging.
Reads from state
user_id— the user being challengedpayload— the factor response submitted by the user (TOTP code, OTP code, or WebAuthn assertion depending on configured factor type)
Writes to state
step.<slug>.verified—truewhen the user successfully passed the configured MFA factorstep.<slug>.factor_id— identifier of the factor credential that was verifiedstep.<slug>.session_aal— the AAL level the session was lifted to after this verificationstep.<slug>.pause— typed pause envelope.kind: "mfa.picker"on the picker step (when configured for"any");kind: "mfa.verify"on the per-factor verify step
Picker mode (factor_type_id: "any"). Like Set Credential, the MFA block accepts "any" to let the user pick. The picker emits an mfa.picker pause listing the user's enrolled factors (minus the one already used in this flow run, if any). Once picked, the block emits the per-factor verify pause and proceeds. Restrict the picker contents with available_factor_types.
Use when — you want a single, configurable MFA challenge block in a login or step-up flow. For explicit per-factor control, prefer Require MFA.
Check MFA Status
Section titled “Check MFA Status”Block id: check_mfa_status · Available in: Login, Registration, Password Reset, MFA Enrollment, MFA Step-up
Read the user's MFA enrollment state via the platform. Writes mfa_enrolled and mfa_methods to state. This block is metadata-only — it never denies and never challenges the user. Use its outputs in a Decision or Condition block to route enrolled users to the MFA challenge and unenrolled users to enrollment.
Reads from state
user_id— the user whose enrollment state is being read
Writes to state
step.<slug>.mfa_enrolled—truewhen the user has at least one active MFA factor of the required typestep.<slug>.mfa_methods— array of enrolled factor type stringsstep.<slug>.mfa_preferred_method— the user's preferred factor type, if set
Use when — you need to branch a flow based on whether the user has MFA enrolled, without immediately challenging them. Typical pattern: Check MFA Status → Decision (read enrolled) → MFA challenge or enrollment redirect.
Require MFA
Section titled “Require MFA”Block id: require_mfa · Available in: Login, Registration, Password Reset, MFA Enrollment, MFA Step-up
An explicit MFA gate that delegates to the MFA evaluator with the configured factor_type_id. Unlike the MFA block, Require MFA is self-contained: it both checks and challenges in one step, without needing an upstream status check. It is fail-closed and can-deny — a failed challenge halts the flow.
Reads from state
user_id— the user being challengedpayload— the factor response submitted by the user
Writes to state
step.<slug>.verified—truewhen the user passed the required MFA factor at this gatestep.<slug>.factor_id— identifier of the verified factor credentialstep.<slug>.session_aal— the AAL level the session was lifted to
Use when — you want a single block that enforces a specific factor at a specific point in the flow, without a separate enrollment-check step. Cymmetri uses this pattern at the end of their Login flow for all users flagged as high-value accounts.
Require MFA Enrollment
Section titled “Require MFA Enrollment”Block id: require_mfa_enroll · Available in: Login, Registration, MFA Enrollment, MFA Step-up
Force a pending MFA enrolment when the user has no enrolled factor of the required type. Require MFA Enrolment is an orchestrator: it delegates to Set Credential under the hood, so it inherits the picker pause, the per-factor enrolment pause, and the optional / allow_skip behaviour without duplicating any of it. If you find yourself wiring "check status → if not enrolled → enrol" by hand with three blocks, replace the chain with this single block.
Reads from state
user_id— the user whose enrolment is being checkedpipeline.run_id— the ledger correlator threaded into the delegated Set Credential ceremony
Writes to state
step.<slug>.mfa_enroll_required—truewhen the user reached the block without a usable factorstep.<slug>.mfa_enrolled—trueafter the delegated enrolment succeeds (or if the user was already enrolled)step.<slug>.credential_id— when an enrolment ran, the id of the newly enrolled credentialstep.<slug>.pause— pause envelopes pass through unchanged from the delegated Set Credential (mfa.picker, thencredential_set)
Configuration knobs
| Knob | Purpose |
|---|---|
factor_type_id | Which factor to demand. Set "any" to surface the picker. |
available_factor_types | Allow-list when factor_type_id is "any" |
allow_skip | Surfaces a "Skip for now" button on the enrolment screen; resume with { action: "skip" } to bypass without enrolling. Use this for "nudge, don't force" enrolment campaigns. |
Use when — you want one block that turns "user has no MFA" into "user has MFA" without composing three blocks by hand. Place it after Password Check in Login flows; the user enrols once, then sails through every subsequent login.
Common compositions
Section titled “Common compositions”These patterns appear in most tenants. The block IDs are illustrative — your flow editor assigns slugs per instance.
Password login with step-up MFA
Identity Lookup -> Verify Password -> Check MFA Status -> Decision (step.check-mfa-status.mfa_enrolled == true) yes -> Multi-Factor Authentication no -> Issue Session (AAL1 only) -> Issue Session (AAL2)Place the Decision block to read step.check-mfa-status.mfa_enrolled. Users without MFA enrolled proceed to a session at AAL1; enrolled users are challenged and lift to AAL2.
OTP-based passwordless login
Identity Lookup -> Send Channel OTP -> Verify Channel OTP -> Issue SessionNo password in the path. The user proves access to their registered email or phone. If you want to enforce that the OTP channel is set up before this flow runs, gate entry with Check MFA Status upstream.
Adding a passkey to an existing user
WebAuthn Begin -> WebAuthn Finish -> Set CredentialWebAuthn Begin issues the registration challenge. WebAuthn Finish verifies the authenticator's attestation response. Set Credential enrolls the verified passkey against the user's identity. This sequence belongs in an MFA Enrollment flow, not a Login flow.