Closed Urbansson closed 2 years ago
Hello, we've come across something similar when re-directing to the 2FA second stage login flow.
We have some middleware checking if a users session is still valid and if it's not they are re-directed to sign-in with a return_to
query parameter in the URL which we are also passing in when initialising the selfServiceLoginFlow
. If a user has 2FA (totp) set up we handle the error that comes back when they sign in and redirect them to the url in redirect_browser_to
(https://localhost:4433/self-service/login/browser?aal=aal2
).
After the redirect to complete the second stage of login (we get redirected to /sign-in?flow=[FLOW-ID]
, if the method for the first stage of login was oidc
the return_to
is included in the flow and we can access it in the response from kratos.getSelfServiceLoginFlow(this.flowId)
. But if the method for the first stage was email + password and there is no return_to
parameter included in the response from kratos.getSelfServiceLoginFlow(this.flowId)
.
Could this be a similar bug where the return_to
parameter is not being included in the new flow created for the second stage (2FA) of login?
I came across a very similar issue in the recovery flow when using the link strategy. I also found where the error happens, and the redirect_to is dropped, and it's a pattern I've seen all over the code, so it makes sense that it would surface in more places.
So the code literally says "take over return_to parameter", which it kinda does, here:
// Take over 'return_to' parameter from recovery flow
sfRequestURL, err := url.Parse(sf.RequestURL)
if err != nil {
return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err)
}
fRequestURL, err := url.Parse(f.RequestURL)
if err != nil {
return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err)
}
sfQuery := sfRequestURL.Query()
sfQuery.Set("return_to", fRequestURL.Query().Get("return_to"))
sfRequestURL.RawQuery = sfQuery.Encode()
sf.RequestURL = sfRequestURL.String()
However, further down it's dropped again, here:
http.Redirect(w, r, sf.AppendTo(s.d.Config(r.Context()).SelfServiceFlowSettingsUI()).String(), http.StatusSeeOther)
Which can be easily hotpatched like this:
http.Redirect(w, r, urlx.CopyWithQuery(sf.AppendTo(s.d.Config(r.Context()).SelfServiceFlowSettingsUI()), url.Values{"return_to": {sfQuery.Get("return_to")}}).String(), http.StatusSeeOther)
This is a pretty dirty solution though, I think maybe it would be better if the (flowType).AppendTo() actually honored the flows entire query, and not just the flow id. The downside to that solution, is that all other queryparams (like the no longer needed token, in the recovery case) will also be appended.
Would anyone official/from Ory like to chime in?
Preflight checklist
Describe the bug
When logging in for the first time using a OIDC provider the
return_to
parameter provided in the login flow is not used.Reproducing the bug
Create a new login flow:
GET http://127.0.0.1:3000/self-service/login/browser?aal=&refresh=false&return_to=http://127.0.0.1:3000/foo
Then log in using a new OIDC identity.
After completing the login flow you will be redirected to
/
instead ofhttp://127.0.0.1:3000/foo
Relevant log output
No response
Relevant configuration
Version
v0.9.0-alpha.3
On which operating system are you observing this issue?
macOS
In which environment are you deploying?
Kubernetes
Additional Context
The issue is that the NewRegistrationFlow function is called with the request from the OIDC callback request and not the initial login request. That means that all the query parameters provided in the login request including the
return_to
is lost.Replacing the
.RequestURL
in the newly create registration flowwith the one from the login flow solves the problem and honors thereturn_to
.