Skip to content

Commit 2c669b3

Browse files
fix(core): correct status code when returning redirects (#6004)
* fix(core): correctly set status when returning redirect * update tests * forward other headers * update test * remove default 200 status
1 parent 2dea891 commit 2c669b3

File tree

4 files changed

+54
-21
lines changed

4 files changed

+54
-21
lines changed

packages/next-auth/src/core/index.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -271,5 +271,18 @@ export async function AuthHandler(
271271
): Promise<Response> {
272272
const req = await toInternalRequest(request)
273273
const internalResponse = await AuthHandlerInternal({ req, options })
274-
return toResponse(internalResponse)
274+
275+
const response = await toResponse(internalResponse)
276+
277+
// If the request expects a return URL, send it as JSON
278+
// instead of doing an actual redirect.
279+
const redirect = response.headers.get("Location")
280+
if (request.headers.has("X-Auth-Return-Redirect") && redirect) {
281+
response.headers.delete("Location")
282+
response.headers.set("Content-Type", "application/json")
283+
return new Response(JSON.stringify({ url: redirect }), {
284+
headers: response.headers,
285+
})
286+
}
287+
return response
275288
}

packages/next-auth/src/next/index.ts

+2-12
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,9 @@ async function NextAuthHandler(
3434

3535
options.secret ??= options.jwt?.secret ?? process.env.NEXTAUTH_SECRET
3636
const response = await AuthHandler(request, options)
37-
const { status, headers } = response
38-
res.status(status)
3937

40-
setHeaders(headers, res)
41-
42-
// If the request expects a return URL, send it as JSON
43-
// instead of doing an actual redirect.
44-
const redirect = headers.get("Location")
45-
46-
if (req.body?.json === "true" && redirect) {
47-
res.removeHeader("Location")
48-
return res.json({ url: redirect })
49-
}
38+
res.status(response.status)
39+
setHeaders(response.headers, res)
5040

5141
return res.send(await response.text())
5242
}

packages/next-auth/src/react/index.tsx

+3-4
Original file line numberDiff line numberDiff line change
@@ -241,13 +241,13 @@ export async function signIn<
241241
method: "post",
242242
headers: {
243243
"Content-Type": "application/x-www-form-urlencoded",
244+
"X-Auth-Return-Redirect": "1",
244245
},
245246
// @ts-expect-error
246247
body: new URLSearchParams({
247248
...options,
248249
csrfToken: await getCsrfToken(),
249250
callbackUrl,
250-
json: true,
251251
}),
252252
})
253253

@@ -291,12 +291,11 @@ export async function signOut<R extends boolean = true>(
291291
method: "post",
292292
headers: {
293293
"Content-Type": "application/x-www-form-urlencoded",
294+
"X-Auth-Return-Redirect": "1",
294295
},
295-
// @ts-expect-error
296296
body: new URLSearchParams({
297-
csrfToken: await getCsrfToken(),
297+
csrfToken: (await getCsrfToken()) ?? "",
298298
callbackUrl,
299-
json: true,
300299
}),
301300
}
302301
const res = await fetch(`${baseUrl}/signout`, fetchOptions)

packages/next-auth/tests/next.test.ts

+35-4
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,43 @@ it("Redirects if necessary", async () => {
8282
req: {
8383
method: "post",
8484
url: "/api/auth/signin/github",
85-
body: { json: "true" },
8685
},
8786
})
8887
expect(res.status).toBeCalledWith(302)
89-
expect(res.removeHeader).toBeCalledWith("Location")
90-
expect(res.json).toBeCalledWith({
91-
url: "http://localhost/api/auth/signin?csrf=true",
88+
expect(res.setHeader).toBeCalledWith("set-cookie", [
89+
expect.stringMatching(
90+
/next-auth.csrf-token=.*; Path=\/; HttpOnly; SameSite=Lax/
91+
),
92+
`next-auth.callback-url=${encodeURIComponent(
93+
process.env.NEXTAUTH_URL
94+
)}; Path=/; HttpOnly; SameSite=Lax`,
95+
])
96+
expect(res.setHeader).toBeCalledTimes(2)
97+
expect(res.send).toBeCalledWith("")
98+
})
99+
100+
it("Returns redirect if `X-Auth-Return-Redirect` header is present", async () => {
101+
process.env.NEXTAUTH_URL = "http://localhost"
102+
const { res } = await nodeHandler({
103+
req: {
104+
method: "post",
105+
url: "/api/auth/signin/github",
106+
headers: { "X-Auth-Return-Redirect": "1" },
107+
},
92108
})
109+
110+
expect(res.status).toBeCalledWith(200)
111+
expect(res.setHeader).toBeCalledWith("content-type", "application/json")
112+
expect(res.setHeader).toBeCalledWith("set-cookie", [
113+
expect.stringMatching(
114+
/next-auth.csrf-token=.*; Path=\/; HttpOnly; SameSite=Lax/
115+
),
116+
`next-auth.callback-url=${encodeURIComponent(
117+
process.env.NEXTAUTH_URL
118+
)}; Path=/; HttpOnly; SameSite=Lax`,
119+
])
120+
expect(res.setHeader).toBeCalledTimes(2)
121+
expect(res.send).toBeCalledWith(
122+
JSON.stringify({ url: "http://localhost/api/auth/signin?csrf=true" })
123+
)
93124
})

0 commit comments

Comments
 (0)