Hey Al.. I'm having trouble getting kratos to send...
# ory-selfhosting
b
Hey Al.. I'm having trouble getting kratos to send a verification email after registration success. What am i missing in this config
Copy code
dsn: <cockroach://root@cockroach:26257/kratos_db?sslmode=disable>

serve:
  public:
    base_url: <http://127.0.0.1:4433/>
    cors:
      enabled: true
      allowed_origins:
        - <http://localhost:5173>
        - <http://localhost:5174>
        - <http://localhost:3000>
        - <http://localhost:4455>
      allowed_methods:
        - POST
        - GET
        - PUT
        - PATCH
        - DELETE
        - OPTIONS
      allowed_headers:
        - Authorization
        - Content-Type
        - Cookie
      exposed_headers:
        - Content-Type
        - Set-Cookie
      allow_credentials: true
  admin:
    base_url: <http://127.0.0.1:4434/>

selfservice:
  default_browser_return_url: <http://localhost:5173/enrollment>
  flows:
    login:
      ui_url: <http://localhost:5173/login>
    registration:
      ui_url: <http://localhost:5173/registration>
      enabled: true
      after:
        default_browser_return_url: <http://localhost:5173/enrollment>
        password:
          hooks:
            - hook: show_verification_ui
            - hook: show_recovery_ui
    settings:
      ui_url: <http://127.0.0.1:4455/settings>
    recovery:
      ui_url: <http://127.0.0.1:4455/recovery>
    verification:
      ui_url: <http://127.0.0.1:4455/verification>
  methods:
    password:
      enabled: true

identity:
  default_schema_id: default
  schemas:
    - id: default
      url: file:///etc/config/kratos/identity-schemas/tpp.schema.json


courier:
  templates:
    verification:
      valid:
        email:
          body:
            html: file:///etc/config/kratos/email-templates/verification/body.html.gotmpl
            plaintext: file:///etc/config/kratos/email-templates/verification/body.plaintext.gotmpl
          subject: file:///etc/config/kratos/email-templates/verification/subject.gotmpl
  delivery_strategy: smtp
  smtp:
    connection_uri: <smtps://sandbox-3>:***@smtp.devmail.email:2525/
    from_address: <mailto:noreply@fapi-gateway.com|noreply@fapi-gateway.com>
    from_name: FAPI Gateway
@chilly-king-10285 can you help with this?
b
A message from kapa.ai
I'm happy to help with questions about Ory! However, your message "can you help with this?" does not specify what you need assistance with. Please provide more details or clarify your question regarding Ory, and I'll do my best to assist you based on the available knowledge sources.
b
@chilly-king-10285 'm having trouble getting kratos to send a verification email after registration success. What am i missing in this config
Copy code
dsn: <cockroach://root@cockroach:26257/kratos_db?sslmode=disable>

serve:
  public:
    base_url: <http://127.0.0.1:4433/>
    cors:
      enabled: true
      allowed_origins:
        - <http://localhost:5173>
        - <http://localhost:5174>
        - <http://localhost:3000>
        - <http://localhost:4455>
      allowed_methods:
        - POST
        - GET
        - PUT
        - PATCH
        - DELETE
        - OPTIONS
      allowed_headers:
        - Authorization
        - Content-Type
        - Cookie
      exposed_headers:
        - Content-Type
        - Set-Cookie
      allow_credentials: true
  admin:
    base_url: <http://127.0.0.1:4434/>

selfservice:
  default_browser_return_url: <http://localhost:5173/enrollment>
  flows:
    login:
      ui_url: <http://localhost:5173/login>
    registration:
      ui_url: <http://localhost:5173/registration>
      enabled: true
      after:
        default_browser_return_url: <http://localhost:5173/enrollment>
        password:
          hooks:
            - hook: show_verification_ui
            - hook: show_recovery_ui
    settings:
      ui_url: <http://127.0.0.1:4455/settings>
    recovery:
      ui_url: <http://127.0.0.1:4455/recovery>
    verification:
      ui_url: <http://127.0.0.1:4455/verification>
  methods:
    password:
      enabled: true

identity:
  default_schema_id: default
  schemas:
    - id: default
      url: file:///etc/config/kratos/identity-schemas/tpp.schema.json


courier:
  templates:
    verification:
      valid:
        email:
          body:
            html: file:///etc/config/kratos/email-templates/verification/body.html.gotmpl
            plaintext: file:///etc/config/kratos/email-templates/verification/body.plaintext.gotmpl
          subject: file:///etc/config/kratos/email-templates/verification/subject.gotmpl
  delivery_strategy: smtp
  smtp:
    connection_uri: <smtps://sandbox-3>:***@smtp.devmail.email:2525/
    from_address: <mailto:noreply@fapi-gateway.com|noreply@fapi-gateway.com>
    from_name: FAPI Gateway
