Skip to content

Block reference — Identity & Verification

Identity blocks are the bridge between what a user typed and the record stored in the platform. They find users by a trait like email or phone, mint new accounts, and patch profile fields. Verification blocks sit alongside them: they dispatch a one-time token to a channel and then confirm the token the user supplies. Together these eight blocks cover the full lifecycle from first-time signup through profile self-service.

A flow that creates an account without these blocks is a flow that writes to nowhere. Almost every Login, Registration, and Password Recovery flow starts with an Identity block and ends with one of the verification pair before handing off to a Session block.

  • "Find a user by email or phone" → Look Up Identity
  • "Mint a new user account" → Create Identity
  • "Update a user's profile fields (full overlay)" → Update Profile
  • "Send an email or SMS verification token" → Send Verification
  • "Confirm the user-supplied verification token" → Check Verification
  • "Check that a refresh token is still valid" → Validate Refresh Token
  • "Send an email-confirmation link (single-step mode)" → Email Verification
  • "Update an identifying alias on an existing user (shorthand)" → Update User

Block id: identity_lookup  ·  Available in: login, registration, password_recovery, mfa_enroll, mfa_step_up

Find a user by a single identifying trait — email or phone — and make the result available to every downstream block. The block is read-only: it never modifies the identity, so it carries no compensating action and cannot deny on its own.

Two config flags drive opposite use cases. Set must_exist: true in a Login flow so the block short-circuits when the trait has no match, routing the engine to a deny path without leaking timing information. Set must_not_exist: true in a Registration flow so an existing account triggers an early exit — the collision guard before Create Identity runs.

Reads from state

  • identifier — the email address or phone number the user supplied at flow start

Writes to state

  • step.<slug>.foundtrue when a matching identity exists for the supplied trait value
  • step.<slug>.user_id — the platform user ID, set when found is true
  • step.<slug>.identity_state — the account's lifecycle state (active, suspended, etc.)
  • step.<slug>.identity_traits — the full trait object for the found identity
  • step.<slug>.identity_verified — per-channel verification flags (email_verified, phone_verified)

Use when — any flow that needs to resolve an email or phone to a user ID. Place it early in the pre-login or pre-registration stage, before credential checks.

Cautions — The must_exist and must_not_exist flags are mutually exclusive. Setting both is an authoring error the editor will catch at save time. When neither is set, the block succeeds regardless of whether a match was found, and downstream blocks must read step.<slug>.found to branch.


Block id: identity_create  ·  Available in: registration

Mint a new identity in the platform with the supplied traits. This block is intentionally scoped to the registration trigger only — it should never run on a Login or Password Recovery flow. It expects a prior Look Up Identity block with must_not_exist: true to have already confirmed the address is not taken; Create Identity performs no deduplication of its own.

If a downstream block fails after Create Identity has already written to the identity store, the platform's compensating action will soft-delete the orphan account automatically. The admin console surfaces these partial-registration identities in the Users list under the pending state; they are pruned on the next lifecycle pass.

Reads from state

  • identifier — the email or phone to register under
  • traits — any additional trait fields collected by the registration form

Writes to state

  • step.<slug>.createdtrue when the new identity was successfully minted
  • step.<slug>.user_id — the platform user ID of the newly created account
  • step.<slug>.identity_state — the initial lifecycle state (typically active or pending_verification)
  • step.<slug>.identity_traits — the trait object as stored

Use when — the Registration flow, immediately after a Look Up Identity block confirms no collision. Follow it with Send Verification or Set Credential.


Block id: profile_update  ·  Available in: login, registration, password_recovery, mfa_enroll, mfa_step_up

Apply a partial trait overlay — and optionally a verified-channel overlay — to an existing identity. At least one overlay must be non-empty; the engine rejects no-op updates as authoring errors at flow execution time, not at save time.

Cymmetri, for example, uses this block in their "Edit Account" flow to let a user update their display name and preferred language without triggering a full re-verification. By supplying only the changed fields in trait_overlay, the block writes only those fields — the rest of the identity is untouched.

Reads from state

  • user_id — from an earlier Look Up Identity or the current session
  • trait_overlay — the fields to write (partial; unspecified fields are preserved)
  • verified_overlay — optional channel-verification flags to update alongside the traits

Writes to state

  • step.<slug>.updatedtrue when the overlay was applied successfully
  • step.<slug>.identity_state — the identity's lifecycle state after the update
  • step.<slug>.identity_traits — the full updated trait object

Use when — profile self-service flows, post-registration onboarding steps, or any flow that needs to patch a user record without replacing it entirely.


Block id: verification_send  ·  Available in: registration, login

Dispatch a verification token to the user via email or SMS. Configure the delivery channel (email or sms) and an optional TTL in seconds; the platform generates a secure token, stores a hash, and hands the plaintext to the courier. Always pair this block with a downstream Check Verification block to confirm the token the user returns.

The token itself is written to state so a Decision block could, in principle, read it — but you should never surface the raw token in a webhook body or custom action response. It is an audit-redacted field.

