Fix passkey sign-in ignoring stored redirect location
Fix passkey sign-in ignoring stored return location Description:
What does this MR do and why?
The passwordless passkey sign-in success handler used
root_path || stored_redirect_uri. Because root_path always returns a
non-nil string (/), the expression always evaluated to root_path, so
the stored return location was silently discarded.
As a result, a user who signed in with a passkey was always dropped at the dashboard instead of being sent back to where they were headed:
- an OAuth authorization request (they never reached the callback) — #594614 (closed)
- any protected page they were redirected to the login form from — #602954 (closed)
The standard username/password flow works because Devise redirects
through after_sign_in_path_for, which resolves both the :redirect
scope (set by SessionsController#store_redirect_uri, gated by
host_allowed?) and the :user scope (user_return_to, set by Devise's
failure app for protected pages and OAuth), falling back to root_path.
This MR makes the passkey success handler delegate to
after_sign_in_path_for(user), so it behaves identically to password
sign-in. Redirect safety is inherited from that shared method: the
:redirect scope is host-gated at write time and the :user scope only
ever holds internal request paths.
References
- Resolves #594614 (closed)
- Resolves #602954 (closed)
How to set up and validate locally
- Enable passkeys and register a passkey for a user.
- While logged out, either:
- open an OAuth authorization URL (
/oauth/authorize?...) for an application using GitLab as an IdP, or - navigate directly to a protected page (e.g. a project).
- open an OAuth authorization URL (
- On the login form, authenticate using the passkey.
- Verify you are returned to the original destination rather than the dashboard.