kratos icon indicating copy to clipboard operation
kratos copied to clipboard

Setting up identity schema with "Recovery via SMS" throwing error

Open kgsnaidu opened this issue 11 months ago • 4 comments

Preflight checklist

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

  1. Update identity schema with phone number support.
  2. While adding a phone number to schema, configure it, recovery via sms
  3. 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

kgsnaidu avatar Jan 06 '25 05:01 kgsnaidu

got the same issue

vuquang23 avatar May 30 '25 21:05 vuquang23

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"
}

icamys avatar Jun 06 '25 10:06 icamys

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?

icamys avatar Jun 06 '25 10:06 icamys

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?

originswift-sys avatar Aug 08 '25 16:08 originswift-sys