Address verification
Ory allows users to verify email addresses or phone numbers associated with their accounts. This is important to prove that the user has access to the address they used to create their account. If verification is enabled, Ory Identities starts the verification process automatically when users sign up. Users can also verify their addresses manually.
The verification flow is supported in both browsers and API clients and can be summarized as the following state machine:
Completing account verification doesn't guarantee that the account is used by the person who performed the verification. We recommend implementing additional security mechanisms to ensure that verified accounts aren't taken over by malicious actors, such as TOTP or FIDO2/WebAuthn.
Configuration
- Ory Console
- Ory CLI
To configure account verification, go to Authentication → Email verification in the Ory Console
For SMS verification to work, you'll also need to configure a courier channel with the ID set to sms
via the CLI. See the
courier documentation for more information.
-
Download the Ory Identities config from your project and save it to a file:
## List all available projects
ory list projects
## Get config
ory get identity-config {project-id} --format yaml > identity-config.yaml -
Add the configuration for the verification flow
config.ymlselfservice:
methods:
code: # or link
enabled: true
config:
# Defines how long the verification or the recovery code is valid for (default 1h)
lifespan: 15m
flows:
verification:
use: code # Defines which method is used, one of 'code' or 'link'.
enabled: true
# Defines how long the verification flow (the UI interaction, not the link!)
# is valid for (default 1h)
lifespan: 15m
# Whether to notify unknown addresses, if verification is requested for them
notify_unknown_recipients: false -
Update the Ory Identities configuration using the file you worked with:
ory update identity-config {project-id} --file updated_config.yaml
Identity schema
To make an address verifiable, it must be marked as such in the
identity schema. In most cases this is the email address the user
provides when registering their account. Other fields inside the traits
section are supported as well.
{
"$id": "https://schemas.ory.sh/presets/kratos/quickstart/email-password/identity.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Person",
"type": "object",
"properties": {
"traits": {
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email",
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
}
},
+ "verification": {
+ "via": "email"
+ }
}
}
},
"additionalProperties": false
}
}
}
Attempted verification notifications
When this option is on and users attempt to initiate verification for unregistered addresses, the system sends an attempted verification notification to the email address that was used in the attempt. This prevents account enumeration attacks as explained in this blog post by Troy Hunt.
By default, this feature is disabled in newly created Ory Network projects.
Follow these steps to enable sending attempted verification notifications:
- Ory Console
- Ory CLI
Go to Authentication → Email verification in the Ory Console and toggle Notify unknown recipients on.
-
Download the Ory Identities config from your project and save it to a file:
## List all available projects
ory list projects
## Get config
ory get identity-config {project-id} --format yaml > identity-config.yaml -
Set
notify_unknown_recipients
totrue
:identity-config.yamlflows:
verification:
enabled: true
lifespan: 15m # Defines how much time the user has to complete the verification flow in the UI. Default: 1h.
use: code # Defines which method is used, one of 'code' or 'link'.
notify_unknown_recipients: true # Defines if the system sends attempted verification notifications to unregistered addresses. -
Update the Ory Identities configuration using the file you worked with:
ory update identity-config {project-id} --file identity-config.yaml
Email templates
Ory Identities comes with default email templates for verification flows.
You can quickly replace the defaults and customize the messages to match the look and feel of your solution. Read the custom email template documentation to learn more.
Allow login only with verified email
To allow only the users with a verified email to sign in, follow these steps:
- Ory Console
- Ory CLI
Go to Authentication → Email verification in the Ory Console and enable Require Verified Address for Login.
-
Download the Ory Identities config from your project and save it to a file:
## List all available projects
ory list projects
## Get config
ory get identity-config {project-id} --format yaml > identity-config.yaml -
Add the configuration for the verification flow
selfservice:
flows:
login:
+ after:
+ hooks:
+ - hook: require_verified_address -
Update the Ory Identities configuration using the file you worked with:
ory update identity-config {project-id} --file updated_config.yaml
For more information see the hooks configuration documentation.
Carry over verified status from Social Sign-In
Some Social Sign-In providers like Google return the verified status of the email address. To carry over the verified status from
the Social Sign-In provider, return verified_addresses
in your Social Sign-In Jsonnet snippet:
local claims = {
email_verified: false,
} + std.extVar('claims');
{
identity: {
traits: {
[if 'email' in claims && claims.email_verified then 'email' else null]: claims.email,
given_name: claims.given_name,
family_name: claims.family_name,
},
verified_addresses: std.prune([
// Carry over verified status from Social Sign-In provider.
if 'email' in claims && claims.email_verified then { via: 'email', value: claims.email },
]),
},
}
Please note that this only works if the verified address is also present in the identity's traits and marked as a verifiable email.
{
$id: "https://example.com/person.schema.json",
$schema: "http://json-schema.org/draft-07/schema#",
title: "Person",
type: "object",
properties: {
traits: {
type: "object",
properties: {
email: {
format: "email",
type: "string",
"ory.sh/kratos": {
verification: {
via: "email",
},
},
},
},
required: ["subject"],
},
},
}
If the verified address is not present in the identity's traits, the verified status is not carried over.
Phone number verification
To send SMS messages, you need to have a trait in your identity schema that holds the phone number. The trait must be marked as a
verifiable address via the verification
extension. Here's an example of how to define such a trait in the identity schema:
{
"$id": "https://schemas.ory.sh/presets/kratos/quickstart/phone-password/identity.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Person",
"type": "object",
"properties": {
"traits": {
"type": "object",
"properties": {
"email": {
"type": "string",
"title": "E-Mail",
"format": "email",
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
}
},
"verification": {
"via": "email"
}
}
},
"phone": {
"type": "string",
"title": "Phone number",
"format": "tel",
"ory.sh/kratos": {
"verification": {
"via": "sms"
}
}
}
},
"additionalProperties": false
}
}
}
Make sure to configure an SMS channel in the Ory configuration. See the SMS documentation.
Choosing the right strategy
Ory supports two strategies for verifying your user's addresses.
- One-time codes
- Magic Links
When using one-time codes to verify a user's address, Ory Identities sends an email with a 6-digit code to the user. They must enter the code in a dedicated UI text field to verify their address.
The email also contains a link, that takes the user to the verification form with the code pre-filled in the appropriate form field. The only thing the user must do to verify their address is to submit the form.
When using the "magic link" method, Ory Identities sends the user an email with a verification link. If the user has access to the email associated with the account and clicks the link, Ory Identities marks that address as verified.
If the user completes the verification after the link or code expired, they must provide the email address associated with their account to get a new verification email.
Comparison
"One-time code" (code
) is the default, preferred, and recommended method by Ory.
Ory supports "magic links", but considers this method a legacy solution. Currently, the method is supported but should be considered deprecated and is set to be removed in future releases.
Consider using the code
method as it mitigates many of the drawbacks of "magic links":
- Some email virus scanners open links in emails to scan them. This invalidates the link and may prevent users from completing the flow even if they have the access to the defined address.
- Flows initialized by apps on mobile phones or smart devices don't work with links.
- Depending on the device settings, clicking a link from an email can open a different browser than the one used to initialize the flow. This can confuse your users.
When you change the strategy from link
to code
in an existing project, you might need to adjust your UI. Make sure the flow
works correctly with your UI implementation after changing the strategy.
Showing the verification flow after settings, registration or login
To show the verification flow directly after the user has registered, see the registration documentation.
For settings, see the settings documentation.
And for login, see the login customization documentation.
Code examples
The user interface for account verification is a page in your solution that renders the actual form elements for the user.
In contrast to other identity systems, Ory Identities (Ory Kratos) doesn't render this HTML directly. Instead, you need to implement the HTML code in your solution, which gives you complete flexibility and customizability in your user interface flows and designs. This part of your application then directly interfaces with Ory Identities through the API.
The API responds with a JSON document describing the form elements to render and actions the form should take upon submission, cancellation, etc. The following shows examples for a few different languages and frameworks.
- Browser UI
- Golang (API Flow)
- Express.js
- React.js
- React Native
- Verification View
- Generic Form View
- Example Input Form Element
- Generic Form View
- Example Input Form Element