square-napkin-92357
06/04/2025, 3:21 AMbrief-egg-61061
06/04/2025, 3:21 AMbrief-egg-61061
06/04/2025, 3:21 AM"verification": { "via": "email" }
in the schema). - If a user does not provide an email, no verification is triggered for that user. - If you want to allow users to register without an email (e.g., using only a phone number), make sure the email
field is not required in your schema. - If the email
field is present and marked as verifiable, Ory will send a verification email after registration, even if the user registered using another method (like phone/SMS) [Phone+email schema: verification email is sent when signed up with SMS code](https://github.com/ory/kratos/issues/4161). How to configure: 1. Make the email trait optional in your identity schema: - Do not include "email"
in the required
array of your schema's traits
object. 2. Mark email as verifiable only if present: - Keep the "verification": { "via": "email" }
property in the email trait definition. - Ory will only require verification if the user provides an email during registration. Example schema snippet: json { "properties": { "traits": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "<http://ory.sh/kratos|ory.sh/kratos>": { "verification": { "via": "email" } } }, "phone": { "type": "string", "format": "tel" } }, "required": ["phone"], // Only phone is required "additionalProperties": false } } }
With this setup: - If a user registers with a phone only, no email verification is triggered. - If a user provides an email, they will be required to verify it. Note: If you want to completely disable email verification for all users, remove the "verification": { "via": "email" }
property from the schema. But for your use case (verify only if email is present), the above approach is correct. For more details, see the discussion and schema examples in [Phone+email schema: verification email is sent when signed up with SMS code](https://github.com/ory/kratos/issues/4161).square-napkin-92357
06/04/2025, 4:25 AMbrief-egg-61061
06/04/2025, 4:25 AMbrief-egg-61061
06/04/2025, 4:25 AMrequired_aal: highest_available
for a flow (e.g., settings or login), users who have set up TOTP (or another second factor) will be required to use it. Users who have not set up a second factor will only need their primary factor (e.g., password) [Configure multi-factor authentication in Ory Kratos](https://www.ory.sh/docs/kratos/self-hosted/mfa), [Step-up authentication](https://www.ory.sh/docs/kratos/mfa/step-up-authentication). - There is no documented method to enforce TOTP setup for only a specific group of users (e.g., based on a user trait or role) at registration or login time. Possible approaches: - You could implement custom logic in your application layer: After user registration or login, check if the user matches your criteria for requiring TOTP. If so, redirect them to the settings flow and prompt them to enroll TOTP before allowing further access. - Alternatively, you could use traits in your identity schema to flag users who must have TOTP, and enforce this requirement in your application's business logic, but this is not handled automatically by Kratos itself. Summary: Ory Kratos enforces MFA requirements at the flow level, not per user. To require TOTP for only some users, you must implement this logic in your application, as there is no built-in configuration for per-user TOTP enforcement in the current Ory Kratos documentation and features. If you need more granular, per-user enforcement, you will need to handle this outside of Kratos using your own application logic after checking user traits or roles [Step-up authentication](https://www.ory.sh/docs/kratos/mfa/step-up-authentication), [Configure multi-factor authentication in Ory Kratos](https://www.ory.sh/docs/kratos/self-hosted/mfa). I'm sorry, but the knowledge sources do not describe a built-in way to enforce TOTP for only some users directly in Ory Kratos configuration.square-napkin-92357
06/04/2025, 6:14 AMpasswordless_enabled
?brief-egg-61061
06/04/2025, 6:14 AMbrief-egg-61061
06/04/2025, 6:14 AMpasswordless_enabled
setting in Ory Kratos is to allow users to authenticate without needing a traditional password. When passwordless_enabled
is set to true
for the code
method, users can log in using a one-time code sent to their email or phone (via SMS), instead of entering a password. This is particularly useful for applications that want to simplify the login process and improve user experience by removing the need for password management. Typical scenarios include: - Frictionless onboarding: Users can sign up and log in with just their email or phone number, receiving a one-time code for authentication. - Enhanced security: Reduces risks associated with password reuse and phishing, as users do not need to remember or enter passwords. - Modern authentication flows: Supports use cases like "magic link" or "OTP" (one-time password) authentication, which are popular in consumer apps. To enable passwordless login with one-time codes, you set passwordless_enabled: true
in your configuration for the code
method: yaml selfservice: methods: code: passwordless_enabled: true
This can be configured via the Ory Console or CLI as well. When enabled, users will receive a code via email or SMS and use it to authenticate, bypassing the need for a password entirely [Enable one-time codes](https://www.ory.sh/docs/identities/get-started/passwordless), [Email and SMS one-time-code authentication](https://www.ory.sh/docs/kratos/passwordless/one-time-code).square-napkin-92357
06/04/2025, 6:17 AM{
"error": {
"id": "session_aal1_required",
"code": 401,
"status": "Unauthorized",
"request": "0d89e5c4eb4bb958d03e9b75e5314924",
"reason": "You can not requested a higher AAL (AAL2/AAL3) without an active session.",
"message": "aal2 and aal3 can only be requested if a session exists already"
}
}
brief-egg-61061
06/04/2025, 6:17 AMbrief-egg-61061
06/04/2025, 6:17 AMjson { "error": { "id": "session_aal1_required", "code": 401, "status": "Unauthorized", "reason": "You can not requested a higher AAL (AAL2/AAL3) without an active session.", "message": "aal2 and aal3 can only be requested if a session exists already" } }
means that you are trying to request a higher Authenticator Assurance Level (AAL2 or AAL3, which require multi-factor authentication) without having an active session at AAL1. In Ory Kratos, passwordless login (using a one-time code) is considered a single-factor authentication and only grants AAL1. To request AAL2 (for example, to access a protected resource or perform a sensitive operation), the user must first have an active session at AAL1, and then "step up" to AAL2 by completing a second factor (like TOTP). Key points from the knowledge sources: - Passwordless login with a one-time code only provides AAL1, as it is a single-factor authentication method. - To access resources or flows that require AAL2, the user must already have an active session (AAL1) and then complete a second factor to upgrade the session to AAL2. - If you try to initiate an AAL2 flow (e.g., by visiting a URL with ?aal=aal2
) without an existing session, you will get this error. The correct flow is: first authenticate (AAL1), then step up to AAL2 if required by the application or endpoint [[Step-up authentication](https://www.ory.sh/docs/kratos/mfa/step-up-authentication)]. Summary: You cannot request AAL2 directly with passwordless login. The user must first log in (AAL1), and only then can you prompt them for a second factor to upgrade to AAL2. This is by design in Ory Kratos to ensure that multi-factor authentication is always a two-step process: establish a session, then step up if needed. If you need to enforce AAL2, make sure your users have a primary session (AAL1) before requiring the second factor [[Step-up authentication](https://www.ory.sh/docs/kratos/mfa/step-up-authentication)].square-napkin-92357
06/04/2025, 6:21 AMcurl --request GET \
--url '{{host}}/kratos/self-service/login/browser?aal=aal1' \
--header 'accept: application/json'
brief-egg-61061
06/04/2025, 6:21 AMbrief-egg-61061
06/04/2025, 6:21 AMGET /self-service/login/browser?aal=aal1
This will start a login flow where only the first authentication factor (such as password or passwordless one-time code) is required. This is the correct approach if you want to allow users to log in without requiring a second factor (AAL2) [[createBrowserLoginFlow](https://www.ory.sh/docs/kratos/reference/api)]. Your example cURL command is correct for this use case: bash curl --request GET \ --url '{{host}}/kratos/self-service/login/browser?aal=aal1' \ --header 'accept: application/json'
This will ensure the login flow is for AAL1, and users will not be prompted for a second factor unless you later initiate a step-up to AAL2 [[Step-up authentication](https://www.ory.sh/docs/kratos/mfa/step-up-authentication)].square-napkin-92357
06/04/2025, 6:22 AMcurl --request GET \
--url '{{host}}/kratos/self-service/login/browser?aal=aal1' \
--header 'accept: application/json'
brief-egg-61061
06/04/2025, 6:22 AMbrief-egg-61061
06/04/2025, 6:22 AMbash curl --request GET \ --url '{{host}}/kratos/self-service/login/browser?aal=aal1' \ --header 'accept: application/json'
you will receive a response containing a flow id
and a ui.action
URL. The next step is to submit the user's credentials (such as identifier and password, or a one-time code if using passwordless) to the ui.action
URL using a POST request. Example for password-based login: 1. Extract the flow ID and CSRF token from the response. 2. Submit the login form (replace placeholders with actual values): bash curl -X POST \ -H 'Content-Type: application/json' \ -H 'Accept: application/json' \ -d '{"method":"password","csrf_token":"<csrf_token>","identifier":"<user-identifier>","password":"<user-password>"}' \ -b cookies.txt \ -c cookies.txt \ "{{host}}/kratos/self-service/login?flow=<flow-id>"
- The csrf_token
is required and can be found in the flow response under ui.nodes
. - Use the -b
and -c
flags to handle cookies for browser flows. If you are using passwordless (one-time code) login, the payload will differ (e.g., you will send the code instead of a password). For more details and examples, see the [Submit login flow](https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-basic-integration#submit-login-flow) documentation. Summary of steps: 1. Start the login flow (GET). 2. Parse the response for flow id
, ui.action
, and csrf_token
. 3. Submit credentials to the ui.action
URL (POST) with the required fields and cookies. This is the standard way to complete a login after retrieving the flow in Ory Kratos [[Submit login flow](https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-basic-integration#submit-login-flow)].square-napkin-92357
06/04/2025, 6:29 AMcurl --request POST \
--url '{{host}}/kratos/self-service/login?flow=530f4a51-19eb-4570-8ebc-068dfbc6f402' \
--header 'content-type: application/json' \
--data '{
"csrf_token": "{{totpFlowCsrf}}",
"method": "totp",
"totp_code": "558929"
}'
but i get error
"messages": [
{
"id": 4010002,
"text": "Could not find a strategy to log you in with. Did you fill out the form correctly?",
"type": "error"
}
]
brief-egg-61061
06/04/2025, 6:29 AMbrief-egg-61061
06/04/2025, 6:29 AM"Could not find a strategy to log you in with. Did you fill out the form correctly?" (4010002)
means that the login method you specified ("method": "totp"
) is not available or enabled for this login flow. If you want to log in using a one-time code (passwordless), you should use the code
method, not totp
. The totp
method is for Time-based One-Time Passwords (like Google Authenticator), while the code
method is for codes sent via email or SMS. How to log in with a one-time code: 1. Start the login flow (as you did). 2. Submit the code using the code
method. Your POST request should look like this: bash curl --request POST \ --url '{{host}}/kratos/self-service/login?flow=530f4a51-19eb-4570-8ebc-068dfbc6f402' \ --header 'content-type: application/json' \ --data '{ "csrf_token": "{{csrf_token}}", "method": "code", "identifier": "<mailto:user@example.com|user@example.com>", "code": "558929" }'
- Replace {{csrf_token}}
with the CSRF token from the flow. - Replace <mailto:user@example.com|user@example.com>
with the identifier (email or phone) used to receive the code. - Replace 558929
with the actual code received by the user. Key points: - The method
must be "code"
for passwordless one-time code login. - The identifier
field is required to specify which user is logging in. - The code
field is the one-time code sent to the user. For more details, see the [Ory Kratos API reference for the code method](https://www.ory.sh/docs/kratos/reference/api) and the [one-time code documentation](https://www.ory.sh/docs/kratos/passwordless/one-time-code). If you use the wrong method (like totp
for a code flow), you will get the 4010002 error as described above [UI message codes](https://www.ory.sh/docs/kratos/concepts/ui-user-interface#could-not-find-a-strategy-to-log-you-in-with-did-you-fill-out-the-form-correctly-4010002).square-napkin-92357
06/04/2025, 6:33 AMbrief-egg-61061
06/04/2025, 6:33 AMbrief-egg-61061
06/04/2025, 6:33 AMjson { "properties": { "traits": { "type": "object", "properties": { "user": { "type": "string", "<http://ory.sh/kratos|ory.sh/kratos>": { "credentials": { "code": { "identifier": true } } } } } } } }
- The important part is "credentials": { "code": { "identifier": true } }
under your user
field. - This tells Ory Kratos to use the user
trait as the identifier for the one-time code login flow. When you submit the login request, use the user
value as the `identifier`: json { "csrf_token": "<csrf_token>", "method": "code", "identifier": "<user>", "code": "<one-time-code>" }
Note: The knowledge sources provide examples for using email
, username
, or phone
as identifiers, and the same approach applies to any custom field name like user
as long as you mark it as an identifier for the relevant method in your schema. For more details, see the [custom identity schema for one-time code](https://www.ory.sh/docs/kratos/passwordless/one-time-code#custom-identity-schema) and [identity schema examples](https://www.ory.sh/docs/kratos/manage-identities/customize-identity-schema#examples). If you encounter issues, double-check that your schema is correctly configured and that the field you use as the identifier is not required to be an email or phone unless you want it to be validated as such.square-napkin-92357
06/04/2025, 6:35 AM"messages": [
{
"id": 4000035,
"text": "This account does not exist or has not setup sign in with code.",
"type": "error"
}
]
brief-egg-61061
06/04/2025, 6:35 AMbrief-egg-61061
06/04/2025, 6:35 AM{
"id": 4000035,
"text": "This account does not exist or has not setup sign in with code.",
"type": "error"
}
means that either: 1. The identifier you provided (e.g., username, email, or phone) does not match any existing account, or 2. The account exists, but the identity schema for that account does not have the one-time code (code
) login method enabled for the identifier field you are using. To resolve this: - Ensure the account exists with the identifier you are using. - Check your identity schema: The field you use as the identifier (e.g., user
, username
, email
, etc.) must be marked with the following extension for the code
method: json "<http://ory.sh/kratos|ory.sh/kratos>": { "credentials": { "code": { "identifier": true } } }
For example, if you use user
as the identifier: json { "properties": { "traits": { "type": "object", "properties": { "user": { "type": "string", "<http://ory.sh/kratos|ory.sh/kratos>": { "credentials": { "code": { "identifier": true } } } } } } } }
- If you are using email or phone for code delivery, also specify the via
property (e.g., "via": "email"
or "via": "sms"
) if needed. See the documentation for more details and schema examples: [Passwordless one-time code login identifier](https://www.ory.sh/docs/kratos/manage-identities/customize-identity-schema#passwordless-one-time-code-login-identifier), [Custom identity schema for one-time code](https://www.ory.sh/docs/kratos/passwordless/one-time-code#custom-identity-schema). This error is documented in the Ory Kratos UI messages: [This account does not exist or has not setup sign in with code. (4000035)](https://www.ory.sh/docs/kratos/concepts/ui-user-interface#this-account-does-not-exist-or-has-not-setup-sign-in-with-code-4000035). Summary: You must ensure both that the account exists and that the identifier field is properly configured for code-based login in your identity schema. If either is missing, you will get this error.square-napkin-92357
06/04/2025, 6:39 AM{
"$id": "kratos/email-password/identity.schema.json",
"$schema": "<http://json-schema.org/draft-07/schema#>",
"title": "Person",
"type": "object",
"properties": {
"traits": {
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email",
"title": "E-Mail",
"minLength": 8,
"maxLength": 50,
"<http://ory.sh/kratos|ory.sh/kratos>": {
"credentials": {
"password": {
"identifier": false
},
"code": {
"identifier": true,
"via": "email"
}
},
"verification": {
"via": "email"
},
"recovery": {
"via": "email"
}
}
},
"username": {
"type": "string",
"format": "username",
"title": "User name",
"pattern": "^[a-zA-Z0-9][a-zA-Z0-9@_.-]{7,49}$",
"minLength": 8,
"maxLength": 50,
"<http://ory.sh/kratos|ory.sh/kratos>": {
"credentials": {
"password": {
"identifier": true
},
"totp": {
"account_name": true
}
}
}
}
},
"required": [
"username"
],
"additionalProperties": false
}
}
}
how can i change?brief-egg-61061
06/04/2025, 6:39 AMbrief-egg-61061
06/04/2025, 6:39 AMusername
field is marked as the identifier for the code
method. Currently, your schema only allows the email
field to be used for code-based login ("code": { "identifier": true, "via": "email" }
), while username
is only set up for password and TOTP. How to change your schema: 1. Add the code
credential with "identifier": true
to the username
field. 2. If you want to use the username as the identifier for code-based login, you do not need the "via": "email"
property under username
. Example update: json { "$id": "kratos/email-password/identity.schema.json", "$schema": "<http://json-schema.org/draft-07/schema#>", "title": "Person", "type": "object", "properties": { "traits": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "title": "E-Mail", "minLength": 8, "maxLength": 50, "<http://ory.sh/kratos|ory.sh/kratos>": { "credentials": { "password": { "identifier": false }, "code": { "identifier": false, // Set to false or remove if not using email for code login "via": "email" } }, "verification": { "via": "email" }, "recovery": { "via": "email" } } }, "username": { "type": "string", "title": "User name", "pattern": "^[a-zA-Z0-9][a-zA-Z0-9@_.-]{7,49}$", "minLength": 8, "maxLength": 50, "<http://ory.sh/kratos|ory.sh/kratos>": { "credentials": { "password": { "identifier": true }, "totp": { "account_name": true }, "code": { "identifier": true } } } } }, "required": ["username"], "additionalProperties": false } } }
Key points: - The "code": { "identifier": true }
under username
enables passwordless one-time code login using the username as the identifier. - If you want to disable code login via email, set "identifier": false
or remove the code
credential from the email
field. - Make sure your application sends the username as the identifier
when performing the code login flow. For more details, see the [passwordless one-time code login identifier documentation](https://www.ory.sh/docs/kratos/manage-identities/customize-identity-schema#passwordless-one-time-code-login-identifier) and [custom identity schema for one-time code](https://www.ory.sh/docs/kratos/passwordless/one-time-code#custom-identity-schema). If you follow this update, users will be able to log in with a one-time code using their username as the identifier.square-napkin-92357
06/04/2025, 7:28 AMcurl --request POST \
--url '{{host}}kratos/self-service/recovery?flow=fdae3164-6602-4921-961d-2be6ae915323' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'cookie: {{recoveryFlowCookie}}' \
--cookie '{{recoveryFlowCookie}}' \
--data '{
"csrf_token": "{{recoveryFlowCsrf}}",
"method": "code",
"code": "273228"
}'
I get error
{
"error": {
"id": "browser_location_change_required",
"code": 422,
"status": "Unprocessable Entity",
"reason": "In order to complete this flow please redirect the browser to: <https://www.ory.sh/kratos/docs/fallback/settings?flow=415c3bbb-dc57-49d1-aba3-9b6cc4ea2cd4>",
"message": "browser location change required"
},
"redirect_browser_to": "<https://www.ory.sh/kratos/docs/fallback/settings?flow=415c3bbb-dc57-49d1-aba3-9b6cc4ea2cd4>"
}
brief-egg-61061
06/04/2025, 7:28 AMbrief-egg-61061
06/04/2025, 7:28 AMjson { "error": { "id": "browser_location_change_required", "code": 422, "status": "Unprocessable Entity", "reason": "In order to complete this flow please redirect the browser to: <https://www.ory.sh/kratos/docs/fallback/settings?flow=415c3bbb-dc57-49d1-aba3-9b6cc4ea2cd4>", "message": "browser location change required" }, "redirect_browser_to": "<https://www.ory.sh/kratos/docs/fallback/settings?flow=415c3bbb-dc57-49d1-aba3-9b6cc4ea2cd4>" }
means that Ory Kratos requires the browser to be redirected to a new location to continue or complete the recovery flow. This is a standard behavior for browser-based flows when a location change is necessary, such as after a successful recovery or when the flow state changes (for example, after submitting a valid recovery code). What to do: - When you receive this error with id: "browser_location_change_required"
and a redirect_browser_to
URL, your application should redirect the user's browser to the provided URL. This is how Kratos signals that the next step in the flow must be handled in the browser, not via an API call. - This is especially relevant for SPAs or custom UIs, where you need to programmatically handle the redirect in your frontend code. This behavior is documented in the Ory Kratos API and UI integration guides, where a 422 error with this ID indicates that a browser redirect is required to continue the flow. The response includes the URL you should redirect to, which will allow the user to proceed with the recovery or settings process in the browser interface [SPAs and the '422' error](https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-advanced-integration#spas-and-the-422-error). Summary: You should redirect the browser to the URL provided in the redirect_browser_to
field to continue the recovery process. This is expected behavior for browser flows in Ory Kratos when a location change is required to complete the flow.square-napkin-92357
06/04/2025, 7:35 AMbrief-egg-61061
06/04/2025, 7:35 AMbrief-egg-61061
06/04/2025, 7:35 AMid: "browser_location_change_required"
and a redirect_browser_to
URL, the correct next step is to programmatically redirect the browser to the URL provided in the redirect_browser_to
field. This is how Ory Kratos signals that the flow must continue in the browser at a new location. In practice: - Your frontend should detect this specific error in the AJAX response. - Then, use window.location.href = response.redirect_browser_to
(or similar) to redirect the user. This is the recommended approach for handling this scenario in SPAs, as described in the documentation: > A response code 422
indicates that the browser needs to be redirected with a newly created flow. Since this is an SPA, the new flow ID can be extracted from the payload and the response can be retrieved in the background instead of a redirect. > Example: > json > { > error: { > id: "browser_location_change_required", > ... > }, > redirect_browser_to: "/ui/login?flow=ad574ad7-1a3c-4b52-9f54-ef9e866f3cec" > } >
> [SPAs and the '422' error](https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-advanced-integration#spas-and-the-422-error) Summary: When you get this error in your AJAX response, redirect the browser to the URL in redirect_browser_to
to continue the flow.square-napkin-92357
06/04/2025, 7:37 AM{
"error": {
"id": "security_identity_mismatch",
"code": 403,
"status": "Forbidden",
"request": "19e48c5090c27e5df2b0af63c10d8598",
"reason": "The request was initiated by someone else and has been blocked for security reasons. Please go back and try again.",
"message": "The requested action was forbidden"
}
}
brief-egg-61061
06/04/2025, 7:38 AMbrief-egg-61061
06/04/2025, 7:38 AMjson { "error": { "id": "security_identity_mismatch", "code": 403, "status": "Forbidden", "reason": "The request was initiated by someone else and has been blocked for security reasons. Please go back and try again.", "message": "The requested action was forbidden" } }
means that the flow you are trying to complete was initiated by a different identity (user) than the one currently making the request. This is a security feature in Ory Kratos to prevent one user from completing a flow that was started by another user. Common causes: - The session cookie or authentication context has changed between starting and completing the flow. - The flow was started in one browser or device, but the completion attempt is happening in another. - The flow is being completed by a different user than the one who initiated it. How to resolve: - Make sure the same user and session are used for both starting and completing the flow. - Do not share flow URLs or tokens between users or devices. - If you see this error, restart the flow from the beginning to ensure the session context matches. This behavior is described in the Ory Kratos API documentation, where a security_identity_mismatch
error indicates that the requested ?return_to
address or flow is not allowed to be used by the current identity, and the flow was interrupted for security reasons. Adjust your application to ensure flows are only completed by the initiating user and session [[updateSettingsFlow](https://www.ory.sh/docs/kratos/reference/api)]. If you continue to see this error, double-check your session and cookie handling, especially in SPAs or when using AJAX, to ensure the correct session is maintained throughout the flow.square-napkin-92357
06/04/2025, 9:01 AMcurl --request GET \
--url '<http://127.0.0.1:4455/kratos/self-service/recovery/browser?refresh=true>' \
--header 'accept: application/json' \
--header 'content-type: application/json'
2. Send code to email
curl --request POST \
--url '<http://127.0.0.1:4455/kratos/self-service/recovery?flow={{recoveryFlowId}}>' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'cookie: {{recoveryFlowCookie}}' \
--cookie '{{recoveryFlowCookie}}' \
--data '{
"csrf_token": "{{recoveryFlowCsrf}}",
"method": "code",
"email": "<mailto:example@gmail.com|example@gmail.com>"
}'
3. Get setting flow
curl --request POST \
--url '<http://127.0.0.1:4455/kratos/self-service/recovery?flow={{recoveryFlowId}}>' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'cookie: {{recoveryFlowCookie}}' \
--cookie '{{recoveryFlowCookie}}' \
--data '{
"csrf_token": "{{recoveryFlowCsrf}}",
"method": "code",
"code": "268155"
}'
4. Change password
curl --request POST \
--url '<http://127.0.0.1:4455/kratos/self-service/settings?flow={{settingFlowId}}>' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'cookie: {{oryKratosSession}};{{settingFlowCookie}}' \
--cookie '{{oryKratosSession}};{{settingFlowCookie}}' \
--data '{
"csrf_token": "{{settingFlowCsrf}}",
"method": "password",
"password": "123SupperPassword2025$"
}'
All steps work well in my local machine (docker compose)
But when I deploy on k9s, step 3 gets the response is
{
"error": {
"id": "browser_location_change_required",
"code": 422,
"status": "Unprocessable Entity",
"reason": "In order to complete this flow please redirect the browser to: <https://www.ory.sh/kratos/docs/fallback/settings?flow=d596e88c-f173-426a-86b5-79ff07e85e27>",
"message": "browser location change required"
},
"redirect_browser_to": "<https://www.ory.sh/kratos/docs/fallback/settings?flow=d596e88c-f173-426a-86b5-79ff07e85e27>"
}
please suggest me how to fixbrief-egg-61061
06/04/2025, 9:01 AMbrief-egg-61061
06/04/2025, 9:01 AMid: "browser_location_change_required"
and a redirect_browser_to
URL after submitting the recovery code—is expected in Ory Kratos when using browser flows and AJAX (such as in SPAs or custom UIs). This response means Kratos requires the browser to be redirected to a new location (in this case, the settings flow) to continue the process. Why does this happen? - In browser flows, after a successful recovery code submission, Kratos transitions the user to a settings flow to allow them to set a new password. - Kratos signals this transition by returning a 422 error with a redirect_browser_to
field, instructing your frontend to redirect the browser to the provided URL to continue the flow [[SPAs and the '422' error](https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-advanced-integration#spas-and-the-422-error)]. How to handle this: - In your frontend, detect this specific error in your AJAX response. - Programmatically redirect the browser to the URL in the redirect_browser_to
field. For example, in JavaScript: js if (response.error && response.error.id === "browser_location_change_required") { window.location.href = response.redirect_browser_to; }
- This will allow the user to continue the password reset process in the correct flow context. Summary: This is not a misconfiguration—it's the designed behavior for browser flows in Ory Kratos. You need to handle the 422 response by redirecting the browser to the provided URL to continue the recovery and settings process [[SPAs and the '422' error](https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-advanced-integration#spas-and-the-422-error)]. If you need a fully API-driven (non-browser) flow, you would need to use the API flow endpoints and handle sessions differently, but for browser flows, this redirect is required.square-napkin-92357
06/04/2025, 9:03 AMredirect_browser_to
using ajax?brief-egg-61061
06/04/2025, 9:03 AMbrief-egg-61061
06/04/2025, 9:04 AM422
error and a redirect_browser_to
field while using AJAX, it means Kratos expects the browser to be redirected to the provided URL to continue the flow. In a Single Page Application (SPA) or AJAX context, you should programmatically redirect the browser to that URL. **You cannot "call" the next step purely via AJAX**—the flow is designed to be continued in the browser context. The correct approach is to set window.location.href
(or similar) to the value of redirect_browser_to
in your frontend code. This will navigate the user to the next step in the flow as required by Kratos. Example (JavaScript): js if (response.error && response.error.id === "browser_location_change_required") { window.location.href = response.redirect_browser_to; }
This is the recommended way to handle the 422 error in SPAs, as described in the Ory documentation: > A response code 422
indicates that the browser needs to be redirected with a newly created flow. Since this is an SPA, the new flow ID can be extracted from the payload and the response can be retrieved in the background instead of a redirect. > [SPAs and the '422' error](https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-advanced-integration#spas-and-the-422-error) Summary: You must redirect the browser to the redirect_browser_to
URL. The next step cannot be completed via AJAX alone; a browser navigation is required to continue the flow.square-napkin-92357
06/04/2025, 9:17 AMcurl --request POST \
--url '{{host}}/self-service/settings?flow=2a2a701a-7a45-4df1-a710-816cc4f9efc' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'cookie: ory_kratos_session=MTc0OTAyODM3N3xncTJXMGdUQjIyb2JVbnNnaUx6U2FNWFc3dV9mRDAyZTQ1VFF4VmNsNDY2X1N4Xy1GS1M1WkVBblZnOE5DT0R2Q0xtVzlOLV9CRXlDVUZTel9FdEl4aENjMGV6WV9oNEhkMVdWNEM4UXJHaENneHF1Z3NYUnU0aFNlT01aTm84bjI1Z2t5d1pOaDJHTE5KS1p5SEMzbS1nRkxfQllqYTl5VUZmeGcya2dxRjdVVjRJdlF3WFk4ekVVVjJKRGxmQlQ2U254b1JHZU1wVzlPNHB3bDBqdGRDUml3Y0NRcHNZRjREa2wxNmlQS3BvWmdpOEwxRlBxeVFSWXJVNWVpcll4YUZ0VW96Qm5vM01oN0RGUF8xMjZ8_zfeN1RlmMIoDP6V9RszmlOwtZn3OwCCNgjTjO4wE88=;csrf_token_308f747c083a9186054ac556e82c244ceb52f8a0e6159140ddb89100318a5e54=lq4sSeHxUIl9gpC8wT9tNwoAvi0jrumMDZeSkB/OU7A=; Path=/; Max-Age=31536000; HttpOnly; Secure; SameSite=Strict' \
--cookie 'ory_kratos_session=MTc0OTAyODM3N3xncTJXMGdUQjIyb2JVbnNnaUx6U2FNWFc3dV9mRDAyZTQ1VFF4VmNsNDY2X1N4Xy1GS1M1WkVBblZnOE5DT0R2Q0xtVzlOLV9CRXlDVUZTel9FdEl4aENjMGV6WV9oNEhkMVdWNEM4UXJHaENneHF1Z3NYUnU0aFNlT01aTm84bjI1Z2t5d1pOaDJHTE5KS1p5SEMzbS1nRkxfQllqYTl5VUZmeGcya2dxRjdVVjRJdlF3WFk4ekVVVjJKRGxmQlQ2U254b1JHZU1wVzlPNHB3bDBqdGRDUml3Y0NRcHNZRjREa2wxNmlQS3BvWmdpOEwxRlBxeVFSWXJVNWVpcll4YUZ0VW96Qm5vM01oN0RGUF8xMjZ8_zfeN1RlmMIoDP6V9RszmlOwtZn3OwCCNgjTjO4wE88=;csrf_token_308f747c083a9186054ac556e82c244ceb52f8a0e6159140ddb89100318a5e54=lq4sSeHxUIl9gpC8wT9tNwoAvi0jrumMDZeSkB/OU7A=; Path=/; Max-Age=31536000; HttpOnly; Secure; SameSite=Strict' \
--data '{
"csrf_token": "{{recoveryFlowCsrf}}",
"method": "password",
"password": "123SupperPassword2025$"
}'
I get error
{
"error": {
"code": 400,
"status": "Bad Request",
"request": "9b7fc1550022bdf333b0a27e4401ee8b",
"reason": "The flow query parameter is missing or malformed.",
"message": "The request was malformed or contained invalid parameters"
}
}
brief-egg-61061
06/04/2025, 9:17 AMbrief-egg-61061
06/04/2025, 9:17 AM"The flow query parameter is missing or malformed."
means that the flow
query parameter is either not present or not correctly formatted in your request URL. What’s wrong? Your request URL is: '{{host}}/self-service/settings?flow=2a2a701a-7a45-4df1-a710-816cc4f9efc'
This is correct in structure, but make sure: - The flow
parameter is present and contains a valid flow ID. - The flow ID is not expired or invalid. - The URL is not being altered by your shell or environment (e.g., extra spaces, wrong variable interpolation). Checklist: 1. Double-check that {{host}}
is replaced with your actual host (e.g., `http://127.0.0.1:4455`). 2. Ensure the flow ID (2a2a701a-7a45-4df1-a710-816cc4f9efc
) is valid and not expired. 3. The request must be a POST
to /self-service/settings?flow=<flow-id>
with the correct flow ID as a query parameter. Example (with placeholders replaced): bash curl --request POST \ --url '<http://127.0.0.1:4455/self-service/settings?flow=2a2a701a-7a45-4df1-a710-816cc4f9efc>' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --cookie 'ory_kratos_session=...;csrf_token_...=...' \ --data '{ "csrf_token": "{{recoveryFlowCsrf}}", "method": "password", "password": "123SupperPassword2025$" }'
If you still get this error: - The flow may have expired. You need to start a new settings flow and use the new flow ID [[updateSettingsFlow](https://www.ory.sh/docs/kratos/reference/api)]. - Make sure you are not missing the flow
parameter or using an incorrect one. Summary: This error is caused by a missing or invalid flow
query parameter. Always ensure you use a valid, non-expired flow ID in your request URL as shown in the documentation [[updateSettingsFlow](https://www.ory.sh/docs/kratos/reference/api)].