Skip to content

Keep the account-linking page after a passkey error in first broker login - #55077

Open
Yunaido wants to merge 1 commit into
keycloak:mainfrom
Yunaido:keep-account-linking-page-after-passkey-error-54943
Open

Yunaido wants to merge 1 commit into
keycloak:mainfrom
Yunaido:keep-account-linking-page-after-passkey-error-54943

Conversation

@Yunaido

@Yunaido Yunaido commented Nov 12, 2026

Copy link
Copy Markdown

Closes #54943

The new createLoginForm(AuthenticationFlowContext, LoginFormsProvider) defaults to createLoginForm(LoginFormsProvider), so authenticators that only override the old method behave as before and no upgrade note is needed. Handing the context to the passkey error callback follows what OrganizationAuthenticator already does for its own callback.

The override in IdpUsernamePasswordForm does not call setupForm: its setInfo would replace the passkey error message, and the passkey data is already on the form at that point.

setDuplicateUserChallenge still renders createLoginUsernamePassword() directly. Routing it through the new method would change other pages, for example the one of UsernameForm, so I left it for a separate issue.

Testing

  • PasskeysIdpUsernamePasswordFormTest fails without the fix (expected: <userwebauthn> but was: <>, register link present) and passes with it (5 runs). I ran it with the published 26.8.2 test framework against the 26.8.2 distribution (chrome-headless); the changed files are identical on 26.8.2 and main. PasskeysUsernamePasswordFormTest passes 8/8 with the fix, and Spotless passes.
  • I could not run it on a full main build locally.
  • I also reproduced the bug on an unmodified 26.8.2 server (two realms, OIDC brokering) and verified the fix there.

AI agent usage
The analysis, the fix and the test were done with an AI agent (Claude Code) and verified as described above.

…ogin

The re-authentication page of the first broker login flow
(IdpUsernamePasswordForm) builds its page in setupForm(), which needs
the flow context. UsernamePasswordForm renders passkey errors through
createLoginForm(LoginFormsProvider), which gets no context, so after a
failed passkey sign-in the page lost the existing user's username and
showed the registration link.

Add createLoginForm(AuthenticationFlowContext, LoginFormsProvider),
which defaults to createLoginForm(LoginFormsProvider), and use it for
the passkey error page and in challenge(). IdpUsernamePasswordForm
overrides it to keep the username and the disabled registration.

Closes keycloak#54943

Signed-off-by: Christopher-Jannik Mauthe <33319800+Yunaido@users.noreply.github.com>
@Yunaido
Yunaido marked this pull request as ready for review November 12, 2026 08:28
@Yunaido
Yunaido requested a review from a team as a code owner November 12, 2026 08:28
Copilot AI balanced review requested due to automatic review settings November 12, 2026 08:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues are reported for the fix that preserves account-linking state after a passkey error.

No open issues 🎉

What changed in this PR

Fixes #54943 by preserving the account-linking page after a passkey error during first broker login, keeping the existing username prefilled and registration hidden.

Changes:

  • Adds a context-aware login-form hook that defaults to the existing hook.
  • Routes passkey errors through the new hook and restores account-linking form state without replacing the error message.
  • Adds a regression test covering the error page and subsequent password-based linking.
File Description
tests/​webauthn/​src/​test/​java/​org/​keycloak/​tests/​webauthn/​passwordless/​PasskeysIdpUsernamePasswordFormTest.java Tests preserved linking-page state and successful password fallback after a passkey error.
services/​src/​main/​java/​org/​keycloak/​authentication/​authenticators/​browser/​UsernamePasswordForm.java Passes flow context to the passkey-error rendering callback.
services/​src/​main/​java/​org/​keycloak/​authentication/​authenticators/​browser/​AbstractUsernameFormAuthenticator.java Adds the context-aware rendering hook while retaining legacy delegation.
services/​src/​main/​java/​org/​keycloak/​authentication/​authenticators/​broker/​IdpUsernamePasswordForm.java Preserves the existing username and hides registration when rendering errors.

Review effort: Balanced

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Passkey error on the first broker login re-authentication page drops the prefilled username and shows the registration link

2 participants