Skip to main content

Identity Schema

An identity ("user", "user account", "account", "subject") is the "who" of a software system. It can be a customer, employee, user, contractor, or even a programmatic identity such as an IoT device, application, or some other type of "robot."

info

In Ory Kratos' terminology we call all of them "identities", and it's always exposed as identity in the API endpoints, requests, and response payloads. In the documentation however, we mix these words as "account recovery" or "account activation" is a widely accepted and understood terminology and user flow, while "identity recovery" or "identity activation" isn't.

The following examples use YAML for improved readability. However, the API payload is usually in JSON format. An identity has the following properties:

curl http://kratos/admin/identities/9f425a8d-7efc-4768-8f23-7647a74fdf13
# A UUID that's generated when the identity is created and
# which can't be changed or updated at a later stage.
id: '9f425a8d-7efc-4768-8f23-7647a74fdf13'

# Every identity has a state. Inactive identities won't be able to log into the system.
state: active

# This section represents all the credentials associated with this identity.
# It's further explained in the "Credentials" section.
credentials:
password:
id: password
identifiers:
- john.doe@acme.com
- johnd@ory.sh
config:
hashed_password: ...
oidc:
id: oidc
identifiers:
- google:j8kf7a3...
- facebook:83475891...
config:
- provider: google
identifier: j8kf7a3
- provider: facebook
identifier: 83475891

# This is the JSON Schema ID used for validating the identities' traits.
schema_id: default

# Traits represent information about the identity, such as the first or last name. The traits content is
# up to you and will be validated using the JSON Schema at `traits_schema_url`.
traits:
# These are just examples
email: office@ory.sh
name:
first: Aeneas
last: Rekkas
favorite_animal: Dog
accepted_tos: true

Identity State

Identities are

  • created - via API or self-service registration;
  • updated - via API or self-service settings, account recovery, etc.;
  • inactive - via API only;
  • deleted - via API or with a self-service flow (not yet implemented see #596).

The identity state is therefore active or inactive.

An inactive identity won't be able to log into the system. It will receive a 401 with a reason indicating that the account has been disabled. More states will be added later on for specific features.

Identity Traits and JSON Schemas

Traits are data associated with an identity. You have to define its schema according to your application's needs. They're also supposed to be modified by the identity itself for example as part of the registration or profile update process as well as anyone having access to Ory Krato's Admin API.

Ory Kratos uses JSON Schema to validate Identity Traits.

Ory Kratos defines JSON Schema extension "Vocabulary" that allows you to tell Ory Kratos that a specific trait adds some specific meaning to the standard JSON Schema (more on that later).

Each identity can, theoretically, have a different JSON Schema. This is useful in the following situations:

  • there is more than one type of identity in the system for instance customers, support or staff;
  • the system includes both users and robots sometimes also known as named service accounts;
  • the system needs to ingest another company's Identity Schema, and
  • the system's Identity Schema changes or grows over time and requires versioning.

The following example illustrates a usage scenario with three types of identities: Regular customers, grandfather accounts, and Service Accounts (for example Microsoft provides Service Accounts). There would be one JSON Schema per type of identity:

  • Customers: http://mydomain.com/schemas/v2/customer.schema.json
  • Grandfather Accounts: http://mydomain.com/schemas/v1/customer.schema.json
  • Service Accounts: http://mydomain.com/schemas/service-account.schema.json

Ory Kratos expects the JSON Schemas in its configuration file:

identity:
# This will be the default JSON Schema. If `schema_id` is empty when creating an identity using the
# Admin API, or a user signs up using a selfservice flow, this schema will be used.
#
# This is a required configuration field!
default_schema_id: person

# Optionally define additional schemas here:
schemas:
# When creating an identity that uses this schema, `traits_schema_id: customer` would be set for that identity.
- id: customer
url: http://foo.bar.com/customer.schema.json
- id: person
url: http://foo.bar.com/person.schema.json

Ory Kratos validates the Identity Traits against the corresponding schema on all writing operations (create / update). The employed business logic must be able to distinguish these three types of identities. You might use a switch statement like in the following example:

// This is an example program that can deal with all three types of identities
session, err := ory.SessionFromRequest(r)
// some error handling
switch (session.Identity.SchemaID) {
case "customer":
// ...
case "employee":
// ...
case "default":
fallthrough
default:
// ...
}

Sensitive Data in Identity Schema

warning

The Identity Schema isn't a place to store sensitive information that should not be visible to the end-user!

The Identity Schema isn't the right place to store data that should be obfuscated from the user! Users can see traits and other data - except credentials - using the sessions/whoami endpoint. Users are also able to edit identity traits. Visit this issue for information on a feature that can be configured to prevent the end-user from viewing/editing identity traits.

Identity Schema Vocabulary Extensions

Because Ory Kratos doesn't know that a particular field has a system-relevant meaning you have to specify these in the schema. This includes for example:

  • The email address for recovering a lost password
  • The identifier for logging in with a password such as username or email
  • The phone number for enabling SMS 2FA
  • ...

Ory Kratos' JSON Schema Vocabulary Extension can be used within a property:

{
"$id": "http://mydomain.com/schemas/v2/customer.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "A customer (v2)",
"type": "object",
"properties": {
"traits": {
"type": "object",
"properties": {
"email": {
"title": "E-Mail",
"type": "string",
"format": "email",

// This tells Ory Kratos that the field should be used as the "username" for the username+password flow.
// It's an extension to the regular JSON Schema vocabulary.
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
}
}
}
}
}
}
}
}

