fix(login v1): handle automatic re-auth using id_token_hint properly (#11326)

# Which Problems Are Solved

A customer reported that when the session in console expires and the
user is prompted to re-authenticate, users get a "mfa required" error
after the re-authentication, resp. after a redirect to the login.
Because of the login policy settings, they're not required to actively
re-authenticate, but are automatically signed-in again and then get the
error.

It was discovered, that the problem is due to the login v1 loading the
wrong login policy (from the default org or instance default) instead of
the user's organization. If there are differences in the allowed second
factors, e.g. if the user's organization allows OTP Email, but the
default policy doesn't allow that and neither policy enforces MFA, then
the login will not check for 2FA/MFA. The then created new OIDC session
/ tokens won't contain any MFA information, which results in the
described error.

# How the Problems Are Solved

When creating the auth request internally, we now check for a userID set
by the id_token_hint. In case it is set, the corresponding user will be
loaded already and the request will be aggregated with their information
incl. the organization id.
A `selectUser` function has been added for this and the existing
`SelectUser` used in the account selection page has been updated to use
the new function.

# Additional Changes

None

# Additional Context

- reported through support
- requires backport to v4.x and v3.x

Co-authored-by: Silvan <[email protected]>
This commit is contained in:
Livio Spring
2026-01-12 06:44:49 +00:00
committed by GitHub
co-authored by Silvan
parent 4b6add514f
commit 512a4199c9
@@ -166,6 +166,11 @@ func (repo *AuthRequestRepo) CreateAuthRequest(ctx context.Context, request *dom
if err := setOrgID(ctx, repo.OrgViewProvider, request); err != nil {
return nil, err
}
if request.UserID != "" && request.UserOrgID == "" {
if err := repo.selectUser(ctx, request, request.UserID); err != nil {
return nil, err
}
}
if request.LoginHint != "" {
err = repo.checkLoginName(ctx, request, request.LoginHint)
logging.WithFields("login name", request.LoginHint, "id", request.ID, "applicationID", request.ApplicationID, "traceID", tracing.TraceIDFromCtx(ctx)).OnError(err).Info("login hint invalid")
@@ -350,6 +355,13 @@ func (repo *AuthRequestRepo) SelectUser(ctx context.Context, authReqID, userID,
return zerrors.ThrowNotFound(nil, "AUTH-2d3f4", "Errors.UserSession.NotFound")
}
}
if err := repo.selectUser(ctx, request, userID); err != nil {
return err
}
return repo.AuthRequests.UpdateAuthRequest(ctx, request)
}
func (repo *AuthRequestRepo) selectUser(ctx context.Context, request *domain.AuthRequest, userID string) error {
user, err := activeUserByID(ctx, repo.UserViewProvider, repo.UserEventProvider, repo.OrgViewProvider, repo.LockoutPolicyViewProvider, userID, false)
if err != nil {
return err
@@ -362,7 +374,7 @@ func (repo *AuthRequestRepo) SelectUser(ctx context.Context, authReqID, userID,
username = user.PreferredLoginName
}
request.SetUserInfo(user.ID, username, user.PreferredLoginName, user.DisplayName, user.AvatarKey, user.ResourceOwner)
return repo.AuthRequests.UpdateAuthRequest(ctx, request)
return nil
}
func (repo *AuthRequestRepo) VerifyPassword(ctx context.Context, authReqID, userID, resourceOwner, password, userAgentID string, info *domain.BrowserInfo) (err error) {