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

How to set up and validate locally

  1. Enable passkeys and register a passkey for a user.
  2. 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).
  3. On the login form, authenticate using the passkey.
  4. Verify you are returned to the original destination rather than the dashboard.
Edited by Fernando Cardenas

Merge request reports

Loading
Loading