b
A message from kapa.ai
Based on your configuration and the available knowledge sources, here are the key requirements for Ory Kratos to send a verification email after successful registration: ### 1. Verification Flow Must Be Enabled You need to ensure that the verification flow is enabled and properly configured in your
selfservice.flows.verification
section. In your config, you have:
Copy code
yaml selfservice:   flows:     verification:       ui_url: <http://127.0.0.1:4455/verification>
However, you are missing the
enabled: true
and the
use: code
(or
link
) fields. According to the documentation, it should look like:
Copy code
yaml selfservice:   flows:     verification:       enabled: true       use: code # or 'link'       ui_url: <http://127.0.0.1:4455/verification>
[Address verification](https://www.ory.sh/docs/kratos/self-service/flows/verify-email-account-activation) ### 2. Identity Schema Must Mark Email as Verifiable Your identity schema (referenced as
tpp.schema.json
) must mark the email trait as verifiable. For example:
Copy code
json "email": {   "type": "string",   "format": "email",   "<http://ory.sh/kratos|ory.sh/kratos>": {     "credentials": {       "password": {         "identifier": true       }     },     "verification": {       "via": "email"     }   } }
[Address verification](https://www.ory.sh/docs/kratos/self-service/flows/verify-email-account-activation) ### 3. Registration Flow and Hooks You have the
show_verification_ui
hook enabled after password registration, which is correct if you want to show the verification screen after registration. This is optional for sending the email, but required if you want to force users to verify before getting a session. By default, Ory will send the verification email if verification is enabled and the schema is correct, even without this hook. [Verification on sign up](https://www.ory.sh/docs/actions/require-verified-address#verification-on-sign-up) ### 4. Courier Configuration Your courier configuration looks correct, assuming your SMTP credentials and template paths are valid. ### 5. Common Pitfalls - If you do not see emails being sent, check the Kratos logs for errors related to the courier or SMTP delivery. - Make sure your SMTP server is reachable and credentials are correct. - Ensure your identity schema is loaded correctly and the
verification
property is present for the email trait. --- Summary of what you are missing: You need to add
enabled: true
and
use: code
(or
link
) to your
selfservice.flows.verification
section. Also, double-check your identity schema to ensure the email trait is marked as verifiable. If you make these changes and still do not receive verification emails, check the logs for courier or SMTP errors, and verify that your SMTP configuration is correct. For more details, see the [Ory Kratos Address Verification documentation](https://www.ory.sh/docs/kratos/self-service/flows/verify-email-account-activation).
b
@chilly-king-10285 give me the config for courier sending email using http
b
A message from kapa.ai
Certainly! Here is an example configuration for Ory Kratos (or Ory Network) to send emails using an HTTP server (instead of SMTP) via the
courier
section. This config can be used in your YAML configuration file:
Copy code
yaml courier:   delivery_strategy: http   http:     request_config:       url: <https://mail-sender.example.com>       method: POST       body: base64://... # Base64-encoded Jsonnet template for the payload (see below)       headers:         Content-Type: application/json       auth:         type: basic_auth # or api_key         config:           user: my-username           password: my-password           # For api_key, use:           # name: my-api-name           # value: my-api-key-value           # in: header # or cookie
Notes: - The
body
field should contain a Base64-encoded Jsonnet template that defines the payload sent to your HTTP email provider. If omitted, a default template is used. - The
auth
section is optional and depends on your provider's requirements. Default Jsonnet template for the payload:
Copy code
jsonnet function(ctx) {   recipient: ctx.recipient,   template_type: ctx.template_type,   to: if "template_data" in ctx && "to" in ctx.template_data then <http://ctx.template_data.to|ctx.template_data.to> else null,   recovery_code: if "template_data" in ctx && "recovery_code" in ctx.template_data then ctx.template_data.recovery_code else null,   recovery_url: if "template_data" in ctx && "recovery_url" in ctx.template_data then ctx.template_data.recovery_url else null,   verification_url: if "template_data" in ctx && "verification_url" in ctx.template_data then ctx.template_data.verification_url else null,   verification_code: if "template_data" in ctx && "verification_code" in ctx.template_data then ctx.template_data.verification_code else null,   login_code: if "template_data" in ctx && "login_code" in ctx.template_data then ctx.template_data.login_code else null,   registration_code: if "template_data" in ctx && "registration_code" in ctx.template_data then ctx.template_data.registration_code else null,   subject: if "template_data" in ctx && "subject" in ctx.template_data then ctx.template_data.subject else null,   body: if "template_data" in ctx && "body" in ctx.template_data then ctx.template_data.body else null }
You can use this template as-is or customize it for your provider, then Base64-encode it and reference it in the
body
field. For more details and examples, see the official documentation: [Send emails using an HTTP server](https://www.ory.sh/docs/kratos/emails-sms/sending-emails-smtp#send-emails-using-an-http-server) and [HTTP based email delivery (self-hosted)](https://www.ory.sh/docs/kratos/self-hosted/email-http#configuration).
b
@chilly-king-10285 i am using an api_key
b
A message from kapa.ai
Certainly! Here is how you configure Ory Kratos to send emails using an HTTP server with API key authentication:
Copy code
yaml courier:   delivery_strategy: http   http:     request_config:       url: <https://api.your-email-provider.com/send>       method: POST       body: file:///etc/config/kratos/mail.api.request.jsonnet # or use <base64://ENCODED_JSONNET>       headers:         "Content-Type": "application/json"       auth:         type: api_key         config:           name: Authorization         # The header or cookie name for the API key           value: Bearer <API_KEY>     # The value of your API key (prefix with 'Bearer ' if required by your provider)           in: header                  # Use 'header' or 'cookie' as required by your provider
Key points: - Replace
url
with your provider’s endpoint. - The
body
can be a file path or a base64-encoded Jsonnet template. If omitted, the default template is used. - Set the
name
,
value
, and
in
fields in the
auth.config
section according to your provider’s requirements. For example, for Sendgrid, you would use:
Copy code
yaml auth:   type: api_key   config:     name: Authorization     value: Bearer <API_KEY>     in: header
This configuration is directly supported and documented in the Ory Kratos docs for HTTP-based email delivery with API key authentication [HTTP based email delivery](https://www.ory.sh/docs/kratos/self-hosted/email-http#configuration) and [Send emails using an HTTP server](https://www.ory.sh/docs/kratos/emails-sms/sending-emails-smtp#send-emails-using-an-http-server). If you need a sample Jsonnet template for the body, let me know!
b
@chilly-king-10285 how do i use jsonnet for the body parameter? Giuve me an example
b
A message from kapa.ai
To use Jsonnet for the
body
parameter in your HTTP email delivery configuration, you provide a Jsonnet template that defines the payload sent to your email provider. This template can be referenced as a file (e.g., `file://path/to/template.jsonnet`) or as a base64-encoded string (e.g.,
<base64://ENCODED_JSONNET>
). Ory Kratos will pass a
ctx
object to your Jsonnet function, containing relevant data for the email. Example Jsonnet template (
mail.api.request.jsonnet
):
Copy code
jsonnet function(ctx) {   recipient: ctx.recipient,   template_type: ctx.template_type,   to: if "template_data" in ctx && "to" in ctx.template_data then <http://ctx.template_data.to|ctx.template_data.to> else null,   recovery_code: if "template_data" in ctx && "recovery_code" in ctx.template_data then ctx.template_data.recovery_code else null,   recovery_url: if "template_data" in ctx && "recovery_url" in ctx.template_data then ctx.template_data.recovery_url else null,   verification_url: if "template_data" in ctx && "verification_url" in ctx.template_data then ctx.template_data.verification_url else null,   verification_code: if "template_data" in ctx && "verification_code" in ctx.template_data then ctx.template_data.verification_code else null }
How to reference it in your config:
Copy code
yaml courier:   delivery_strategy: http   http:     request_config:       url: <https://api.your-email-provider.com/send>       method: POST       body: file:///etc/config/kratos/mail.api.request.jsonnet       headers:         "Content-Type": "application/json"       auth:         type: api_key         config:           name: Authorization           value: Bearer <API_KEY>           in: header
Alternatively, you can base64-encode your Jsonnet file and use:
Copy code
yaml body: base64://<BASE64_ENCODED_JSONNET>
What fields are available in
ctx
?
- `recipient`: The email address of the recipient. - `template_type`: The type of template (e.g.,
verification_valid
). - `template_data`: An object with template-specific data (e.g.,
verification_url
,
recovery_code
, etc.). For more details and a list of available fields, see the [official documentation](https://www.ory.sh/docs/kratos/self-hosted/email-http#configuration) and [Jsonnet reference](https://www.ory.sh/docs/kratos/reference/jsonnet).
b
@chilly-king-10285 give me config for totp:
b
A message from kapa.ai
Certainly! To enable and configure TOTP (Time-based One-Time Password) in Ory Kratos, you need to add the following section to your configuration file:
Copy code
yaml selfservice:   methods:     totp:       config:         # The "issuer" is the name shown in the TOTP app (e.g., Google Authenticator)         issuer: <http://ExampleIssuer.com|ExampleIssuer.com>       enabled: true
Key points: - The
issuer
value will be displayed in the authenticator app. - Make sure
enabled: true
is set. This configuration enables TOTP as a second-factor authentication method for your users. After enabling, users can pair their account with a TOTP app (like Google Authenticator) via the Ory Account Experience or your custom UI. For more details, see the official documentation: [Time-based one-time passwords (TOTP)](https://www.ory.sh/docs/kratos/mfa/totp) and [Self-hosted MFA configuration](https://www.ory.sh/docs/kratos/self-hosted/mfa).
b
@chilly-king-10285 how do you totp after login success. Show sample config
b
A message from kapa.ai
To require TOTP (Time-based One-Time Password) after a successful login (i.e., as a second authentication step), you need to configure Ory Kratos to enforce multi-factor authentication (MFA) with TOTP as a second factor. ### 1. Enable TOTP in your config
Copy code
yaml selfservice:   methods:     totp:       config:         issuer: <http://ExampleIssuer.com|ExampleIssuer.com>       enabled: true
This enables TOTP as a second factor and sets the issuer name that appears in authenticator apps [Time-based one-time passwords (TOTP)](https://www.ory.sh/docs/kratos/mfa/totp). ### 2. Enforce MFA after login To require users to complete TOTP after logging in, set the required Authenticator Assurance Level (AAL) for sessions and/or sensitive flows. For example, to require the highest available AAL (which includes TOTP if configured) for accessing account settings:
Copy code
yaml selfservice:   flows:     settings:       required_aal: highest_available session:   whoami:     required_aal: highest_available
With this configuration, after a user logs in with their password, they will be prompted for TOTP if they have it configured. If not, they can proceed with just their password. If you want to require TOTP for all users who have it set up, this is the recommended approach [Configure multi-factor authentication in Ory Kratos](https://www.ory.sh/docs/kratos/self-hosted/mfa). ### 3. How it works in practice - User logs in with their first factor (e.g., password). - If the session or flow requires
aal2
(second factor), and the user has TOTP configured, Ory will prompt for the TOTP code. - Upon successful TOTP entry, the session is upgraded to
aal2
. For more on step-up authentication and enforcing TOTP after login, see [Step-up authentication](https://www.ory.sh/docs/kratos/mfa/step-up-authentication). --- Summary: Enable TOTP in
selfservice.methods
, and set
required_aal: highest_available
for the relevant flows or session. This will prompt users for TOTP after a successful login if they have TOTP configured.
b
i mean google authenticator
@chilly-king-10285 i mean google authenticator
b
A message from kapa.ai
To require users to enter a code from Google Authenticator (or any TOTP app) after a successful login, you need to enable TOTP as a second factor and enforce multi-factor authentication (MFA) in your Ory Kratos configuration. Here’s a sample configuration based on the official documentation:
Copy code
yaml selfservice:   methods:     totp:       config:         # This is the name that will appear in Google Authenticator         issuer: <http://ExampleIssuer.com|ExampleIssuer.com>       enabled: true    flows:     settings:       required_aal: highest_available  session:   whoami:     required_aal: highest_available
How it works: - After a user logs in with their password, if they have TOTP (e.g., Google Authenticator) configured, Ory will prompt them to enter the code from their app. - The
issuer
field is what users will see in Google Authenticator when they pair their account. - The
required_aal: highest_available
setting ensures that users must complete the second factor (TOTP) for sensitive actions or to upgrade their session to AAL2. This setup is directly supported and described in the Ory documentation for TOTP and step-up authentication [Time-based one-time passwords (TOTP)](https://www.ory.sh/docs/kratos/mfa/totp) [Step-up authentication](https://www.ory.sh/docs/kratos/mfa/step-up-authentication). If you want TOTP to be required immediately after login for all users who have it configured, this is the recommended approach. If a user does not have TOTP set up, they will not be prompted for it until they do so. If you need to customize which flows require TOTP, adjust the
required_aal
setting under the relevant flow (e.g.,
login
,
settings
, etc.) as shown above.
b
@chilly-king-10285 How do we delete an account
b
A message from kapa.ai
To delete an account (identity) in Ory Kratos, you need to use the Ory Identities API. Specifically, you can use the
deleteIdentityCredentials
method, which requires authentication with an Ory access token. This operation is typically performed via the admin API and is not a self-service flow exposed to end users by default. Here’s what the knowledge sources state: > To perform this operation, you must be authenticated by means of one of the following methods: oryAccessToken [Kratos API Reference](https://raw.githubusercontent.com/ory/kratos/master/spec/api.json) The documentation does not provide a full example of the API call, but the process generally involves: - Authenticating as an admin or with appropriate permissions. - Calling the relevant admin API endpoint to delete the identity. If you need to delete an account via the Ory Console or CLI, you would typically use the admin interface or CLI commands to manage identities, but the knowledge sources do not provide explicit step-by-step instructions for this process. Summary: Account deletion is performed via the admin API using an authenticated request. The knowledge sources do not provide a detailed example, but you must use an Ory access token and the appropriate API endpoint to delete an identity.
b
@chilly-king-10285 i want to show normal login then after that show a google authenticator challenge, how do i configure this with kratos
b
A message from kapa.ai
To show a normal login (e.g., password) and then, after successful login, prompt the user for a Google Authenticator (TOTP) challenge, you need to enable TOTP as a second factor and enforce multi-factor authentication (MFA) in your Ory Kratos configuration. Here’s how you can configure this: 1. Enable TOTP as a second factor:
Copy code
yaml selfservice:   methods:     totp:       config:         issuer: <http://ExampleIssuer.com|ExampleIssuer.com>  # This is the name shown in Google Authenticator       enabled: true
This enables TOTP (Google Authenticator) for your project and sets the issuer name that appears in the authenticator app [Time-based one-time passwords (TOTP)](https://www.ory.sh/docs/kratos/mfa/totp). 2. Enforce MFA after login: Set the required Authenticator Assurance Level (AAL) to require the highest available factor (which includes TOTP if configured):
Copy code
yaml session:   whoami:     required_aal: highest_available
With this configuration, after a user logs in with their password, Ory Kratos will check if the user has TOTP configured. If so, the user will be prompted for their TOTP code (e.g., from Google Authenticator) before the session is fully established at AAL2. If the user does not have TOTP set up, they will not be prompted for it. How it works: - User enters their username and password (normal login). - If TOTP is enabled and configured for the user, Ory will prompt for the TOTP code after the password is verified. - Upon successful TOTP entry, the user gains access with an AAL2 session. This approach is described in the official documentation for step-up authentication and TOTP configuration [Step-up authentication](https://www.ory.sh/docs/kratos/mfa/step-up-authentication) [Time-based one-time passwords (TOTP)](https://www.ory.sh/docs/kratos/mfa/totp). If you want to require TOTP only for specific flows (e.g., only for settings changes), adjust the
required_aal
setting under the relevant flow (such as
selfservice.flows.settings.required_aal
). Note: The knowledge sources do not mention a way to force TOTP for all users regardless of whether they have it configured, nor do they describe a way to force TOTP enrollment immediately after registration. Users must enable TOTP themselves in their account settings after registration [Time-based one-time passwords (TOTP)](https://www.ory.sh/docs/kratos/mfa/totp). --- Summary: Enable TOTP and set
session.whoami.required_aal: highest_available
to prompt for a Google Authenticator challenge after normal login if the user has TOTP configured.
b
@chilly-king-10285 Do i redirect from login to TOTP screen manually within my app or will kratos do the redirection for me
b
A message from kapa.ai
Ory Kratos will handle the redirection for you as part of the self-service login flow when multi-factor authentication (such as TOTP/Google Authenticator) is required. After the user successfully completes the first factor (e.g., password), Kratos will automatically present the TOTP challenge screen if the user has TOTP configured and the flow or session requires a higher AAL (Authenticator Assurance Level). You do not need to manually redirect from the login to the TOTP screen within your app. Kratos manages the flow state and will return the appropriate UI screen (or API response) based on what is required next in the authentication process. Your UI should render the form based on the current flow state provided by Kratos. This is described in the documentation for self-service flows and step-up authentication, where Kratos manages the flow and prompts for the second factor as needed, depending on the configuration and the user's state [Step-up authentication](https://www.ory.sh/docs/kratos/mfa/step-up-authentication) [Login flow](https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-basic-integration#login-flow). If you are building a custom UI, you should use the flow information returned by Kratos to determine which form to display, but the transition between steps (e.g., from password to TOTP) is managed by Kratos itself.
b
@chilly-king-10285 After clicking email verification link, i am getting this error
Copy code
{
  "error": {
    "id": "security_csrf_violation",
    "code": 403,
    "status": "Forbidden",
    "reason": "Please retry the flow and optionally clear your cookies. The request was rejected to protect you from Cross-Site-Request-Forgery (CSRF) which could cause account takeover, leaking personal information, and other serious security issues.",
    "details": {
      "docs": "<https://www.ory.sh/kratos/docs/debug/csrf>",
      "hint": "The anti-CSRF cookie was found but the CSRF token was not included in the HTTP request body (csrf_token) nor in the HTTP Header (X-CSRF-Token).",
      "reject_reason": "The HTTP Cookie Header was set and a CSRF token was sent but they do not match. We recommend deleting all cookies for this domain and retrying the flow."
    },
    "message": "the request was rejected to protect you from Cross-Site-Request-Forgery"
  }
}
after redirecting to my app to check verification state and process with onboarding
c
A message from kapa.ai
The error message you are seeing:
Copy code
"error": {     "id": "security_csrf_violation",     ...     "reason": "Please retry the flow and optionally clear your cookies. The request was rejected to protect you from Cross-Site-Request-Forgery (CSRF)...",     "details": {         ...         "hint": "The anti-CSRF cookie was found but the CSRF token was not included in the HTTP request body (csrf_token) nor in the HTTP Header (X-CSRF-Token).",         "reject_reason": "The HTTP Cookie Header was set and a CSRF token was sent but they do not match. We recommend deleting all cookies for this domain and retrying the flow."     } }
indicates a CSRF protection failure. This typically happens when the CSRF token in the request does not match the anti-CSRF cookie, or one of them is missing. Common causes and solutions based on the knowledge sources: 1. Cookies and CSRF Token Mismatch: This can occur if the verification link is opened in a different browser, incognito window, or if cookies were cleared or not sent with the request. Ory Kratos expects the CSRF cookie and the CSRF token (from the form or header) to match. If they do not, the request is rejected for security reasons [CSRF troubleshooting](https://www.ory.sh/docs/troubleshooting/csrf). 2. Public Suffix Domains: If you are using a domain that is on the [public suffix list](https://publicsuffix.org/), cookies may not be set correctly, leading to CSRF errors. Use a subdomain that is not on the PSL, such as
<http://app.myftp.org|app.myftp.org>
instead of
<http://myftp.org|myftp.org>
 [CSRF troubleshooting](https://www.ory.sh/docs/troubleshooting/csrf). 3. Mixing Domains or Inconsistent URLs: Make sure you are not mixing
localhost
and
127.0.0.1
, or using different subdomains, as cookies are domain-specific. Use the same domain consistently across your app and Ory Kratos [CSRF debug](https://www.ory.sh/docs/kratos/debug/csrf). 4. Flow Handling: When handling verification flows, ensure you are forwarding the
Cookie
header from the client when fetching the flow, especially in server-side applications. Without forwarding the
Cookie
header, you can't fetch the flow due to a security error [CSRF troubleshooting](https://www.ory.sh/docs/troubleshooting/csrf). 5. How to Fix: - Ask the user to retry the flow and clear cookies for the domain if necessary. - Ensure the verification link is opened in the same browser and context where the registration was performed. - Double-check your domain and cookie settings in the Kratos config. - If you are using a custom UI, make sure to include the CSRF token from the flow in your form submissions. For more details, see the [Ory Kratos CSRF troubleshooting guide](https://www.ory.sh/kratos/docs/debug/csrf). --- Summary: This error is caused by a mismatch or absence of the CSRF token and cookie. Ensure the verification link is opened in the same browser session, cookies are not blocked or cleared, and your domain configuration is correct. If the problem persists, clear cookies and retry the flow [CSRF troubleshooting](https://www.ory.sh/docs/troubleshooting/csrf).
b
@chilly-king-10285 how do we set Access-Control-Allow-Origin in the cors for kratos
c
A message from kapa.ai
To set the
Access-Control-Allow-Origin
header for Ory Kratos, you need to configure the CORS settings in your Kratos configuration file under the
serve.public.cors.allowed_origins
section. This determines which origins are allowed to make cross-origin requests to your Kratos public API. Here is an example configuration:
Copy code
yaml serve:   public:     cors:       enabled: true       allowed_origins:         - <https://example.org>         - https://*.<http://example.org|example.org>       allowed_methods:         - POST         - GET         - PUT         - PATCH         - DELETE       allowed_headers:         - Authorization         - Cookie         - Content-Type       exposed_headers:         - Content-Type         - Set-Cookie
In this example, the
allowed_origins
list sets the values for the
Access-Control-Allow-Origin
header. You can specify exact origins or use wildcards for subdomains (e.g.,
https://*.<http://example.org|example.org>
). For more details, see the official documentation: [Cross-origin resource sharing (CORS) settings](https://www.ory.com/docs/kratos/guides/setting-up-cors) and [Configure cross-origin resource sharing (CORS)](https://www.ory.com/docs/hydra/guides/cors).
b
@chilly-king-10285 how do we do logout flows
c
A message from kapa.ai
Ory supports several logout flows depending on your application type and use case. Here’s how you can implement logout flows with Ory Kratos and Ory OAuth2 & OpenID Connect, based on the knowledge sources: --- ### 1. Browser-Based Logout Flow (Ory Kratos) For browser applications, the logout flow is a two-step process: 1. Create a Logout URL: Call the
/self-service/logout/browser
endpoint to generate a logout URL associated with the current session cookie. 2. Complete the Logout: Redirect the user to the generated logout URL (which points to
/self-service/logout?token=...
). This will invalidate the session and remove the session cookie. You can also specify a
return_to
parameter to redirect the user after logout. Example (Express.js):
Copy code
js // Create logout route   app.get("/logout", async (req, res) => {     try {       // Create a logout flow       const { logout_url } = await ory.createBrowserLogoutFlow({         cookie: req.header("cookie"),       })       // Redirect to logout URL       res.redirect(logout_url)     } catch (err) {       res.redirect("/")     }   })
After successful logout, the user is redirected to the specified return URL, the session is invalidated, and the session cookie is removed [Sign out](https://www.ory.com/docs/identities/get-started/sign-out) [Logout flow](https://www.ory.com/docs/kratos/bring-your-own-ui/custom-ui-basic-integration#logout-flow). --- ### 2. Native/API Logout Flow (Ory Kratos) For native or API clients (such as mobile apps), use the session token to log out: - Call the
/self-service/logout/api
endpoint with the session token in the request body. Example (TypeScript):
Copy code
ts await frontend.performNativeLogout({   performNativeLogoutBody: {     session_token: token,   }, })
This revokes the session token and logs out the user [Native API applications](https://www.ory.com/docs/kratos/self-service/flows/user-logout#native-api-applications). --- ### 3. OpenID Connect/OAuth2 Logout (Ory Hydra) For OIDC/OAuth2, Ory supports: - Front-Channel Logout: Redirects the browser to a registered
frontchannel_logout_uri
after logout. - Back-Channel Logout: Sends a POST request with a
logout_token
to a registered
backchannel_logout_uri
when the user logs out. To initiate logout, call the
/oauth2/sessions/logout
endpoint. You can use parameters like
post_logout_redirect_uri
,
state
, and
id_token_hint
to control the redirect and state after logout [OpenID Connect logout](https://www.ory.com/docs/oauth2-oidc/oidc-logout#redirect-after-logout). --- ### Summary Table | Application Type | Endpoint | Method | Notes | |------------------|------------------------------------------|----------|-----------------------------------------------------------------------| | Browser |
/self-service/logout/browser
| GET | Generates logout URL, then redirect user to it | | Browser |
/self-service/logout
| GET | Completes logout with token from previous step | | Native/API |
/self-service/logout/api
| DELETE | Send session token in body | | OIDC/OAuth2 |
/oauth2/sessions/logout
| GET | Initiates OIDC/OAuth2 logout, supports redirect and state parameters | --- For more details and code samples, see the [Ory Kratos Logout documentation](https://www.ory.com/docs/kratos/self-service/flows/user-logout) and [Ory OAuth2 & OpenID Connect logout documentation](https://www.ory.com/docs/oauth2-oidc/oidc-logout).
b
@chilly-king-10285 how do i notify my backend that a user has verified thier account
c
A message from kapa.ai
To notify your backend when a user has verified their account in Ory Kratos, you can use Ory Actions with webhooks. Specifically, you can configure a webhook to trigger after a successful verification flow. Here's how to set it up: ### 1. Configure a Webhook for the Verification Flow Add a webhook action to the
after
verification flow in your Kratos configuration. This webhook will be called when a user successfully verifies their account. Example configuration:
Copy code
yaml selfservice:   flows:     verification:       enabled: true       use: code  # or 'link'       after:         hooks:           - hook: web_hook             config:               url: <https://your-backend.com/webhooks/verification-success>               method: POST               body: <base64://ENCODED_JSONNET>  # Optional: customize the payload               auth:                 type: api_key  # Optional: if your backend requires authentication                 config:                   name: Authorization                   value: Bearer YOUR_API_KEY                   in: header
### 2. Customize the Webhook Payload (Optional) You can use a Jsonnet template to customize the data sent to your backend. For example: verification-webhook.jsonnet:
Copy code
jsonnet function(ctx) {   user_id: ctx.identity.id,   email: ctx.identity.verifiable_addresses[0].value,   verified: ctx.identity.verifiable_addresses[0].verified,   verification_status: ctx.identity.verifiable_addresses[0].status }
Base64-encode this file and reference it in the
body
field:
Copy code
bash cat verification-webhook.jsonnet | base64 | pbcopy
Then update your config:
Copy code
yaml body: <base64://ENCODED_JSONNET>
### 3. Handle the Webhook in Your Backend Your backend should listen for POST requests at the configured endpoint (e.g.,
/webhooks/verification-success
) and process the verification event. The webhook payload will include the identity data, including the verified status. Example payload received by your backend:
Copy code
json {   "user_id": "abc123",   "email": "[email protected]",   "verified": true,   "verification_status": "completed" }
### 4. Apply the Configuration Update your Ory Identities configuration using the Ory CLI:
Copy code
bash ory update identity-config --project <project-id> --workspace <workspace-id> --file updated_config.yaml
--- ### Alternative: Use Live Event Streams If you need real-time notifications for verification events, you can also use Ory Live Event Streams. The
VerificationSucceeded
event is emitted when a user successfully verifies their account [Event names](https://www.ory.com/docs/actions/live-events#event-names). --- ### Summary Configure a webhook in the
after
verification flow to notify your backend when a user verifies their account. Use Jsonnet to customize the payload if needed, and handle the webhook in your backend to process the verification event. For more details, see: - [Trigger custom logic with webhooks](https://www.ory.com/docs/guides/integrate-with-ory-cloud-through-webhooks) - [Configure hooks](https://www.ory.com/docs/kratos/hooks/configure-hooks) - [Live event streams](https://www.ory.com/docs/actions/live-events)
b
@chilly-king-10285 i get this The configuration contains values or keys which are invalid: selfservice.flows: map[aftermap[default browser return urlhttp://localhost:3000/main/overview/] errormap[ui urlhttps://www.ory.sh/kratos/docs/fallback/error] loginmap[lifespan1h ui_url:http://localhost:3000/auth/login] recoverymap[enabledfalse lifespan:1h notify_unknown_recipients:false ui_url:http://localhost:3000/auth/recovery use:code] registrationmap[aftermap[codemap[hooks[map[hook:session]]]] enabled:true lifespan:1h login_hints:false ui_url:http://localhost:3000/auth/register] settingsmap[lifespan1h privileged_session_max_age:1h required_aal:highest_available ui_url:http://localhost:3000/auth/settings] verificationmap[aftermap[default_browser_return_url:http://localhost:3000/onboarding hooks[map[configmap[bodyfile///etc/config/kratos/hooks/verification.jsonnet method:POST url:http://localhost:8080/api/v1/account/webhook/email-verification] hook:web_hook]]] enabled:true lifespan:10m notify_unknown_recipients:false ui_url:http://localhost:3000/account/verify use:link]] ^-- additionalProperties "after" not allowed time=2025-10-18T224024Z level=info msg=A change to a configuration file was detected. audience=application event_type=*watcherx.ChangeEvent file=/etc/config/kratos/kratos.yml service_name=Ory Kratos service_version=v1.1.0 time=2025-10-18T224024Z level=error msg=The changed configuration is invalid and could not be loaded. Rolling back to the last working configuration revision. Please address the validation errors before restarting the process. audience=application event=&jsonschema.ValidationError{Message:"additionalProperties \"after\" not allowed", InstancePtr:"#/selfservice/flows", SchemaURL:"https://github.com/ory/kratos/embedx/config.schema.json", SchemaPtr:"#/properties/selfservice/properties/flows/additionalProperties", Context:jsonschema.ValidationErrorContext(nil), Causes:[]*jsonschema.ValidationError(nil)} service_name=Ory Kratos service_version=v1.1.0
c
A message from kapa.ai
The error message indicates that you have an
after
configuration at the wrong level in your
selfservice.flows
section. Specifically, you have:
Copy code
yaml selfservice:   flows:     after:       default_browser_return_url: <http://localhost:3000/main/overview/>
This is not allowed. The
after
configuration should be nested inside specific flows (like
registration
,
verification
, etc.), not at the top level of
selfservice.flows
. ### How to Fix Remove the top-level
after
configuration and place it inside the appropriate flow. For example, if you want to set a default redirect after registration, it should be:
Copy code
yaml selfservice:   flows:     registration:       after:         default_browser_return_url: <http://localhost:3000/main/overview/>
### Corrected Configuration Structure Here's the corrected structure based on your config:
Copy code
yaml selfservice:   flows:     error:       ui_url: <https://www.ory.sh/kratos/docs/fallback/error>          login:       lifespan: 1h       ui_url: <http://localhost:3000/auth/login>          recovery:       enabled: false       lifespan: 1h       notify_unknown_recipients: false       ui_url: <http://localhost:3000/auth/recovery>       use: code          registration:       enabled: true       lifespan: 1h       login_hints: false       ui_url: <http://localhost:3000/auth/register>       after:         default_browser_return_url: <http://localhost:3000/main/overview/>  # Move here if needed         code:           hooks:             - hook: session          settings:       lifespan: 1h       privileged_session_max_age: 1h       required_aal: highest_available       ui_url: <http://localhost:3000/auth/settings>          verification:       enabled: true       lifespan: 10m       notify_unknown_recipients: false       ui_url: <http://localhost:3000/account/verify>       use: link       after:         default_browser_return_url: <http://localhost:3000/onboarding>         hooks:           - hook: web_hook             config:               url: <http://localhost:8080/api/v1/account/webhook/email-verification>               method: POST               body: file:///etc/config/kratos/hooks/verification.jsonnet
### Key Points - The
after
configuration must be inside a specific flow (e.g.,
registration
,
verification
), not at the top level of
selfservice.flows
. - Each flow can have its own
after
section with hooks and redirect URLs. For more details on configuring hooks and flows, see the [Ory Kratos hooks documentation](https://www.ory.com/docs/kratos/hooks/configure-hooks).
b
i get this. The configuration contains values or keys which are invalid: selfservice.flows: map[aftermap[default browser return urlhttp://localhost:3000/main/overview/] errormap[ui urlhttps://www.ory.sh/kratos/docs/fallback/error] loginmap[lifespan1h ui_url:http://localhost:3000/auth/login] recoverymap[enabledfalse lifespan:1h notify_unknown_recipients:false ui_url:http://localhost:3000/auth/recovery use:code] registrationmap[aftermap[codemap[hooks[map[hook:session]]]] enabled:true lifespan:1h login_hints:false ui_url:http://localhost:3000/auth/register] settingsmap[lifespan1h privileged_session_max_age:1h required_aal:highest_available ui_url:http://localhost:3000/auth/settings] verificationmap[aftermap[default_browser_return_url:http://localhost:3000/onboarding hooks[map[configmap[bodyfile///etc/config/kratos/hooks/verification.jsonnet method:POST url:http://localhost:8080/api/v1/account/webhook/email-verification] hook:web_hook]]] enabled:true lifespan:10m notify_unknown_recipients:false ui_url:http://localhost:3000/account/verify use:link]] ^-- additionalProperties "after" not allowed time=2025-10-18T224024Z level=info msg=A change to a configuration file was detected. audience=application event_type=*watcherx.ChangeEvent file=/etc/config/kratos/kratos.yml service_name=Ory Kratos service_version=v1.1.0 time=2025-10-18T224024Z level=error msg=The changed configuration is invalid and could not be loaded. Rolling back to the last working configuration revision. Please address the validation errors before restarting the process. audience=application event=&jsonschema.ValidationError{Message:"additionalProperties \"after\" not allowed", InstancePtr:"#/selfservice/flows", SchemaURL:"https://github.com/ory/kratos/embedx/config.schema.json", SchemaPtr:"#/properties/selfservice/properties/flows/additionalProperties", Context:jsonschema.ValidationErrorContext(nil), Causes:[]*jsonschema.ValidationError(nil)} service_name=Ory Kratos service_version=v1.1.0 with this config
Copy code
dsn: <cockroach://root@cockroach:26257/defaultdb?sslmode=disable>

serve:
  public:
    base_url: <http://localhost:4433/>
    cors:
      enabled: true
      allowed_origins:
        - <http://localhost:3000>
      allowed_methods:
        - POST
        - GET
        - PUT
        - PATCH
        - DELETE
        - OPTIONS
      allowed_headers:
        - Authorization
        - Content-Type
        - Cookie
      exposed_headers:
        - Content-Type
        - Set-Cookie
      allow_credentials: true
  admin:
    base_url: <http://localhost:4434/>

selfservice:
  default_browser_return_url: <http://localhost:3000/main/overview>
  flows:
    login:
      ui_url: <http://localhost:3000/auth/login>
    after:
      default_browser_return_url: <http://localhost:3000/main/overview>
    registration:
      enabled: true
      ui_url: <http://localhost:3000/auth/register>
      after:
        code:
          hooks:
            - hook: session
    settings:
      ui_url: <http://localhost:3000/auth/settings>
    recovery:
      ui_url: <http://localhost:3000/auth/recovery>
    verification:
      enabled: true
      ui_url: <http://localhost:3000/account/verify>
      lifespan: 10m
      use: link
      after:
        default_browser_return_url: <http://localhost:3000/onboarding>
        hooks:
          - hook: web_hook
            config:
              url: <http://localhost:8080/api/v1/account/webhook/email-verification>
              method: POST
              body: file:///etc/config/kratos/hooks/verification.jsonnet
  methods:
    password:
      enabled: true
    link:
      enabled: true
identity:
  default_schema_id: default
  schemas:
    - id: default
      url: file:///etc/config/kratos/identity-schemas/user.schema.json

courier:
  delivery_strategy: smtp
  smtp:
    connection_uri: "<smtps://resend:re_3RVyNtRU_77gr1dB2kLghPow8WTrV6Los@smtp.resend.com:465>"
    from_address: "onboarding@resend.dev"
  template_override_path: /etc/config/kratos/email-templates
  templates:
    verification:
      valid:
        email:
          body:
            html: file:///etc/config/kratos/email-templates/verification/body.html.gotmpl
@chilly-king-10285 i get this. The configuration contains values or keys which are invalid: selfservice.flows: map[aftermap[default browser return urlhttp://localhost:3000/main/overview/] errormap[ui urlhttps://www.ory.sh/kratos/docs/fallback/error] loginmap[lifespan1h ui_url:http://localhost:3000/auth/login] recoverymap[enabledfalse lifespan:1h notify_unknown_recipients:false ui_url:http://localhost:3000/auth/recovery use:code] registrationmap[aftermap[codemap[hooks[map[hook:session]]]] enabled:true lifespan:1h login_hints:false ui_url:http://localhost:3000/auth/register] settingsmap[lifespan1h privileged_session_max_age:1h required_aal:highest_available ui_url:http://localhost:3000/auth/settings] verificationmap[aftermap[default_browser_return_url:http://localhost:3000/onboarding hooks[map[configmap[bodyfile///etc/config/kratos/hooks/verification.jsonnet method:POST url:http://localhost:8080/api/v1/account/webhook/email-verification] hook:web_hook]]] enabled:true lifespan:10m notify_unknown_recipients:false ui_url:http://localhost:3000/account/verify use:link]] ^-- additionalProperties "after" not allowed time=2025-10-18T224024Z level=info msg=A change to a configuration file was detected. audience=application event_type=*watcherx.ChangeEvent file=/etc/config/kratos/kratos.yml service_name=Ory Kratos service_version=v1.1.0 time=2025-10-18T224024Z level=error msg=The changed configuration is invalid and could not be loaded. Rolling back to the last working configuration revision. Please address the validation errors before restarting the process. audience=application event=&jsonschema.ValidationError{Message:"additionalProperties \"after\" not allowed", InstancePtr:"#/selfservice/flows", SchemaURL:"https://github.com/ory/kratos/embedx/config.schema.json", SchemaPtr:"#/properties/selfservice/properties/flows/additionalProperties", Context:jsonschema.ValidationErrorContext(nil), Causes:[]*jsonschema.ValidationError(nil)} service_name=Ory Kratos service_version=v1.1.0 with this config
Copy code
dsn: <cockroach://root@cockroach:26257/defaultdb?sslmode=disable>

serve:
  public:
    base_url: <http://localhost:4433/>
    cors:
      enabled: true
      allowed_origins:
        - <http://localhost:3000>
      allowed_methods:
        - POST
        - GET
        - PUT
        - PATCH
        - DELETE
        - OPTIONS
      allowed_headers:
        - Authorization
        - Content-Type
        - Cookie
      exposed_headers:
        - Content-Type
        - Set-Cookie
      allow_credentials: true
  admin:
    base_url: <http://localhost:4434/>

selfservice:
  default_browser_return_url: <http://localhost:3000/main/overview>
  flows:
    login:
      ui_url: <http://localhost:3000/auth/login>
    after:
      default_browser_return_url: <http://localhost:3000/main/overview>
    registration:
      enabled: true
      ui_url: <http://localhost:3000/auth/register>
      after:
        code:
          hooks:
            - hook: session
    settings:
      ui_url: <http://localhost:3000/auth/settings>
    recovery:
      ui_url: <http://localhost:3000/auth/recovery>
    verification:
      enabled: true
      ui_url: <http://localhost:3000/account/verify>
      lifespan: 10m
      use: link
      after:
        default_browser_return_url: <http://localhost:3000/onboarding>
        hooks:
          - hook: web_hook
            config:
              url: <http://localhost:8080/api/v1/account/webhook/email-verification>
              method: POST
              body: file:///etc/config/kratos/hooks/verification.jsonnet
  methods:
    password:
      enabled: true
    link:
      enabled: true
identity:
  default_schema_id: default
  schemas:
    - id: default
      url: file:///etc/config/kratos/identity-schemas/user.schema.json

courier:
  delivery_strategy: smtp
  smtp:
    connection_uri: "<smtps://resend:re_3RVyNtRU_77gr1dB2kLghPow8WTrV6Los@smtp.resend.com:465>"
    from_address: "onboarding@resend.dev"
  template_override_path: /etc/config/kratos/email-templates
  templates:
    verification:
      valid:
        email:
          body:
            html: file:///etc/config/kratos/email-templates/verification/body.html.gotmpl
c
A message from kapa.ai
The error message indicates that you have an
after
configuration at the wrong level in your
selfservice.flows
section. Looking at your config, you have:
Copy code
yaml selfservice:   flows:     login:       ui_url: <http://localhost:3000/auth/login>     after:       default_browser_return_url: <http://localhost:3000/main/overview>
This is not allowed. The
after
configuration cannot be a direct child of
selfservice.flows
. It must be nested inside specific flows (like
login
,
registration
, etc.). ### How to Fix Remove the standalone
after
block and place it inside the
login
flow (or whichever flow you want to configure). Here's the corrected configuration:
Copy code
yaml dsn: <cockroach://root@cockroach:26257/defaultdb?sslmode=disable>  serve:   public:     base_url: <http://localhost:4433/>     cors:       enabled: true       allowed_origins:         - <http://localhost:3000>       allowed_methods:         - POST         - GET         - PUT         - PATCH         - DELETE         - OPTIONS       allowed_headers:         - Authorization         - Content-Type         - Cookie       exposed_headers:         - Content-Type         - Set-Cookie       allow_credentials: true   admin:     base_url: <http://localhost:4434/>  selfservice:   default_browser_return_url: <http://localhost:3000/main/overview>   flows:     login:       ui_url: <http://localhost:3000/auth/login>       after:         default_browser_return_url: <http://localhost:3000/main/overview>     registration:       enabled: true       ui_url: <http://localhost:3000/auth/register>       after:         code:           hooks:             - hook: session     settings:       ui_url: <http://localhost:3000/auth/settings>     recovery:       ui_url: <http://localhost:3000/auth/recovery>     verification:       enabled: true       ui_url: <http://localhost:3000/account/verify>       lifespan: 10m       use: link       after:         default_browser_return_url: <http://localhost:3000/onboarding>         hooks:           - hook: web_hook             config:               url: <http://localhost:8080/api/v1/account/webhook/email-verification>               method: POST               body: file:///etc/config/kratos/hooks/verification.jsonnet   methods:     password:       enabled: true     link:       enabled: true  identity:   default_schema_id: default   schemas:     - id: default       url: file:///etc/config/kratos/identity-schemas/user.schema.json  courier:   delivery_strategy: smtp   smtp:     connection_uri: "<smtps://resend:re_3RVyNtRU_77gr1dB2kLghPow8WTrV6Los@smtp.resend.com:465>"     from_address: "onboarding@resend.dev"   template_override_path: /etc/config/kratos/email-templates   templates:     verification:       valid:         email:           body:             html: file:///etc/config/kratos/email-templates/verification/body.html.gotmpl
### Key Changes - Moved the
after
block from being a direct child of
selfservice.flows
to inside the
login
flow. - Each flow (login, registration, verification, etc.) can have its own
after
section with hooks and redirect URLs. This should resolve the validation error. For more details on configuring flows and redirects, see the [Ory Kratos browser redirect documentation](https://www.ory.com/docs/kratos/concepts/browser-redirect-flow-completion).