-
Notifications
You must be signed in to change notification settings - Fork 7
Description
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
dazzling-curran-48eql75kst
Describe your problem
This feature request originates from Ory Community Slack discussion.
We're using Ory Network to authenticate into the system via OAuth2/OIDC. We have a requirement from InfoSec department to require 2FA assurance level for login. As of 2025-08 this does not seem to be possible with Ory Network (Hydra+Kratos).
Currently Ory Network, as described in Step-up authentication doc, allows setting required AAL for all login scenarios except for the self-service settings (which has a dedicated config). The choice, however, is limited to "single factor" (aal2 in Kratos terms) and "2FA if a user has configured it" (highest_available). In other words, it's impossible to require 2FA and reject the users that do not have it configured.
It's worth mentioning that it's possible to create a login flow that requires 2FA directly in Kratos's /self-service/login/browser API (doc), and using aal=aal2 query parameter to require the 2FA. However, this has two blockers:
- we do not work directly with Kratos, but rather with Hydra (
/oauth2/auth) which initialises the login flow under the hood. - we can't move the control over adding AAL2 requirement to the frontend side, because it can be easily bypassed by a malicious actor.
Describe your ideal solution
As a minimum, we would like to specify required_aal=aal2 for every login flow in the project (except for the settings, obviously).
For more flexibility, it might be useful to allow configuring required_aal=aal1 | highest_available | aal2 individually per an OAuth2 client. This is inspired by Okta's authentication policies.
Workarounds or alternatives
We have identified two possible "workarounds":
Login webhooks
We can add an interrupting login webhook for password flow that would:
- react only to flows with OAuth2 challenge (to not affect the settings access) by looking at
std.objectHas(ctx.flow, 'oauth2_login_challenge') - fetch the user identity with credentials for
ctx.identity.idusing Ory admin API - check the credentials against the factors that are currently allowed (either taken from the project settings or hard-coded)
- interrupt the flow if the identity has only password factor active
Needless to say, it's a very convoluted hook, and the resulting UX is quite bad, because all we can do here is to show "Please add the second factor" message on the login form.
Validate Ory-specific traits in OIDC callback
During the callback, where we establish a user session on our side, we call /userinfo to resolve the requested claims. In a reply from Ory we see "amr":["password"] or "amr":["password","totp"], depending on the factors used. We can check that list to reject single-factor sessions.
The downside here is that we would have to add an Ory-specific code for otherwise generic logic, but at least it's not as convoluted as the webhook option above.
Version
Ory Network (as of 2025-08-13)
Additional Context
No response