<@U04UQ68083H> is it possible to customize `ui.nod...
# ory-copilot
m
@chilly-king-10285 is it possible to customize
ui.nodes
in the response when calling
/self-service/login/browser?aal=aal2
?
b
A message from kapa.ai
No, it is not possible to directly customize the contents or structure of the
ui.nodes
array in the response when calling
/self-service/login/browser?aal=aal2
through the API request itself. The
ui.nodes
are generated by Ory Kratos based on your server-side configuration (such as enabled login methods, MFA requirements, etc.) and the current flow context. You can, however, control which authentication methods are available (e.g., password, OIDC, TOTP) and how they are configured by adjusting your Ory Identities (Kratos) configuration. This will affect which nodes are included in the response, but you cannot arbitrarily add, remove, or mutate nodes via the API call or query parameters. If you want to change how the UI is rendered, you should do so on the client side by filtering, grouping, or reordering the nodes as needed for your custom UI. The backend does not provide a way to customize the structure of
ui.nodes
per request; it only groups nodes by method (e.g., "password", "oidc", "totp") using the
group
property, which you can use to organize your UI rendering logic. This is a common point of discussion in the community, and while some have suggested more explicit grouping or form structures in the API response, this is not currently supported by Ory Kratos out of the box [Understanding UI nodes and error messages](https://www.ory.sh/docs/kratos/concepts/ui-user-interface) [Github Issue: Incorrect UI nodes for using OIDC and password flow together](https://github.com/ory/network/issues/143) [UI rendering is becoming extremely convoluted and complicated](https://github.com/ory/kratos/discussions/4152). In summary: - You cannot customize
ui.nodes
via the API call. - You can influence which nodes appear by changing your server-side configuration. - For custom UI needs, process and render the nodes as you wish on the client side.
m
@chilly-king-10285 I dont like that it leaks user’s emails. I would like user info to be authorized for fetching only when 2fa login is complete
b
A message from kapa.ai
You are correct to be concerned about leaking user information, such as email addresses, before a user has fully authenticated with 2FA. Ory supports enforcing that sensitive user information is only accessible after the user has completed the required Authenticator Assurance Level (AAL), such as AAL2 for 2FA. To achieve this, you should configure your Ory project to require the highest available AAL for sensitive operations, such as fetching user info or accessing account settings. This ensures that endpoints like
/sessions/whoami
will only return user information if the session meets the required AAL (e.g., after 2FA is completed). If the session does not meet the required AAL, Ory will return a 403 error and will not leak user information. You can enforce this by setting:
Copy code
yaml session:   whoami:     required_aal: highest_available
or, for specific flows like settings:
Copy code
yaml selfservice:   flows:     settings:       required_aal: highest_available
With this configuration, user info is only accessible after the user has completed 2FA, and attempts to fetch it before that will be blocked [Step-up authentication](https://www.ory.sh/docs/kratos/mfa/step-up-authentication) [Check AAL](https://www.ory.sh/docs/identities/get-started/mfa#check-aal) [Configure multi-factor authentication in Ory Kratos](https://www.ory.sh/docs/kratos/self-hosted/mfa). If you are building a custom UI, you should also ensure that you do not display any user-identifying information until the session is verified to be at the required AAL. This approach is recommended to prevent account enumeration and information leakage [Github Issue: Ensure that login, registration and recovery do not leak identity information](https://github.com/ory/kratos/issues/133). Summary: Set
required_aal: highest_available
for sensitive endpoints and flows to ensure user info is only accessible after 2FA is complete. This prevents leaking user emails or other sensitive data before full authentication.
m
@chilly-king-10285 when using
code
method flow and
passwordless_enabled
with email and/or sms, do emails and sms need to be unique? What about when using password flow together with
mfa_enabled
code flow?
b
A message from kapa.ai
When using the
code
method flow with
passwordless_enabled
for email and/or SMS, the identifiers (email or phone number) must be unique per credential type. This means: - If you use email or phone number as the identifier for the
code
credential (passwordless), each email or phone number can only be associated with one identity for that credential type. - The same applies to the
password
credential: the identifier (email, username, or phone number) must be unique for that credential type. However, the same identifier (e.g., an email address) can be used across different credential types for the same or different identities. For example, one identity could have the same email as both a
password
and a
code
identifier, or two different identities could have the same email if one uses it for
password
and the other for
oidc
(OpenID Connect), but not for the same credential type. > Each credential - regardless of its type - has one or more identifiers attached to it. Each identifier is universally unique. > ... While credentials must be unique per type, there can be duplicates amongst multiple types > ... If you tried to create (or update) another identity with the same identifier (
<mailto:john.doe@acme.com|john.doe@acme.com>
), the system would reject the request with a 409 Conflict state. > [Credentials - Ory Kratos Concepts](https://www.ory.sh/docs/kratos/concepts/credentials) When using the
password
flow together with
mfa_enabled
code flow (for example, password login plus code-based MFA), the uniqueness requirement still applies per credential type. So, the email or phone number used as an identifier for the
password
credential must be unique among all identities for
password
, and the same for the
code
credential. Summary: - Email and phone numbers must be unique per credential type (e.g., unique for all identities using
code
, unique for all identities using
password
). - The same identifier can be used across different credential types (e.g., the same email for both
password
and
oidc
). - This applies whether you use passwordless (
code
with
passwordless_enabled
) or combine
password
with
mfa_enabled
code flow. If you need email or phone number uniqueness to be scoped differently (e.g., per OIDC provider), this is not supported—identifiers are globally unique per credential type [kratos, login with different oidc providers, with same email address](https://github.com/ory/kratos/discussions/4162).
m
@chilly-king-10285 give me identity.schema.json for MFA - first factor being username and password and second factor being OTP code sent to email or phone number Also give me kratos config yaml
b
A message from kapa.ai
Certainly! Below is an example of an
identity.schema.json
for MFA where the first factor is username and password and the second factor is a one-time code (OTP) sent to either email or phone number. This is followed by a sample Kratos configuration YAML to enable this flow. --- ###
identity.schema.json
This schema allows users to log in with a username and password, and then receive an OTP code for MFA via either email or phone number.
Copy code
json {   "$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",           "minLength": 3,           "<http://ory.sh/kratos|ory.sh/kratos>": {             "credentials": {               "password": {                 "identifier": true               }             }           }         },         "email": {           "type": "string",           "format": "email",           "<http://ory.sh/kratos|ory.sh/kratos>": {             "credentials": {               "code": {                 "identifier": true,                 "via": "email"               }             },             "recovery": {               "via": "email"             },             "verification": {               "via": "email"             }           }         },         "phone": {           "type": "string",           "format": "tel",           "<http://ory.sh/kratos|ory.sh/kratos>": {             "credentials": {               "code": {                 "identifier": true,                 "via": "sms"               }             },             "recovery": {               "via": "sms"             },             "verification": {               "via": "sms"             }           }         }       },       "required": ["username"],       "additionalProperties": false     }   } }
- This schema enables username/password login and allows OTP codes to be sent to either email or phone for MFA. - You can require either email or phone by adding them to the
required
array as needed. References: [Customize identity schema: username and email and password](https://www.ory.sh/docs/kratos/manage-identities/customize-identity-schema#username-and-email-and-password) [Passwordless one-time code login identifier](https://www.ory.sh/docs/kratos/manage-identities/customize-identity-schema#passwordless-one-time-code-login-identifier) [MFA via SMS and Email](https://www.ory.sh/docs/kratos/mfa/mfa-via-sms) --- ###
kratos.config.yaml
Below is a minimal configuration to enable password login and code-based MFA (OTP via email or SMS):
Copy code
yaml selfservice:   methods:     password:       enabled: true     code:       enabled: true       mfa_enabled: true    flows:     settings:       required_aal: highest_available  session:   whoami:     required_aal: highest_available
- This configuration enables both password and code methods. -
mfa_enabled: true
for the
code
method enables OTP as a second factor. -
required_aal: highest_available
ensures that sensitive operations require the highest authentication level (i.e., after MFA is completed). References: [MFA via SMS and Email](https://www.ory.sh/docs/kratos/mfa/mfa-via-sms) [Configure multi-factor authentication in Ory Kratos](https://www.ory.sh/docs/kratos/self-hosted/mfa) --- If you need to configure the email/SMS delivery provider, refer to the [sending emails and SMS documentation](https://www.ory.sh/docs/kratos/emails-sms/sending-emails-smtp) for the required courier setup. If you need further customization or have a specific use case, please let me know!
m
@chilly-king-10285 with given configuration, does emails and phone numbers need to be unique? Or is it possible for two users to have same email? Ideally I would want only username to be required to be unique
b
A message from kapa.ai
With the given configuration—where username is used for password login and email/phone are used for OTP code MFA—**email and phone number must be unique per credential type**. This means: - If you configure email or phone as an identifier for the
code
credential (used for OTP), then each email or phone number can only be associated with one identity for the
code
credential. - The same applies to the
password
credential: the username must be unique for all identities using
password
. It is not possible for two users to have the same email or phone number if those fields are used as identifiers for the
code
credential. Ory Kratos enforces uniqueness of identifiers per credential type. If you try to create a second identity with the same email or phone number for the
code
credential, you will get a conflict error [Credentials - Ory Kratos Concepts](https://www.ory.sh/docs/kratos/concepts/credentials). > Each credential - regardless of its type - has one or more identifiers attached to it. Each identifier is universally unique. ... While credentials must be unique per type, there can be duplicates amongst multiple types. So, if you want only the username to be unique and allow duplicate emails or phone numbers, you cannot use those fields as identifiers for the
code
credential. If you use them for OTP delivery and as identifiers, they must be unique. If you need to allow duplicate emails/phones, you would have to not use them as identifiers for any credential type, which is not compatible with using them for passwordless or code-based login/MFA in Ory Kratos [kratos, login with different oidc providers, with same email address](https://github.com/ory/kratos/discussions/4162).
m
@chilly-king-10285 I am reading Kratos 1.3.0 release logs and it says:
Please note that the
via
parameter is deprecated when performing SMS 2FA. It will be removed in a future version. If the parameter is not included in the request, the user will see all their phone/email addresses from which to perform the flow.
What should be used instead of
via
parameter? Give me correct identity schema json for MFA
b
A message from kapa.ai
Based on the information in the knowledge sources, the
via
parameter for SMS 2FA is deprecated and will be removed in a future version. The release notes state that if the parameter is not included, the user will be presented with all their phone/email addresses to choose from when performing the flow. However, the knowledge sources do not provide a concrete example of the updated identity schema JSON that omits the
via
parameter, nor do they specify what should be used in its place. The documentation and issues confirm that the
via
parameter is still present in current schema examples, but also highlight that its use for SMS recovery is not supported and can cause errors. For example, using
"recovery": { "via": "sms" }
in the schema will result in a validation error, and only
"email"
is accepted for recovery. For verification and code credentials, the
via
parameter is still shown in examples, but the deprecation notice suggests it should be omitted for future compatibility [Setting up identity schema with "Recovery via SMS" throwing error](https://github.com/ory/kratos/issues/4262) [Cannot Verify Phone](https://github.com/ory/network/issues/406). In summary: - The knowledge sources confirm the deprecation of the
via
parameter for SMS 2FA, but do not provide a new, correct identity schema JSON for MFA without it. - There is no explicit replacement for the
via
parameter documented in the provided sources. - If you omit the
via
parameter, Ory will present all available addresses to the user for 2FA, but the exact schema format is not shown in the sources. If you want to future-proof your schema, you should omit the
via
parameter for SMS/email in the
code
credential and
verification
sections, but please note that the knowledge sources do not provide a validated example of this.
I'm sorry, but the knowledge sources do not contain enough information to provide a definitive, correct identity schema JSON for MFA without the
via
parameter.
m
@chilly-king-10285 if I have password credential and code via sms credential, can I login first with code and then with password do I have to login with password first and the nwith code?
b
A message from kapa.ai
Based on the knowledge sources, when you have both a password credential and a code via SMS credential configured, you can use either method to log in, depending on how your identity schema and self-service methods are set up. The login flow supports multiple methods, including
password
and
code
(for SMS or email), and you can choose which method to use at the start of the login flow [Login flow methods](https://www.ory.sh/docs/kratos/self-service/flows/user-login). However, for multi-factor authentication (MFA), the typical flow is: - First factor: The user logs in with their primary credential (e.g., password). - Second factor: The user is then prompted for the second factor (e.g., OTP code via SMS). The sources do not describe a flow where you log in first with the code (SMS) and then with the password as a second factor. The standard MFA setup is password (or another primary method) first, then code as the second factor [MFA overview](https://www.ory.sh/docs/kratos/mfa/overview) [MFA via SMS](https://www.ory.sh/docs/kratos/mfa/mfa-via-sms). In summary: - You can log in with either password or code as the first factor, depending on your configuration. - For MFA, the expected flow is password first, then code as the second factor. - The knowledge sources do not mention a supported flow where you log in with code first and then password as the second factor. If you need a specific order or combination, you must configure your flows accordingly, but the sources do not provide details on reversing the typical MFA order.
m
@chilly-king-10285 are there some selfservice methods and flows that are enabled by default or I need to explicitly enable what I want?
b
A message from kapa.ai
By default, you need to explicitly enable the self-service methods and flows you want to use in Ory Kratos. The configuration for self-service methods (such as
password
,
oidc
,
code
, etc.) and flows (like registration, login, recovery, settings, verification) must be set in your configuration file or through the Ory Console. For example, to enable password and OIDC login, you would configure:
Copy code
yaml selfservice:   methods:     password:       enabled: true     oidc:       enabled: true
If you do not explicitly enable a method or flow, it will not be available to users. The documentation provides configuration examples for each method and flow, and there is no mention of any self-service methods or flows being enabled by default [Registration flow methods](https://www.ory.sh/docs/kratos/self-service/flows/user-registration) [Login flow methods](https://www.ory.sh/docs/kratos/self-service/flows/user-login) [Settings flow methods](https://www.ory.sh/docs/kratos/self-service/flows/user-settings). Summary: You must explicitly enable the self-service methods and flows you want; they are not enabled by default.
m
@chilly-king-10285 when sending login code, how can i template expiration time of the token in email body?
b
A message from kapa.ai
When sending a login code, you can include the expiration time of the token in the email body using the
ExpiresInMinutes
variable in your email template. For the
login_code.valid
template, the following variables are available: - `To`: the email address to whom the email is sent - `LoginCode`: the login code - `Identity`: the identity of the email address - `ExpiresInMinutes`: the expiration time of the code in minutes You can use
{{ .ExpiresInMinutes }}
in your template to display the expiration time. For example:
Copy code
Your login code is: {{ .LoginCode }} This code will expire in {{ .ExpiresInMinutes }} minutes.
This will render the expiration time in the email sent to the user [Available variables for templates](https://www.ory.sh/docs/kratos/emails-sms/custom-email-templates#available-variables).
m
@chilly-king-10285 Getting this error
Copy code
kratos-1  | time=2025-06-19T08:04:16Z level=error msg=Unable to get email body from template. audience=application error=map[message:template: email.body.gotmpl:40:35: executing "email.body.gotmpl" at <.ExpiresInMinutes>: can't evaluate field ExpiresInMinutes in type *email.LoginCodeValidModel stack_trace:stack trace could not be recovered from error type template.ExecError] message_from=no-reply@ory.kratos.sh message_id=300e4d5a-6634-47e7-aee7-0581cb5cdabd message_nid=aa6f7269-be76-4297-8ebe-dc73527b9018 message_subject=Mobile Stock Take Login Code message_template_type=login_code_valid message_type=email service_name=Ory Kratos service_version=v1.3.1 smtp_server=mailslurper:1025 smtp_ssl_enabled=true
Kratos v1.3.1
b
A message from kapa.ai
The error message you are seeing:
Copy code
executing "email.body.gotmpl" at <.ExpiresInMinutes>: can't evaluate field ExpiresInMinutes in type *email.LoginCodeValidModel
indicates that the template is trying to use the variable
ExpiresInMinutes
, but it is not available in the context for the
login_code.valid
template in your version of Ory Kratos (v1.3.1). According to the [official documentation](https://www.ory.sh/docs/kratos/emails-sms/custom-email-templates#available-variables),
ExpiresInMinutes
should be available for the
login_code.valid
template. However, your error suggests that in Kratos v1.3.1, this variable is not actually present in the template context for this message type. What you can do: - Double-check that you are using the correct template type (
login_code.valid
). - If you are on Ory Kratos v1.3.1 and the variable is missing, it may be a bug or a documentation mismatch for this version. - As a workaround, you may need to omit
{{ .ExpiresInMinutes }}
from your template until this variable is supported for
login_code.valid
in your version. Summary: Although the documentation lists
ExpiresInMinutes
as available for
login_code.valid
, your error and the current knowledge sources indicate it is not present in Kratos v1.3.1 for this template. You will need to remove or replace
{{ .ExpiresInMinutes }}
in your template to resolve the error [Available variables for templates](https://www.ory.sh/docs/kratos/emails-sms/custom-email-templates#available-variables).
m
@chilly-king-10285 give me example of body of a request to resend code
b
A message from kapa.ai
To resend a code (for example, during a login, verification, or recovery flow using the
code
method), you typically submit a request body with the
method
set to
"code"
and include the relevant identifier (such as
email
or
identifier
). To trigger a resend, you include a field like
resend
set to
"code"
. Here is an example of a request body to resend a code during a login flow:
Copy code
json {   "method": "code",   "identifier": "<mailto:user@example.com|user@example.com>",   "resend": "code",   "csrf_token": "your-csrf-token" }
- `method`: Must be
"code"
to indicate the code-based login. - `identifier`: The user's email or phone number (depending on your configuration). - `resend`: Set to
"code"
to trigger resending the code. - `csrf_token`: Required for browser flows. This structure is reflected in the UI nodes and API documentation, where a "Resend code" button is associated with a submit action containing the
resend
field [Github Issue: Requesting a login code returns HTTP 400](https://github.com/ory/kratos/issues/4052). Note: The exact field names may vary depending on the flow (login, recovery, verification) and your identity schema, but the pattern of including
resend: "code"
is consistent for resending codes.
m
@chilly-king-10285 give me example of response when user submits
method: 'code', identifier: '<mailto:test@example.com|test@example.com>'
b
A message from kapa.ai
Here is an example of a response when a user submits a login request with
method: 'code'
and `identifier: 'test@example.com'`:
Copy code
json {   "id": "367c97cc-0499-47ec-9a3c-208d2c308445",   "organization_id": null,   "type": "api",   "expires_at": "2024-08-22T10:19:49.24531247Z",   "issued_at": "2024-08-22T10:09:49.24531247Z",   "request_url": "<http://localhost:4433/self-service/login/api>",   "active": "code",   "ui": {     "action": "<http://127.0.0.1:4433/self-service/login?flow=367c97cc-0499-47ec-9a3c-208d2c308445>",     "method": "POST",     "nodes": [       {         "type": "input",         "group": "default",         "attributes": {           "name": "csrf_token",           "type": "hidden",           "value": "",           "required": true,           "disabled": false,           "node_type": "input"         },         "messages": [],         "meta": {}       },       {         "type": "input",         "group": "default",         "attributes": {           "name": "identifier",           "type": "hidden",           "value": "<mailto:test@example.com|test@example.com>",           "required": true,           "disabled": false,           "node_type": "input"         },         "messages": [],         "meta": {           "label": {             "id": 1070002,             "text": "E-Mail",             "type": "info",             "context": {               "title": "E-Mail"             }           }         }       },       {         "type": "input",         "group": "code",         "attributes": {           "name": "method",           "type": "hidden",           "value": "code",           "disabled": false,           "node_type": "input"         },         "messages": [],         "meta": {}       },       {         "type": "input",         "group": "code",         "attributes": {           "name": "code",           "type": "text",           "required": true,           "disabled": false,           "node_type": "input"         },         "messages": [],         "meta": {           "label": {             "id": 1070013,             "text": "Login code",             "type": "info"           }         }       },       {         "type": "input",         "group": "code",         "attributes": {           "name": "method",           "type": "submit",           "value": "code",           "disabled": false,           "node_type": "input"         },         "messages": [],         "meta": {           "label": {             "id": 1070005,             "text": "Submit",             "type": "info"           }         }       },       {         "type": "input",         "group": "code",         "attributes": {           "name": "resend",           "type": "submit",           "value": "code",           "disabled": false,           "node_type": "input"         },         "messages": [],         "meta": {           "label": {             "id": 1070008,             "text": "Resend code",             "type": "info"           }         }       }     ],     "messages": [       {         "id": 1010014,         "text": "An email containing a code has been sent to the email address you provided. If you have not received an email, check the spelling of the address and retry the login.",         "type": "info"       }     ]   },   "created_at": "2024-08-22T10:09:49.251261Z",   "updated_at": "2024-08-22T10:09:49.251261Z",   "refresh": false,   "requested_aal": "aal1",   "state": "sent_email",   "transient_payload": {} }
This response includes the flow ID, UI nodes for entering the code, and a message indicating that an email with the code has been sent to the provided address [Requesting a login code returns HTTP 400](https://github.com/ory/kratos/issues/4052).
m
@chilly-king-10285 How about if user sends
method: 'code', identifier: '<tel:+4912345678|+4912345678>'
b
A message from kapa.ai
If a user sends a login request with
method: 'code'
and
identifier: '+4912345678'
(a phone number), Ory Kratos will process the request similarly to the email case, but will send the login code via SMS to the provided phone number, assuming your identity schema and configuration support code-based login via SMS. The response will include a login flow object with UI nodes for entering the code, and a message indicating that an SMS containing a code has been sent to the provided phone number. The structure of the response is similar to the email case, but the message will reference SMS instead of email. For example:
Copy code
json {   "ui": {     "nodes": [       // ... nodes for csrf_token, identifier, method, code input, submit, resend ...     ],     "messages": [       {         "id": 1010015,         "text": "An SMS containing a code has been sent to the phone number you provided. If you have not received an SMS, check the spelling of the number and retry the login.",         "type": "info"       }     ]   },   // ... other flow properties ... }
This behavior is confirmed by the documentation, which states that Ory will deliver a 6-digit code to an SMS gateway of your choice, such as Twilio or Amazon SNS, and the user will be prompted to enter the code to complete the login flow [MFA via SMS and Email](https://www.ory.sh/docs/kratos/mfa/mfa-via-sms). If your identity schema is configured to allow code login via SMS (i.e., the phone trait has
"credentials": { "code": { "identifier": true, "via": "sms" } }
), this flow will work as described. If not, the request will result in an error. Summary: - The response structure is the same as for email, but the message will reference SMS. - The code will be sent to the provided phone number if your configuration supports it. - The user will see UI nodes to enter the code and options to submit or resend the code [MFA via SMS and Email](https://www.ory.sh/docs/kratos/mfa/mfa-via-sms).
m
@chilly-king-10285 What’s
state
property when code is sent via sms?
b
A message from kapa.ai
When a code is sent via SMS during a login flow, the
state
property in the response is set to
sent_email
according to the available knowledge sources. This is the same state used when a code is sent via email. The documentation and example responses indicate that the
state
property can have values such as: - `choose_method`: ask the user to choose a method to sign in with - `sent_email`: the email has been sent to the user - `passed_challenge`: the request was successful and the login challenge was passed There is no mention of a separate
sent_sms
state; the system uses
sent_email
for both email and SMS code delivery [Kratos API Reference - getLoginFlow](https://www.ory.sh/docs/kratos/reference/api). Summary: The
state
property is set to
sent_email
when a code is sent via SMS during the login flow, based on the current documentation and API references.
m
nvm
@chilly-king-10285 I have this courier setup
Copy code
channels:
    - id: sms
      type: http
      request_config:
        url: <http://echoserver:80/sms>
        method: POST
        headers:
          Content-Type: 'application/json'
          Accept: 'application/json'
        body: file:///etc/config/kratos/sms-body.jsonnet
        auth:
          type: api_key
          config:
            name: 'api-key'
            value: 'BREVO_SMS_API_KEY'
            in: header
Which variables do I have access to isnide
sms-body.jsonnet
?
b
A message from kapa.ai
Inside your
sms-body.jsonnet
file, you have access to the following variables via the
ctx
object: - `recipient`: The recipient's phone number. - `body`: The message body. - `template_type`: The template type, e.g.,
verification_code
. - `template_data`: The template data, e.g.,
{ "VerificationCode": "1234", Identity: { ... } }
. - `message_type`: The message type, e.g.,
sms
. A typical Jsonnet template for SMS might look like:
Copy code
jsonnet function(ctx) {   To: ctx.recipient,   Body: ctx.body, }
You can use these fields to construct the payload sent to your SMS provider. For more details, see the [Ory Kratos SMS documentation](https://www.ory.sh/docs/kratos/emails-sms/sending-sms). If you need to access specific template variables (like the code or identity), you can reference them through
ctx.template_data
as appropriate for your template type [Send SMS to your users](https://www.ory.sh/docs/kratos/emails-sms/sending-sms).
m
@chilly-king-10285 how is
template_data
populated?
b
A message from kapa.ai
The
template_data
object is populated by Ory Kratos based on the template type and the context of the message being sent. For each type of message (such as verification code, recovery code, login code, etc.), Ory Kratos includes specific variables in
template_data
that are relevant to that template. For example, for an SMS or email containing a verification code,
template_data
will include fields like
VerificationCode
,
VerificationURL
,
Identity
, and others, depending on the template type. The exact variables available for each template type are documented in the [available variables section](https://www.ory.sh/docs/kratos/emails-sms/custom-email-templates#available-variables): - For
verification_code.valid
,
template_data
includes: -
To
-
VerificationCode
-
VerificationURL
-
Identity
-
ExpiresInMinutes
- For
login_code.valid
,
template_data
includes: -
To
-
LoginCode
-
Identity
-
ExpiresInMinutes
- For SMS, the message body is typically set to the code or message you want to send, and you can access these fields via
ctx.template_data
in your Jsonnet template [Send SMS to your users](https://www.ory.sh/docs/kratos/emails-sms/sending-sms). In summary, Ory Kratos automatically populates
template_data
with the variables relevant to the message type being sent
, and you can reference these variables in your Jsonnet template for custom SMS or email delivery.
m
@chilly-king-10285 Can I add my own variable somehow? I want to add Sender ID that should be different per enironemnt (development, staging, production)
b
A message from kapa.ai
I'm sorry, but the knowledge sources do not contain enough information to confirm whether you can add your own custom variable (such as a Sender ID) to the
template_data
object in Ory Kratos. The documentation describes how Ory Kratos automatically populates
template_data
with variables relevant to the message type, but it does not mention a supported way to inject additional custom variables per environment or per request [Send SMS to your users](https://www.ory.sh/docs/kratos/emails-sms/sending-sms) [Available variables for templates](https://www.ory.sh/docs/kratos/emails-sms/custom-email-templates#available-variables). If you need environment-specific values like a Sender ID, you may need to handle this logic within your Jsonnet template by referencing environment variables or by using different Jsonnet files/configurations per environment, but this approach is not documented in the provided sources.
m
@chilly-king-10285 is there a way to call hook before sms is sent
b
A message from kapa.ai
I'm sorry, but the knowledge sources do not contain information about a way to call a hook specifically before an SMS is sent in Ory Kratos. The available documentation describes hooks and actions that can be triggered before or after flows such as login, registration, recovery, verification, and settings, but it does not mention a hook point that occurs immediately before message (SMS or email) delivery [Actions in Ory Identities](https://www.ory.sh/docs/kratos/hooks/configure-hooks#action-triggers). Hooks can be configured to run before or after self-service flows, but not at the granularity of message delivery steps within those flows. Therefore, there is no documented way to trigger a hook right before an SMS is sent.
m
@chilly-king-10285 how to access trait value inside
login_code/valid/email.subject.gotmpl
template?
b
A message from kapa.ai
To access a trait value inside the
login_code/valid/email.subject.gotmpl
template, you can use the
.Identity.traits
object. For example, if your identity schema includes a trait called
first_name
, you can reference it in your template like this:
Copy code
Login code for {{ .Identity.traits.first_name }}
This approach is documented for customizing template content based on the identity of the recipient. The
Identity
object is available in all templates and contains all the attributes defined in your identity schema, including
traits
 [Customizing template content for specific users](https://www.ory.sh/docs/kratos/emails-sms/custom-email-templates#customizing-template-content-for-specific-users).
m
@chilly-king-10285 using paswordless code, how to configure for how long the code is valid?
b
A message from kapa.ai
To configure how long a passwordless code is valid in Ory, you need to set the
lifespan
property for the
code
method in your Ory Identities (Kratos) configuration. This can be done via the Ory Console or by editing your configuration file. Example configuration in `identity-config.yaml`:
Copy code
yaml selfservice:   methods:     code:       passwordless_enabled: true       enabled: true       config:         lifespan: 15m # The code will be valid for 15 minutes
You can also set this using the Ory Console by navigating to AuthenticationPasswordless login and adjusting the code lifespan setting [Email and SMS one-time-code authentication](https://www.ory.sh/docs/kratos/passwordless/one-time-code). The
lifespan
value defines how long the code is valid (e.g.,
15m
for 15 minutes,
1h
for one hour). If not set, it defaults to 1 hour [Account recovery and password reset configuration](https://www.ory.sh/docs/kratos/self-service/flows/account-recovery-password-reset#configuration).
m
@chilly-king-10285 what does
lifespan
in this block mean?
Copy code
flows:
    login:
      ui_url: <http://localhost:3000/login>
      lifespan: 30m
b
A message from kapa.ai
The
lifespan
property in the
flows.login
block specifies how long a login flow is valid after it is initiated. For example, with
lifespan: 30m
, the user has 30 minutes to complete the login process before the flow expires and they need to start a new one. This setting controls the expiration time for the login flow, not the session or the code itself [Session-management > Session lifespan](https://www.ory.sh/docs/kratos/session-management/session-lifespan) [Github Issue: Account recovery and password reset configuration](https://github.com/ory/network/issues/409).
A message from kapa.ai
The
lifespan
property in the
flows.login
block defines how long a login flow is valid after it is initiated. In your example:
Copy code
yaml flows:   login:     ui_url: <http://localhost:3000/login>     lifespan: 30m
the login flow will expire 30 minutes after it starts. If the user does not complete the login within this time, the flow becomes invalid and they must start a new login flow [Session-management > Session lifespan](https://www.ory.sh/docs/kratos/session-management/session-lifespan) [Account recovery and password reset configuration](https://github.com/ory/network/issues/409).
m
@chilly-king-10285 what should be relationship between lifespan in login flow and in method code?
b
A message from kapa.ai
The
lifespan
in the login flow (
flows.login.lifespan
) and the
lifespan
in the
code
method (
methods.code.config.lifespan
) control different aspects of the authentication process: -
flows.login.lifespan
: This sets how long the entire login flow is valid after it is initiated. If the user does not complete the login within this time, the flow expires and must be restarted. -
methods.code.config.lifespan
: This sets how long the one-time code (OTP) sent to the user (via email or SMS) is valid. If the user does not use the code within this time, the code expires and a new one must be requested. Relationship: The knowledge sources do not specify a strict required relationship between these two values, but for a smooth user experience, the code lifespan should generally be less than or equal to the login flow lifespan. This ensures that the code does not outlive the flow itself, preventing situations where a user receives a valid code but cannot use it because the flow has already expired. For example, you might set:
Copy code
yaml flows:   login:     lifespan: 30m  methods:   code:     config:       lifespan: 15m
This way, the user has 30 minutes to complete the login flow, but each code is only valid for 15 minutes within that window. Summary: - The code lifespan should not exceed the login flow lifespan. - There is no enforced relationship, but aligning them as described above avoids user confusion and errors. This is supported by the configuration examples and explanations in the documentation [Account recovery and password reset configuration](https://www.ory.sh/docs/kratos/self-service/flows/account-recovery-password-reset#configuration) [Address verification](https://www.ory.sh/docs/kratos/self-service/flows/verify-email-account-activation).
m
@chilly-king-10285 I have both of these files in `login_code/valid`: •
email.body.gotmpl
email.body.plaintext.gotmpl
I am testing with mailslurper and I only see plaintext emails being received
b
A message from kapa.ai
If you have both
email.body.gotmpl
(HTML) and
email.body.plaintext.gotmpl
(plain text) templates in your
login_code/valid
directory, Ory Kratos will attempt to send both versions as alternatives in the email. However, whether you see the HTML or plain text version in your email client (in this case, MailSlurper) depends on how the client renders multipart emails. According to the documentation, both HTML and plain text templates are required, and the mail courier uses them as alternatives for fallback. If the email client (MailSlurper) does not render or display the HTML part, you will only see the plain text version [Email templates in self-hosted Ory Kratos](https://www.ory.sh/docs/kratos/self-hosted/mail-courier-selfhosted#template-override-path) [Mandatory template formats](https://www.ory.sh/docs/kratos/emails-sms/custom-email-templates#mandatory-template-formats). Summary: - Ory Kratos sends both HTML and plain text versions if both templates are present. - If you only see the plain text email in MailSlurper, it is likely due to how MailSlurper displays emails, not an issue with your Ory Kratos configuration. - To verify the HTML template, try viewing the raw email source in MailSlurper or test with a different email client that supports HTML rendering.
m
@chilly-king-10285 how to configure mailpit instead of mailslurper for sending email and sms?
b
A message from kapa.ai
I'm sorry, but the knowledge sources do not contain information or examples specifically about configuring Mailpit as an email or SMS provider for Ory Kratos. The documentation provides examples for MailSlurper and general SMTP/HTTP configuration, but does not mention Mailpit or its setup. If you need to use Mailpit, you would generally follow the same SMTP configuration steps as for any other SMTP server, but the knowledge sources do not provide explicit instructions or confirmation for Mailpit.
m
@chilly-king-10285 does email have to be unique if using passwordless login via email?
b
A message from kapa.ai
Yes, the email must be unique if you are using passwordless login via email. When you configure the
code
credential (used for passwordless login) with email as the identifier, Ory Kratos enforces that each email address can only be associated with one identity for the
code
credential type. If you try to register or update another identity with the same email for the
code
credential, the system will reject the request with a conflict error [Credentials - Ory Kratos Concepts](https://www.ory.sh/docs/kratos/concepts/credentials). > Each credential - regardless of its type - has one or more identifiers attached to it. Each identifier is universally unique. ... While credentials must be unique per type, there can be duplicates amongst multiple types. So, for passwordless login via email, the email address must be unique among all identities using that login method.
m
@chilly-king-10285 when using
code
passwordless login, can I have a user with multiple emails as identifiers?
b
A message from kapa.ai
Yes, you can configure a user to have multiple emails as identifiers for passwordless login using the
code
method. This is done by defining the
emails
trait as an array in your identity schema, and marking each email as an identifier for the
code
credential. Here is an example from the documentation:
Copy code
json {   "$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",             "<http://ory.sh/kratos|ory.sh/kratos>": {               "credentials": {                 "code": {                   "identifier": true,                   "via": "email"                 }               }             }           }         }       }     }   } }
With this schema, each email in the
emails
array can be used as an identifier for passwordless login via the
code
method [Customize identity schemas: Multiple identifiers](https://www.ory.sh/docs/kratos/manage-identities/customize-identity-schema#multiple-identifiers) [Customize identity schemas: Examples](https://www.ory.sh/docs/kratos/manage-identities/customize-identity-schema#examples). Note: Each email address must still be unique across all identities for the
code
credential type.
m
@chilly-king-10285 what about when using
code
method with
mfa_enabled: true
? User logs in with username and password, then with code
b
A message from kapa.ai
When using the
code
method with
mfa_enabled: true
, the typical flow is that the user first logs in with their primary credential (such as username and password), and then completes a second authentication step by entering a code (OTP) sent via email or SMS. This is a standard multi-factor authentication (MFA) setup in Ory Kratos. If your identity schema allows multiple emails as identifiers for the
code
credential (for example, using an array of emails), the user can choose which email to receive the OTP code on during the MFA step. However, each email used as an identifier for the
code
credential must still be unique across all identities [Customize identity schemas: Multiple identifiers](https://www.ory.sh/docs/kratos/manage-identities/customize-identity-schema#multiple-identifiers). So, in this scenario: - The user logs in with their username and password (first factor). - For the second factor, Ory Kratos will prompt for a code sent to one of the user's registered email addresses (or phone numbers, if configured). - The user can select from their available identifiers (emails/phones) to receive the code, provided your schema supports multiple identifiers. Summary: Yes, you can use multiple emails as identifiers for the
code
method with
mfa_enabled: true
. The user logs in with username and password, then completes MFA with a code sent to one of their unique email addresses configured as identifiers for the
code
credential [Customize identity schemas: Multiple identifiers](https://www.ory.sh/docs/kratos/manage-identities/customize-identity-schema#multiple-identifiers).
m
@chilly-king-10285 give me an example of logic code valid gotmpl with if-else logic for identity.traits.language == ‘DE’
b
A message from kapa.ai
Certainly! Here is an example of a
login_code/valid/email.body.gotmpl
template that uses if-else logic to render different content based on the user's language trait (
identity.traits.language
). This approach is documented in the Ory Kratos documentation for customizing template content and internationalization (i18n):
Copy code
gotmpl {{- if eq .Identity.traits.language "DE" -}} Hallo {{ .Identity.traits.first_name }},  Ihr Login-Code lautet: {{ .LoginCode }} {{- else -}} Hello {{ .Identity.traits.first_name }},  Your login code is: {{ .LoginCode }} {{- end -}}
This template checks if the user's language trait is
"DE"
(German) and renders a German message; otherwise, it defaults to English. You can adapt the trait name and message as needed for your schema. This pattern is described in the documentation for translated templates (i18n) and customizing template content for specific users [Customizing template content for specific users](https://www.ory.sh/docs/kratos/emails-sms/custom-email-templates#customizing-template-content-for-specific-users).
m
@chilly-king-10285 what does dashes inside double brackets mean?
b
A message from kapa.ai
In Go templates (used by Ory for email templates), the dashes inside double brackets—like
{{-
or `-}}`—are used to control whitespace trimming. Specifically: -
{{-
(dash on the left): Trims all whitespace to the left of the tag. -
-}}
(dash on the right): Trims all whitespace to the right of the tag. This helps you control the formatting of the rendered output, making it easier to avoid unwanted spaces or newlines in your emails. This behavior is part of the Go template engine, which Ory uses for rendering email templates [Creating templates](https://www.ory.sh/docs/kratos/emails-sms/custom-email-templates#creating-templates).
m
@chilly-king-10285 can I access Identity inside jsonnet file?
b
A message from kapa.ai
You can access the identity object inside a Jsonnet file when using Ory webhooks or actions that bind the
identity
into the context. For example, when defining a webhook or action that runs after a self-service flow (such as registration or login), the
identity
object is available as
ctx.identity
in your Jsonnet template. This allows you to access traits and other identity properties:
Copy code
jsonnet function(ctx) {   user_id: ctx.identity.id,   email: ctx.identity.traits.email,   // ...other fields... }
This is documented in the Ory webhook and actions guides, which show that the
identity
object is available in the
ctx
context for after-hooks and actions [Define HTTP request](https://www.ory.sh/docs/guides/integrate-with-ory-cloud-through-webhooks#define-http-request) [Jsonnet templating](https://www.ory.sh/docs/guides/integrate-with-ory-cloud-through-webhooks#jsonnet-templating). Note: For email/SMS courier templates (not webhooks/actions), the context is different and you typically access identity data via
ctx.template_data.Identity
in Jsonnet, depending on the template type [Send SMS to your users](https://www.ory.sh/docs/kratos/emails-sms/sending-sms). Summary: - For webhooks/actions: access identity as
ctx.identity
. - For courier templates: access identity as
ctx.template_data.Identity
(if available for that template type).
m
@chilly-king-10285 Can I do if-else logic in jsonnet?
b
A message from kapa.ai
Yes, you can do if-else logic in Jsonnet. Jsonnet supports conditional expressions using the
if ... then ... else ...
syntax. For example:
Copy code
jsonnet local claims = std.extVar('claims');  {   identity: {     traits: {       [if "website" in claims then "website" else null]: claims.website,     },   }, }
This example shows how to conditionally include a field based on whether
"website"
exists in the
claims
object [Write a Jsonnet data mapper](https://www.ory.sh/docs/kratos/social-signin/data-mapping#write-a-jsonnet-data-mapper). You can use similar if-else logic for more complex conditions in your Jsonnet code.
m
@chilly-king-10285 give me example of setting
templateId
based on
identity.traits.language
property (1 for EN, 2 for DE, 3 for others)
b
A message from kapa.ai
Certainly! Here’s how you can set a
templateId
in a Jsonnet file based on the value of
identity.traits.language
, using if-else logic:
Copy code
jsonnet function(ctx) {   templateId:     if ctx.identity.traits.language == "EN" then 1     else if ctx.identity.traits.language == "DE" then 2     else 3 }
This uses standard Jsonnet conditional expressions, as shown in the documentation for data mapping and Jsonnet usage [Write a Jsonnet data mapper](https://www.ory.sh/docs/kratos/social-signin/data-mapping#write-a-jsonnet-data-mapper). -
ctx.identity.traits.language
accesses the language property of the identity. - The
templateId
is set to
1
for English,
2
for German, and
3
for any other language. You can use this pattern in webhooks, actions, or any context where the
identity
object is available in Jsonnet [Jsonnet templating](https://www.ory.sh/docs/guides/integrate-with-ory-cloud-through-webhooks#jsonnet-templating).
m
@chilly-king-10285 getting this error
Copy code
jsonnetsecure: ERROR: RUNTIME ERROR: Field does not exist: identity\n\tfile:///etc/config/kratos/login_code.email.jsonnet
b
A message from kapa.ai
The error message:
Copy code
jsonnetsecure: ERROR: RUNTIME ERROR: Field does not exist: identity
indicates that the
identity
field is not available in the context when your Jsonnet template is being executed for the email courier. According to the knowledge sources, for email and SMS delivery via courier, the variables available in the Jsonnet context are accessed through the
ctx
object, and identity information (if available) is typically found under
ctx.template_data.Identity
(not
ctx.identity
). For example, the documentation for SMS delivery shows: - `ctx.template_data`: The template data, e.g.,
{ "VerificationCode": "1234", Identity: { ... } }
- To access the identity, you would use
ctx.template_data.Identity
 [Send SMS to your users](https://www.ory.sh/docs/kratos/emails-sms/sending-sms). How to fix your Jsonnet: Instead of:
Copy code
jsonnet ctx.identity.traits.language
use:
Copy code
jsonnet ctx.template_data.Identity.traits.language
Example:
Copy code
jsonnet function(ctx) {   templateId:     if ctx.template_data.Identity.traits.language == "EN" then 1     else if ctx.template_data.Identity.traits.language == "DE" then 2     else 3 }
Summary: In courier Jsonnet templates, use
ctx.template_data.Identity
to access identity fields, not
ctx.identity
. The error occurs because
identity
is not present at the top level of
ctx
in this context [Send SMS to your users](https://www.ory.sh/docs/kratos/emails-sms/sending-sms).
m
@chilly-king-10285 now getting
Copy code
jsonnetsecure: ERROR: RUNTIME ERROR: Field does not exist: Identity\n\tfile:///etc/config/kratos/login_code.email.jsonnet
b
A message from kapa.ai
The error
Copy code
jsonnetsecure: ERROR: RUNTIME ERROR: Field does not exist: Identity
means that
Identity
is not present in
ctx.template_data
in your current context. Based on the knowledge sources, the variables available in
ctx.template_data
depend on the template type. For the
login_code.valid
template, the documentation states that
Identity
should be available in
template_data
 [Available variables for templates](https://www.ory.sh/docs/kratos/emails-sms/custom-email-templates#available-variables). However, your error suggests that in your specific setup or Ory version, it is not present. Possible reasons and what you can do: 1. Template Type Limitation or Version Difference: The knowledge sources indicate
Identity
should be present, but if it is not, it may be due to a version difference or a bug. The documentation does not provide a workaround for when
Identity
is missing. 2. Check What Is Available: You can debug what fields are present by temporarily using a Jsonnet template like:
Copy code
jsonnet    function(ctx) ctx
This will output the entire context and help you see what fields are actually available. 3. Fallback: If
Identity
is not available in your context, you cannot access it in the Jsonnet template for that message type, and the knowledge sources do not provide a supported workaround. Summary: Although the documentation says
Identity
should be available in
ctx.template_data
for
login_code.valid
, your error shows it is not. The knowledge sources do not contain enough information to resolve this discrepancy or provide an alternative way to access identity traits in this context.
m
@chilly-king-10285 but this availalbe variables for templates are to be used in gotmpl, not in jsonnet?
b
A message from kapa.ai
You are correct: the list of [available variables for templates](https://www.ory.sh/docs/kratos/emails-sms/custom-email-templates#available-variables) in the documentation specifically applies to Go template (
gotmpl
) files used for email and SMS content, not to Jsonnet templates used for HTTP/SMS/Email courier payloads. For Jsonnet templates (used in courier HTTP/SMS/email integrations), the available variables are provided via the
ctx
object, and the structure of
ctx
is different from the Go template context. In Jsonnet, you typically have access to fields like
ctx.recipient
,
ctx.body
,
ctx.template_type
, and
ctx.template_data
. The contents of
ctx.template_data
depend on the flow and may not always include the full
Identity
object, even if it is available in Go templates [Send SMS to your users](https://www.ory.sh/docs/kratos/emails-sms/sending-sms). Summary: - The variables listed in the "available variables for templates" documentation are for Go templates (
gotmpl
), not Jsonnet. - Jsonnet templates use the
ctx
object, and the available fields may differ. - If you need to know what is available in Jsonnet, inspect the
ctx
object as described in the courier integration documentation.