Repository navigation
Conversation
…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>
Contributor
There was a problem hiding this comment.
🟢 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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #54943
The new
createLoginForm(AuthenticationFlowContext, LoginFormsProvider)defaults tocreateLoginForm(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 whatOrganizationAuthenticatoralready does for its own callback.The override in
IdpUsernamePasswordFormdoes not callsetupForm: itssetInfowould replace the passkey error message, and the passkey data is already on the form at that point.setDuplicateUserChallengestill renderscreateLoginUsernamePassword()directly. Routing it through the new method would change other pages, for example the one ofUsernameForm, so I left it for a separate issue.Testing
PasskeysIdpUsernamePasswordFormTestfails 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.PasskeysUsernamePasswordFormTestpasses 8/8 with the fix, and Spotless passes.AI agent usage
The analysis, the fix and the test were done with an AI agent (Claude Code) and verified as described above.