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:
# 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.