Reads from state

  • user_id — the identity to send the token to
  • channel — the delivery channel; falls back to the block's config if not in state

Writes to state

  • step.<slug>.verification_token — the plaintext token dispatched to the user
  • step.<slug>.verification_token_expires — ISO 8601 timestamp after which the token is invalid
  • step.<slug>.verification_channel — the channel used: email or sms

Use when — after Create Identity in a Registration flow, or at the start of a Password Recovery flow before the user supplies the token.

Cautions — If the courier is unconfigured or the send fails, the block is marked fail-open by default, meaning the flow continues. Check your courier configuration under Tenant settings → Notifications before publishing a flow that depends on this block.


Block id: verification_check  ·  Available in: registration, login

Verify a user-supplied token against the stored hash written by an earlier Send Verification block. The block sets verified: true on match and can deny the flow on mismatch — place a Decision block after it if you want to offer retry attempts rather than an immediate hard stop.

On admin-created accounts, verification is typically bypassed. The editor exposes a "Skip verification check" toggle that the platform enables by default on admin-create paths, so users Cymmetri's ops team imports programmatically don't get stuck on a verification gate.

Reads from state

  • verification_token — the token the user supplied in the UI
  • expected_token — the stored token value from the earlier Send Verification output

Writes to state

  • step.<slug>.verifiedtrue when the user-supplied token matched the stored hash

Use when — as the second half of the send-and-confirm pattern. Always place it after Send Verification, with the user's input wired into verification_token.


Block id: refresh_token_validate  ·  Available in: token_refresh

Validate a refresh token at the token-refresh boundary. The block calls the OAuth2 introspect endpoint and confirms the token is active, unexpired, and unrevoked. If validation fails, the block denies the flow — the caller must send the user back through a full login.

This block is the entry point of the token_refresh trigger, which is a specialised flow type separate from Login and Registration. You will not add it to a Login flow; it belongs to the dedicated Refresh flow that the platform automatically routes /auth/refresh requests through.

Reads from state

  • session.refresh_token — the refresh token presented by the client

Writes to state

  • step.<slug>.refresh_token_validtrue when the token is active and unrevoked
  • step.<slug>.refresh_token_subject — the user ID extracted from the token's subject claim

Use when — you have a custom Refresh flow and need an explicit validation gate before re-issuing tokens.


Block id: email_verification  ·  Available in: login, registration, password_recovery, mfa_enroll, mfa_step_up

A unified alias over the Send Verification and Check Verification pair. Configure mode to send to dispatch the token, or mode to check to confirm the user's input. Using this block instead of the individual pair keeps the flow graph cleaner when the send and check steps are in the same stage.

The outputs follow the same state contract as the underlying blocks: verification_token and verification_token_expires when sending; verified when checking. Both modes are auditable and audit-redact the email address.

Reads from state

  • user_id — the identity to send to or verify against
  • verification_token — the user-supplied token (check mode only)

Writes to state

  • step.<slug>.verification_token — the plaintext token (send mode)
  • step.<slug>.verification_token_expires — ISO 8601 expiry (send mode)
  • step.<slug>.verifiedtrue when token matched (check mode)

Use when — you want a single block to represent the full email-confirmation responsibility in a stage, or when send and check happen in the same stage without a user round-trip between them.


Block id: update_user  ·  Available in: login, registration, password_recovery, mfa_enroll, mfa_step_up

A streamlined alias over Update Profile, scoped to the current user in the flow. Where Update Profile accepts explicit trait_overlay and verified_overlay inputs wired from state, Update User reads its overlay from the block's config directly. This makes it convenient for flows where the traits to write are known at flow-design time — for example, setting onboarded: true on first login — rather than being computed at runtime.

Like Update Profile, the block does not roll back on downstream failure: the trait write is visible immediately and persists.

Reads from state

  • user_id — the current user, typically from an earlier Look Up Identity

Writes to state

  • step.<slug>.updatedtrue when the trait overlay was applied
  • step.<slug>.identity_traits — the updated trait object as stored

Use when — you want to stamp a known field value onto the current user mid-flow, such as updating a last_login_method metadata field or marking a profile step as complete.


A typical Registration flow uses this sequence in the pre-registration and post-registration stages:

pre-registration
1. Email Validation — rejects disposable or malformed addresses
2. Look Up Identity — must_not_exist: true (collision guard)
3. Create Identity — mints the account
4. Send Verification — channel: email
(user receives email; enters token)
post-registration
5. Check Verification — confirms the token
6. Issue Session — terminal; hands the user a session JWT

The two stages may run in separate Flow invocations if the UI collects the verification code on a separate screen. The stage token carries state across both /submit calls.

password-reset
1. Look Up Identity — must_exist: true
2. Send Verification — channel: email
(user receives recovery link; clicks it)
3. Check Verification — confirms the recovery token
4. credential_set (password) — sets the new password
5. Issue Session — terminal

The Look Up Identity step must run even if no match is found, and the Send Verification step must appear to run even when the address is unregistered — both to honour anti-enumeration discipline. Use the default fail-open behaviour and a Delay block to equalise timing across branches.