Address verification
Address verification ensures that a user’s email or phone number is valid and belongs to them. It helps prevent spam, ensures delivery of important notifications, and maintains system integrity.
Ory supports these verification policies:
- Require verified addresses during sign up and/or login.
- Allow optional verification. Users can choose to verify their email or phone number, but it’s not required or enforced by the UI.
Require verification on login
To require address verification at login, use the require_verified_address action. It requires at least one verified address for
the identity. You can enable it using either the Ory Console or CLI.
- Ory Console
- Ory CLI
- Go to Authentication → Account verification in the Ory Console.
- Enable Require Verified Address for Login.
- Click Save.
Run:
ory patch identity-config --project <project-id> --workspace <workspace-id> \
--add '/selfservice/flows/login/after/password/hooks/0/hook="require_verified_address"'
If the identity schema defines multiple verifiable addresses, Ory sends a verification code to the first one and redirects the user to the verification flow.
If none of the identity's verifiable addresses are verified, a code will be sent to the first email or phone number in the list. If at least one address is verified, Ory will not ask for verification.
- Server rendered browser client
- SPA & Native clients
For HTML form submissions, the POST /self-service/login endpoint responds with an HTTP 302 redirect to the verification flow.
For AJAX (Accept: application/json) or native clients using /self-service/login/api, the endpoint responds with a 400 error:
{
"id": "session_verified_address_required",
"code": 400,
"status": "Bad Request",
"reason": "Your account's email or phone address are not verified yet. Please check your email or phone inbox or re-request verification.",
"details": {
"continue_with": [
{
"action": "show_verification_ui",
"flow": {
"id": "7f4dfb3b-c3cc-4e35-9f09-286b09e77beb",
"verifiable_address": "user@example.com",
"url": "https://<your-slug>.projects.oryapis.com/verification?flow=7f4dfb3b-c3cc-4e35-9f09-286b09e77beb"
}
}
]
},
"message": "your email or phone address is not yet verified"
}
Legacy compatibility
Before May 2025, require_verified_address returned a 400 error without sending a verification code. This behavior is deprecated.
To re-enable it:
ory patch identity-config --project <project-id> --workspace <workspace-id> \
--add '/feature_flags/legacy_require_verified_login_error=true'
The verification and show_verification_ui actions in login flows (but not sign up!) are also deprecated. Use
require_verified_address instead.
Verified-address login error (legacy_require_verified_login_error)
When the "require verified address" login hook blocks a login because the address is not yet verified, the response changed. The
legacy behavior returned a 400 Bad Request with a static error and skipped the check for non-password methods (such as social
sign-in). The new behavior starts a verification flow and returns an actionable continue_with entry — 403 Forbidden with
continue_with for API clients, or a 303 redirect to the verification screen for browser clients — and applies to all login
methods. The feature_flags.legacy_require_verified_login_error flag restores the old behavior and defaults to false.
Am I affected?
You are affected if any of the following apply:
- Your configuration sets
feature_flags.legacy_require_verified_login_error: true. - You enforce verified addresses at login and your client handles the unverified case by checking for a
400 Bad Requesterror rather than parsingcontinue_with(or following the browser redirect). - You rely on social sign-in / OIDC logins bypassing the verified-address requirement.
If your client already parses continue_with (or follows the verification redirect) on login, you are not affected.
Why was this change made?
Returning a verification continue_with instead of a terminal error lets users recover from an unverified-address login without a
dead end, and applying the check to all login methods closes a gap where social sign-in could bypass the requirement.
How to adapt to this change?
Update your login client to handle the new response before disabling the legacy flag:
- For API / SDK clients, handle
403 Forbiddenand read theshow_verification_uiaction from thecontinue_witharray to send the user into the verification flow. - For browser clients, follow the
303redirect to the verification screen. - If you use social sign-in / OIDC, confirm that requiring a verified address for those logins is acceptable, because the new behavior no longer exempts them.
- Ory Network
- Self-hosted (OSS or OEL)
After your login client handles the continue_with verification response, disable
feature_flags.legacy_require_verified_login_error in Project settings → Advanced in the Ory Console.
After your login client handles the continue_with verification response, set
feature_flags.legacy_require_verified_login_error to false in your Kratos configuration and redeploy.
Verification on sign up
Ory supports two options after sign up:
Optional verification
Users sign up without address verification, but a code is sent. They can verify later. By default, Ory follows this behavior.
Required verification
Users must verify their address before getting a session. After registration, they’re redirected to the verification flow.
If the identity schema includes multiple verifiable addresses, the code is sent to the first one.
To enable this:
- Go to Authentication → Account verification in the Ory Console.
- Enable Show verification screen after password registration.
Or with the CLI:
ory patch identity-config "$PROJECT_ID" \
--add '/selfservice/flows/registration/after/password/hooks/0/hook="show_verification_ui"' \
--add '/selfservice/flows/registration/after/oidc/hooks/0/hook="show_verification_ui"' \
--add '/selfservice/flows/registration/after/webauthn/hooks/0/hook="show_verification_ui"'
- Server rendered browser client
- SPA & Native clients
For browser clients using native forms, Ory redirects to the verification flow with HTTP 302.
The registration endpoint returns a 400 error with a continue_with field that contains the verification flow:
{
"id": "...",
"ui": {
"action": "...",
"method": "...",
"nodes": [
/* ... */
]
},
"continue_with": [
{
"action": "show_verification_ui",
"flow": {
"id": "d859f6af-1dfe-453e-9320-d572e10edeea",
"verifiable_address": "example@ory.com",
"url": "https://ory.example.org/verification?flow=d859f6af-1dfe-453e-9320-d572e10edeea"
}
}
]
}
Legacy compatibility
In projects created before May 2025, the registration response includes continue_with even if Show verification screen after
password registration is off.
To re-enable this legacy behavior:
ory patch identity-config --project <project-id> --workspace <workspace-id> \
--add '/feature_flags/legacy_continue_with_verification_ui=true'
Verification UI in continue_with (legacy_continue_with_verification_ui)
After registration, login, or settings, Kratos can tell the client to show a verification screen by adding a
show_verification_ui entry to the flow's continue_with array. Previously this entry was added automatically for every
unverified address. Going forward, it is only added when you explicitly enable the show_verification_ui hook. The
feature_flags.legacy_continue_with_verification_ui flag restores the automatic behavior and defaults to false.
Am I affected?
You are affected if any of the following apply:
- Your configuration sets
feature_flags.legacy_continue_with_verification_ui: true. - Your UI or SDK reads
continue_withfor ashow_verification_uiaction and you have not added theshow_verification_uihook to your post-registration / post-login / post-settings hooks.
If you already configure the show_verification_ui hook, or you do not rely on the verification continue_with entry, you are not
affected.
Why was this change made?
Making the verification screen an explicit hook gives you control over when the verification UI is surfaced, instead of Kratos
always emitting it. It also makes the verification continue_with entry behave like other continue_with actions, which are
driven by hooks.
How to adapt to this change?
Add the show_verification_ui hook to the after hooks of every flow where you want the verification screen surfaced
(registration, login, and settings as applicable). Once the hook is configured, your client receives the same
show_verification_ui entry in continue_with, and you can set the legacy flag to false.
selfservice:
flows:
registration:
after:
hooks:
- hook: show_verification_ui
login:
after:
hooks:
- hook: show_verification_ui
- Ory Network
- Self-hosted (OSS or OEL)
Add the show_verification_ui hook to the relevant flows in your project's identity configuration (via the Ory CLI or the Ory
Console configuration editor), then disable
feature_flags.legacy_continue_with_verification_ui in Project settings → Advanced in the Ory Console.
Add the show_verification_ui hook to the relevant flows in your Kratos configuration, set
feature_flags.legacy_continue_with_verification_ui to false, and redeploy.
Verification on address change
When a user updates their email address or phone number in the settings flow, Ory sends a verification code to the new address. By default, the settings flow will display a success message when the profile is updated, but the address remains unverified until the user completes the verification process.
Show verification screen after address change
If you want users to be immediately redirected to verify their new address after changing it, you can configure the
show_verification_ui hook for the settings flow. This will redirect the user to the verification screen instead of showing a
success message.
To enable this behavior, use the Ory CLI:
ory patch identity-config {project_id} \
--add '/selfservice/flows/settings/after/profile/hooks/0/hook="show_verification_ui"'
- Server rendered browser client
- SPA & Native clients
For browser clients using native forms, Ory redirects to the verification flow with HTTP 302.
The settings endpoint returns a 400 error with a continue_with field that contains the verification flow:
{
"id": "...",
"ui": {
"action": "...",
"method": "...",
"nodes": [
/* ... */
]
},
"continue_with": [
{
"action": "show_verification_ui",
"flow": {
"id": "d859f6af-1dfe-453e-9320-d572e10edeea",
"verifiable_address": "example@ory.com",
"url": "https://ory.example.org/verification?flow=d859f6af-1dfe-453e-9320-d572e10edeea"
}
}
]
}