An overview of available configuration options follows in the next sections.

Identifier for Username and Password Flows

You can configure Ory Kratos to use specific fields as the identifier such as username, email, phone number, etc., in the Username and Password Registration and Login Flow:

{
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
}
}
}
}

Email

Looking at the traits from above

traits:
# These are just examples
email: office@ory.sh
name:
first: Aeneas
last: Rekkas
favorite_animal: Dog
accepted_tos: true

and using a JSON Schema that uses the email field as the identifier for the password flow

{
"$id": "http://mydomain.com/schemas/v2/customer.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "A customer (v2)",
"type": "object",
"properties": {
"traits": {
"type": "object",
"properties": {
"email": {
"title": "E-Mail",
"type": "string",
"format": "email",

// This tells Ory Kratos that the field should be used as the "username" for the Username and Password Flow.
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
}
}
}
},
"name": {
"type": "object",
"properties": {
"first": {
"type": "string"
},
"last": {
"type": "string"
}
}
},
"favorite_animal": {
"type": "string"
},
"accepted_tos": {
"type": "string"
}
},
"required": ["email"],
"additionalProperties": false
}
}
}

In this example, Ory Kratos understands that traits✉️ office@ory.sh is the identity's identifier. The system expects office@ory.sh plus a password to sign in.

Username and Password Credentials contains more information and examples about credentials usage.

Note that "format" field of identity schema will perform validation of given trait. In this example email address of identity will be validated using JSONSchema ruleset.

Phone number

Ory Kratos also has phone number identity trait extension. Phone number trait will allow users to recover and verify account by SMS. For a moment this functionality is in development #1451.

Let's extend identity schema from previous chapter with phone number:

{
"$id": "http://mydomain.com/schemas/v2/customer.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "A customer (v2)",
"type": "object",
"properties": {
"traits": {
"type": "object",
"properties": {
"email": {
"title": "E-Mail",
"type": "string",
"format": "email",

// This tells Ory Kratos that the field should be used as the "username" for the Username and Password Flow.
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
}
}
}
},
"phone": {
"title": "Phone",
"type": "string",
"format": "tel",

// Let's mark phone number as identifier. This allows the user to login with both email and phone.
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
}
}
}
},
"name": {
"type": "object",
"properties": {
"first": {
"type": "string"
},
"last": {
"type": "string"
}
}
},
"favorite_animal": {
"type": "string"
},
"accepted_tos": {
"type": "string"
}
},
"required": ["email"],
"additionalProperties": false
}
}
}

By using "format": "tel" field we enable validation of phone numbers using golang port of Google's libphonenumber.

There are no other extensions supported for Identity Traits. Further fields will be added in future releases!

Best Practices for Updating Identity Schemas

We strongly encourage everyone to specify unique (for example versioned) identifiers for every identity schema defined. This allows you to gradually update your identity schema without affecting existing identities. Assume you just defined your first Identity Schema:

identity:
default_schema_id: user_v0
schemas:
- id: user_v0
url: file://path/to/user_v0.json

Weeks later you might notice that you want some additional fields, or want to break compatibility with your current schema. Just add another version to the schema and change the default_schema_id:

identity:
default_schema_id: user_v1
schemas:
- id: user_v0
url: file://path/to/user_v0.json
- id: user_v1
url: file://path/to/user_v1.json

All existing identities will continue to work as expected, having their identity schema ID be user_v0. All new identities will user user_v1! If you are ready to do a migration, you can list all identities in your system with user_v0 as the schema, and update them to user_v1 with the required data transformations using the REST APIs!

Sanitize Usernames/Traits

To make sure usernames (or traits) satisfy a specific regex (for example only alphanumeric characters), they can be sanitized. To sanitize usernames add Regular Expressions to the Ory Kratos Identity Schema. To sanitize usernames coming from third-party OIDC providers like Google or GitHub write Jsonnet. Learn more about Data Mapping with Jsonnet.