Kratos generates broken redirects to AAL2 login flows if identity has both SMS and another 2FA method
MichaelMarner opened this issue · comments
Preflight checklist
- I could not find a solution in the existing issues, docs, nor discussions.
- I agree to follow this project's Code of Conduct.
- I have read and am following this repository's Contribution Guidelines.
- I have joined the Ory Community Slack.
- I am signed up to the Ory Security Patch Newsletter.
Ory Network Project
No response
Describe the bug
If an identity is configured for SMS 2FA, and also has another 2FA method configured, such as TOTP, then any redirects to an AAL2 login flow generated by Kratos are broken, as they do not include a via
request parameter.
Reproducing the bug
- Configure an identity schema with a phone verifiable phone number
- Configure Kratos to enable SMS based 2FA
- Configure Kratos to use
highest_available
on whoami, settings, or other self service flows - Log into Kratos
- In a settings flow, add a phone number to the account, complete the verification process
- In a settings flow, add TOTP to the account
- Log out
- Attempt to log in with email/password
At this point, Kratos will redirect the client:
{
"error": {
"id": "browser_location_change_required",
"code": 422,
"status": "Unprocessable Entity",
"reason": "In order to complete this flow please redirect the browser to: http://127.0.0.1:4433/self-service/login/browser?aal=aal2",
"message": "browser location change required"
},
"redirect_browser_to": "http://127.0.0.1:4433/self-service/login/browser?aal=aal2"
}
However, navigating to the URL provided will result in an error screen, with the following error:
{
"id": "ff1cb352-2137-40e9-8eb5-04f4c74ffdd1",
"error": {
"code": 400,
"reason": "AAL2 login via code requires the `via` query parameter",
"status": "Bad Request",
"message": "The request was malformed or contained invalid parameters"
},
"created_at": "2024-03-07T01:53:18.011166Z",
"updated_at": "2024-03-07T01:53:18.011166Z"
}
Note: I've focused on the login redirect here, but equivalent broken redirects are generated when making other calls, such as to whoami.
Relevant log output
No response
Relevant configuration
Kratos.yml:
version: 1.1.0
session:
whoami:
required_aal: highest_available
methods:
password:
enabled: true
totp:
config:
issuer: My Cool Business
enabled: true
lookup_secret:
enabled: true
code:
enabled: true
mfa_enabled: true
Identity Schema:
{
"$id": "https://schemas.ory.sh/presets/kratos/quickstart/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": 3,
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
}
},
"verification": {
"via": "email"
},
"recovery": {
"via": "email"
}
}
},
"phone": {
"title": "Phone Number",
"type": "string",
"format": "tel",
"ory.sh/kratos": {
"credentials": {
"password": {
"identifier": true
}
},
"verification": {
"via": "sms"
}
}
},
"name": {
"type": "object",
"properties": {
"first": {
"title": "First Name",
"type": "string"
},
"last": {
"title": "Last Name",
"type": "string"
}
}
}
},
"required": ["email"],
"additionalProperties": false
}
}
}
Version
1.1.0
On which operating system are you observing this issue?
macOS
In which environment are you deploying?
Docker
Additional Context
It feels like the via=
request parameter isn't really the right approach to start an AAL2 login flow - it requires the client to know too much about how Kratos is configured, and requires the client to have information about the identity that is not possible to know (ie what 2FA approaches are enabled on the account). It makes the client very brittle and at risk of breaking if any Kratos configuration changes.
I think Kratos needs another step to the login flow that generates a UI presenting all the ways the user can complete AAL2 authentication, allowing the user to select "use Authenticator app" or "send an SMS". Kratos could be configured to have a default or preferred option.
This matches what other services tend to do. For example Github I have TOTP and phone number configured. When I login, Github asked for my TOTP code by default, but also gives me the option to authenticate with an SMS or recovery code.