Skip to content

Commit e7d8bd1

Browse files
aeneasrory-bot
authored andcommitted
fix: resolve null response in OAuth2 flow with existing session
GitOrigin-RevId: 54adcc002fa545e2eb4abf1ef819d9e08089a279
1 parent 8b52ac9 commit e7d8bd1

2 files changed

Lines changed: 31 additions & 11 deletions

File tree

selfservice/flow/login/handler.go

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package login
55

66
import (
77
"net/http"
8-
"net/url"
98
"strconv"
109
"time"
1110

@@ -599,23 +598,18 @@ func (h *Handler) createBrowserLoginFlow(w http.ResponseWriter, r *http.Request)
599598
return
600599
}
601600

602-
rt, err := h.d.Hydra().AcceptLoginRequest(ctx,
601+
rt, hydraErr := h.d.Hydra().AcceptLoginRequest(ctx,
603602
hydra.AcceptLoginRequestParams{
604603
LoginChallenge: string(hydraLoginChallenge),
605604
IdentityID: sess.IdentityID.String(),
606605
SessionID: sess.ID.String(),
607606
AuthenticationMethods: sess.AMR,
608607
})
609-
if err != nil {
610-
h.d.SelfServiceErrorManager().Forward(ctx, w, r, err)
611-
return
612-
}
613-
returnTo, err := url.Parse(rt)
614-
if err != nil {
615-
h.d.SelfServiceErrorManager().Forward(ctx, w, r, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unable to parse URL: %s", rt)))
608+
if hydraErr != nil {
609+
h.d.SelfServiceErrorManager().Forward(ctx, w, r, hydraErr)
616610
return
617611
}
618-
x.SendFlowCompletedAsRedirectOrJSON(w, r, h.d.Writer(), err, returnTo.String())
612+
x.SendFlowCompletedAsRedirectOrJSON(w, r, h.d.Writer(), err, rt)
619613
return
620614
}
621615

selfservice/flow/login/handler_test.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ func init() {
5050
func TestFlowLifecycle(t *testing.T) {
5151
ctx := context.Background()
5252
conf, reg := internal.NewFastRegistryWithMocks(t)
53-
reg.SetHydra(hydra.NewFake())
53+
fakeHydra := hydra.NewFake()
54+
reg.SetHydra(fakeHydra)
5455

5556
routerPublic := httprouterx.NewTestRouterPublic(t)
5657
ts, _ := testhelpers.NewKratosServerWithRouters(t, reg, routerPublic, httprouterx.NewTestRouterAdminWithPrefix(t))
@@ -837,6 +838,31 @@ func TestFlowLifecycle(t *testing.T) {
837838

838839
assert.NotEmpty(t, gjson.GetBytes(body, "oauth2_login_request").Value(), "%s", body)
839840
})
841+
842+
t.Run("case=oauth2 flow with existing session and JSON request should not return null", func(t *testing.T) {
843+
// This test reproduces issue #10255 where the /self-service/login/browser endpoint
844+
// returns null when called with an existing session, a Hydra login challenge, and
845+
// an Accept: application/json header.
846+
847+
// Has a side effect on this test suite but since its running serial and there is no significantly easier way it's acceptable.
848+
fakeHydra.Skip = true
849+
t.Cleanup(func() {
850+
fakeHydra.Skip = false
851+
})
852+
853+
// Make a login request with an authenticated session, Hydra login challenge, and JSON accept
854+
req := testhelpers.NewTestHTTPRequest(t, "GET", ts.URL+login.RouteInitBrowserFlow+"?login_challenge="+hydra.FakeValidLoginChallenge, nil)
855+
req.Header.Set("Accept", "application/json")
856+
body, res := testhelpers.MockMakeAuthenticatedRequest(t, reg, conf, routerPublic, req)
857+
858+
// Before the fix, this would return 200 OK with "null" as body because of variable shadowing
859+
// After the fix, it should return a proper error response with ErrAlreadyLoggedIn
860+
assert.Equal(t, http.StatusBadRequest, res.StatusCode, "Response should be 400 Bad Request, got body: %s", body)
861+
assert.NotEqual(t, "null", string(body), "Response should not be null")
862+
assert.NotEmpty(t, gjson.GetBytes(body, "error.id").String(), "Should have error.id field, got body: %s", body)
863+
assert.Equal(t, "session_already_available", gjson.GetBytes(body, "error.id").String(), "Should return session_already_available error, got body: %s", body)
864+
assert.Contains(t, gjson.GetBytes(body, "error.reason").String(), "A valid session was detected", "Should have proper error reason, got body: %s", body)
865+
})
840866
})
841867

842868
t.Run("case=relative redirect when self-service login ui is a relative URL", func(t *testing.T) {

0 commit comments

Comments
 (0)