Setting up identity schema with "Recovery via SMS" throwing error
Preflight checklist
- [X] I could not find a solution in the existing issues, docs, nor discussions.
- [X] I agree to follow this project's Code of Conduct.
- [X] I have read and am following this repository's Contribution Guidelines.
- [X] I have joined the Ory Community Slack.
- [X] I am signed up to the Ory Security Patch Newsletter.
Ory Network Project
No response
Describe the bug
Getting the following error when I add a phone number to the identity schema with recovery via SMS. Is this expected, or is the documentation unclear?
| The configuration contains values or keys which are invalid:
| properties.traits.properties.phone.ory\.sh/kratos.recovery.via: sms
| ^-- value must be "email"
btw, schema is copied from Kratos documentation - link
Reproducing the bug
- Update identity schema with phone number support.
- While adding a phone number to schema, configure it, recovery via sms
- Run docker-compose
quickstart.yml:
version: '3.7'
services:
kratos-migrate:
image: oryd/kratos:v1.3.1
environment:
- DSN=sqlite:///var/lib/sqlite/db.sqlite?_fk=true&mode=rwc
volumes:
- type: volume
source: kratos-sqlite
target: /var/lib/sqlite
read_only: false
- type: bind
source: ./contrib/quickstart/kratos/email-password
target: /etc/config/kratos
command: -c /etc/config/kratos/kratos.yml migrate sql -e --yes
restart: on-failure
networks:
- intranet
kratos-selfservice-ui-node:
image: oryd/kratos-selfservice-ui-node:v1.3.1
environment:
- KRATOS_PUBLIC_URL=http://kratos:4433/
- KRATOS_BROWSER_URL=http://127.0.0.1:4433/
- COOKIE_SECRET=changeme
- CSRF_COOKIE_NAME=ory_csrf_ui
- CSRF_COOKIE_SECRET=changeme
networks:
- intranet
restart: on-failure
kratos:
depends_on:
- kratos-migrate
image: oryd/kratos:v1.3.1
ports:
- '4433:4433' # public
- '4434:4434' # admin
restart: unless-stopped
environment:
- DSN=sqlite:///var/lib/sqlite/db.sqlite?_fk=true
- LOG_LEVEL=trace
command: serve -c /etc/config/kratos/kratos.yml --dev --watch-courier
volumes:
- type: volume
source: kratos-sqlite
target: /var/lib/sqlite
read_only: false
- type: bind
source: ./contrib/quickstart/kratos/email-password
target: /etc/config/kratos
networks:
- intranet
mailslurper:
image: oryd/mailslurper:latest-smtps
ports:
- '4436:4436'
- '4437:4437'
networks:
- intranet
networks:
intranet:
volumes:
kratos-sqlite:
Relevant log output
| I[#] S[#/allOf/1] allOf failed
| I[#/properties/traits/properties/phone] S[#/allOf/1/properties/properties/properties/traits/properties/properties/patternProperties/.%2A/allOf/0] allOf failed
| I[#/properties/traits/properties/phone] S[#/allOf/1/properties/properties/properties/traits/properties/properties/patternProperties/.%2A/allOf/0/$ref] doesn't validate with "ory://identity-extension#"
| I[#/properties/traits/properties/phone] S[#/allOf/0] allOf failed
| I[#/properties/traits/properties/phone/ory.sh~1kratos/recovery/via] S[#/allOf/0/properties/ory.sh~1kratos/properties/recovery/properties/via/enum] value must be "email"
exited with code 1
| time=2024-12-20T05:25:48Z level=debug msg=Adding config files. func=github.com/ory/x/configx.(*Provider).createProviders file=/go/pkg/mod/github.com/ory/[email protected]/configx/provider.go:144 audience=application files=[/etc/config/kratos/kratos.yml] service_name=Ory Kratos service_version=v1.3.1
|
| The configuration contains values or keys which are invalid:
| The configuration contains values or keys which are invalid:
| properties.traits.properties.phone: map[format:tel minLength:3 ory.sh/kratos:map[credentials:map[code:map[identifier:true via:sms] passkey:map[display_name:true] password:map[identifier:true] totp:map[account_name:true]] recovery:map[via:sms] verification:map[via:sms]] title:Phone type:string]
| ^-- allOf failed
|
| The configuration contains values or keys which are invalid:
| properties.traits.properties.phone: map[format:tel minLength:3 ory.sh/kratos:map[credentials:map[code:map[identifier:true via:sms] passkey:map[display_name:true] password:map[identifier:true] totp:map[account_name:true]] recovery:map[via:sms] verification:map[via:sms]] title:Phone type:string]
| ^-- doesn't validate with "ory://identity-extension#"
|
| The configuration contains values or keys which are invalid:
| properties.traits.properties.phone: map[format:tel minLength:3 ory.sh/kratos:map[credentials:map[code:map[identifier:true via:sms] passkey:map[display_name:true] password:map[identifier:true] totp:map[account_name:true]] recovery:map[via:sms] verification:map[via:sms]] title:Phone type:string]
| ^-- allOf failed
|
| The configuration contains values or keys which are invalid:
| properties.traits.properties.phone.ory\.sh/kratos.recovery.via: sms
| ^-- value must be "email"
Relevant configuration
{
"$id": "your_schema_id",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Person",
"type": "object",
"properties": {
"traits": {
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email",
"title": "E-Mail",
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
},
"totp": {
"account_name": true
},
"code": {
"identifier": true,
"via": "email"
},
"passkey": {
"display_name": true
}
},
"recovery": {
"via": "email"
},
"verification": {
"via": "email"
}
},
"maxLength": 320
},
"phone": {
"type": "string",
"format": "tel",
"title": "Phone number",
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
},
"code": {
"identifier": true,
"via": "sms"
}
},
"recovery": {
"via": "sms"
},
"verification": {
"via": "sms"
}
},
"maxLength": 320
}
},
"required": ["email"],
"additionalProperties": false
}
}
}
Version
1.3.1
On which operating system are you observing this issue?
None
In which environment are you deploying?
None
Additional Context
No response
got the same issue
I see the same issue using the latest stable version as of this moment. If you use the schema from the official docs, Identity schema extensions section, Kratos fails to parse it.
In the UI, the error is displayed like this:
{
"id": "c539c163-0f27-467e-8452-b6285518ddf2",
"error": {
"code": 500,
"status": "Internal Server Error",
"message": "json-schema \"file:///etc/config/kratos/identity.schema.json\" compilation failed. Reason:\nI[#] S[#] doesn't validate with \"ory://identity-extension#\"\n I[#] S[#/allOf/1] allOf failed\n I[#/properties] S[#/allOf/1/patternProperties/.%2A/$ref] doesn't validate with \"#\"\n I[#/properties] S[#/allOf/1] allOf failed\n I[#/properties/traits] S[#/allOf/1/patternProperties/.%2A/$ref] doesn't validate with \"#\"\n I[#/properties/traits] S[#/allOf/1] allOf failed\n I[#/properties/traits/properties] S[#/allOf/1/patternProperties/.%2A/$ref] doesn't validate with \"#\"\n I[#/properties/traits/properties] S[#/allOf/1] allOf failed\n I[#/properties/traits/properties/phone] S[#/allOf/1/patternProperties/.%2A/$ref] doesn't validate with \"#\"\n I[#/properties/traits/properties/phone] S[#/allOf/0] allOf failed\n I[#/properties/traits/properties/phone/ory.sh~1kratos/recovery/via] S[#/allOf/0/properties/ory.sh~1kratos/properties/recovery/properties/via/enum] value must be \"email\""
},
"created_at": "2025-06-06T10:32:09.566206Z",
"updated_at": "2025-06-06T10:32:09.566206Z"
}
This error happens because the Ory identity extension schema does not support the "sms" recovery method.
If you remove the "recovery": { "via": "sms" } from your schema definition, or change it to "recovery": { "via": "email" }, the error disappears.
This makes sense since, in the case of phone number loss, recovery via SMS won't help you, and you need to use another recovery method to regain access to your account. The problem is more with the documentation than with the code.
@aeneasr @vinckr Could you confirm if this is a correct assumption?
does not support
Why though? Phone numbers are primary drivers of businesses in lots of countries. In fact, email addresses lose to phone number usage in Africa. A "lot" of adults forget their email account passwords (and the usernames too), but they guard their phone numbers like their lives depend on it.
WhatsApp has evolved into a microbusiness platform and all that traffic/economy is powered by phone number ownership and SMS-based verification. I understand mileage varies across geozones, but both email addresses AND phone numbers should be given equal treatment, leaving the "importance" up to the Kratos user to configure. Most mobile apps just prompt for phone number only and don't even support email addresses in their business domain. If we cannot build a complete experience around phone numbers only, then Kratos has intentionally rejected adoption by businesses with that requirement. I'm representing one of such businesses and just landed here after getting the config error. A lot of time was spent getting here and I'm quite disappointed.
It's appears everything needed to support this is already in place, so why not extend it? Unless it's considered trivial because the perspective of phone numbers being 1st party like email addresses is was missing when considering this as a feature I guess?