Version: v0.4

Username / Email & Password

The password method is the most commonly used form of authentication, it requires an identifier (username, email, phone number, ...) and a password during registration and login.

ORY Kratos hashes the password after registration, password reset, and password change using the Argon2 Hashing Algorithm, the winner of the (https://github.com/P-H-C/phc-winner-argon2)[Password Hashing Competition (PHC)].

Configuration

Enabling this method is as easy as setting

path/to/my/kratos/config.yml
# $ kratos -c path/to/my/kratos/config.yml serve
selfservice:
strategies:
password:
enabled: true

in your ORY Kratos configuration. You can configure the Argon2 hasher using the following options:

path/to/my/kratos/config.yml
# $ kratos -c path/to/my/kratos/config.yml serve
hashers:
argon2:
parallelism: 1
memory: 131072 # 128MB
iterations: 3
salt_length: 16
key_length: 32

When a user signs up using this strategy, the Default Identity JSON Schema (set using identity.default_schema_url) is used:

path/to/my/kratos/config.yml
identity:
default_schema_url: file:///path/to/default-identity.schema.json
# also works with HTTP(S):
#
# default_schema_url: https://mydomain.com/path/to/default-identity.schema.json

If you don't know what that means, please read the Identity Data Model Chapter in the docs' concepts section.

For a complete reference, defaults, and description please check the Configuration Reference.

For a better understanding of security implications imposed by Argon2 Configuration, head over to Argon2 Security.

Choosing between Username, Email, Phone Number

Before you start, you need to decide what data you want to collect from your users and why! It is hard to change this decision afterwards, so make sure you've taken everything into account!

When logging in, the user will use a login identifier and a password to sign up and in. The identifier can be

  • a username - e.g. "john.doe" or "johndoe123" or "oryuser",
  • an email address - e.g. john.doe@gmail.com,
  • a phone number - e.g. +49-1234-4321-1234-4321.

All of these approaches have up- and downsides.

Using the email address as the login identifier is easy to remember, does not require additional fields (because the email address is already being collected), and is usually unique. It's usually unique because sometimes companies use a "shared" email account (e.g. office@acme.org) to access services. In that case, multiple real identities are using the same email identifier to log in.

The email address however represents a unique identifier and personally identifiable information (PII). An attacker could for example check if an email address (e.g. john.doe@gmail.com) is registered at a site (e.g. an adult website) and use that information for blackmail (see Account Enumeration Attacks).

The same considerations apply to using a phone number as the primary registration & login identifier.

Using a free text username reduces the privacy risk because it is much harder to make a connection between the username and a real world identity. It's still possible in cases where users choose a username such as "john.doe.from.newyork.1970", but finding the right username identifier is still difficult and there is plausible deniability because anyone could use that username.

A free text username however requires capturing additional fields (e.g. an email address for password resets / account recovery) and is hard to remember. It is often very difficult to find unique usernames as people tend to use a combination of their names and initials (e.g. john.doe) which has a high chance of collision. Therefore, one ends up with usernames such as john.doe1234432.

It is important to understand that ORY Kratos lowercases all password identifiers and therefore E-Mail addresses. Characters + or . which have special meaning for some E-Mail Providers (e.g. GMail) are not normalized:

  • userNAME is equal to username
  • foo@BaR.com is equal to foo@bar.com
  • foo+baz@bar.com is NOT equal to foo@bar.com
  • foo.baz@bar.com is NOT equal to foobar@bar.com

You need to decide which route you want to take.

Picking the right Identity JSON Schema

When processing an identity and its traits, the method will use JSON Schema to extract one or more identifiers.

Use Case: Email and Password

To use the email address as the login identifier, define the following Identity JSON Schema:

{
"$id": "https://example.com/registration.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
}
}
}
}
}
}
}
}

Use Case: Multiple E-Mails and Password

You can allow users to sign up with multiple E-Mail Addresses and use any of those for log in:

{
"$id": "https://example.com/registration.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Person",
"type": "object",
"properties": {
"traits": {
"type": "object",
"properties": {
"emails": {
"type": "array",
"items": {
"type": "string",
"format": "email",
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
}
}
}
}
}
}
}
}
}

Use Case: Username and Password

To use a username as the login identifier, define the following Identity JSON Schema:

{
"$id": "https://example.com/registration.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Person",
"type": "object",
"properties": {
"traits": {
"type": "object",
"properties": {
"username": {
"type": "string",
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
}
}
}
}
}
}
}
}

Use Case: Username and Email and Password

You may also mix usernames and passwords:

{
"$id": "https://example.com/registration.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
}
}
}
},
"username": {
"type": "string",
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
}
}
}
}
}
}
}
}

Use Case: Phone Number And Password

This will be addressed in a future release and is tracked as kratos#137.

Example

Assuming your Identity JSON Schema is as follows:

{
"$id": "https://example.com/example.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Person",
"type": "object",
"properties": {
"traits": {
"type": "object",
"properties": {
"first_name": {
"type": "string"
},
"email": {
"type": "string",
"format": "email",
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
}
}
}
},
"username": {
"type": "string",
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
}
}
}
}
},
"additionalProperties": false
}
}
}

And an identity registers with the following JSON payload (more on registration in Selfservice Registration):

{
"traits": {
"first_name": "John Doe",
"email": "john.doe@example.org",
"username": "johndoe123"
},
"password": "my-secret-password"
}

The password method would generate a credentials block as follows:

credentials:
password:
id: password
identifiers:
- john.doe@example.org
- johndoe123
config:
hashed_password: ... # this would be `argon2(my-secret-password)`

Because credential identifiers need to be unique, no other identity can be created that has johndoe123 or john.doe@example.org as their email or username.

Last updated on by aeneasr