mirror of
https://github.com/better-auth/better-auth.git
synced 2026-05-25 16:36:34 -05:00
fix(oauth-proxy): return multiple Set-Cookie headers instead of a single comma-separated header (#6039)
This commit is contained in:
@@ -4,7 +4,7 @@ import {
|
||||
createAuthMiddleware,
|
||||
} from "@better-auth/core/api";
|
||||
import { env } from "@better-auth/core/env";
|
||||
import type { EndpointContext } from "better-call";
|
||||
import type { CookieOptions, EndpointContext } from "better-call";
|
||||
import * as z from "zod";
|
||||
import { originCheck } from "../../api";
|
||||
import { parseJSON } from "../../client/parser";
|
||||
@@ -186,12 +186,53 @@ export const oAuthProxy = (opts?: OAuthProxyOptions | undefined) => {
|
||||
filteredAttrs.push("Secure");
|
||||
}
|
||||
|
||||
return filteredAttrs.length > 0
|
||||
? `${name}=${value}; ${filteredAttrs.join("; ")}`
|
||||
: `${name}=${value}`;
|
||||
// Build options
|
||||
const options: CookieOptions = {};
|
||||
for (const attr of filteredAttrs) {
|
||||
const [attrName, attrValue] = attr.split("=");
|
||||
if (!attrName) continue;
|
||||
switch (attrName.toLowerCase()) {
|
||||
case "path":
|
||||
options.path = attrValue;
|
||||
break;
|
||||
case "expires":
|
||||
if (!attrValue) break;
|
||||
options.expires = new Date(attrValue);
|
||||
break;
|
||||
case "samesite":
|
||||
options.sameSite = attrValue as "lax" | "strict" | "none";
|
||||
break;
|
||||
case "httponly":
|
||||
options.httpOnly = true;
|
||||
break;
|
||||
case "max-age":
|
||||
if (!attrValue) break;
|
||||
options.maxAge = parseInt(attrValue, 10);
|
||||
break;
|
||||
case "prefix":
|
||||
if (!attrValue) break;
|
||||
options.prefix = attrValue as "host" | "secure";
|
||||
break;
|
||||
case "partitioned": {
|
||||
options.partitioned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name,
|
||||
value,
|
||||
options,
|
||||
};
|
||||
});
|
||||
|
||||
ctx.setHeader("set-cookie", processedCookies.join(", "));
|
||||
for (const cookie of processedCookies) {
|
||||
// using `ctx.setHeader` overrides previous Set-Cookie headers
|
||||
// so use ctx.setCookie helper instead
|
||||
// https://github.com/Bekacru/better-call/blob/d27ac20e64b329a4851e97adf864098a9bc2a260/src/context.ts#L217
|
||||
ctx.setCookie(cookie.name, cookie.value, cookie.options);
|
||||
}
|
||||
throw ctx.redirect(ctx.query.callbackURL);
|
||||
},
|
||||
),
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { GoogleProfile } from "@better-auth/core/social-providers";
|
||||
import { HttpResponse, http } from "msw";
|
||||
import { setupServer } from "msw/node";
|
||||
import { afterAll, afterEach, beforeAll, describe, expect, it } from "vitest";
|
||||
import { signJWT } from "../../crypto";
|
||||
import { signJWT, symmetricEncrypt } from "../../crypto";
|
||||
import { getTestInstance } from "../../test-utils/test-instance";
|
||||
import { DEFAULT_SECRET } from "../../utils/constants";
|
||||
import { oAuthProxy } from ".";
|
||||
@@ -244,4 +244,53 @@ describe("oauth-proxy", async () => {
|
||||
},
|
||||
});
|
||||
});
|
||||
it("should redirect to proxy url", async () => {
|
||||
const { client, auth } = await getTestInstance({
|
||||
plugins: [
|
||||
oAuthProxy({
|
||||
currentURL: "http://preview-localhost:3000",
|
||||
}),
|
||||
],
|
||||
socialProviders: {
|
||||
google: {
|
||||
clientId: "test",
|
||||
clientSecret: "test",
|
||||
},
|
||||
},
|
||||
});
|
||||
const { secret } = await auth.$context;
|
||||
|
||||
const mockCookies = {
|
||||
sessionid: "abcd1234",
|
||||
state: "statevalue",
|
||||
};
|
||||
const mockCookiesString = Object.entries(mockCookies)
|
||||
.map(([k, v]) => `${k}=${v}`)
|
||||
.join(", ");
|
||||
const cookies = await symmetricEncrypt({
|
||||
key: secret,
|
||||
data: mockCookiesString,
|
||||
});
|
||||
|
||||
await client.$fetch(
|
||||
`/oauth-proxy-callback?callbackURL=%2Fdashboard&cookies=${cookies}`,
|
||||
{
|
||||
onError(context) {
|
||||
const headersList = [...context.response.headers];
|
||||
const parsedCookies: Record<string, string> = {};
|
||||
for (const [key, value] of headersList) {
|
||||
if (key.toLowerCase() === "set-cookie") {
|
||||
const [cookiePair] = value.split(";");
|
||||
if (!cookiePair) continue;
|
||||
const [cookieKey, cookieValue] = cookiePair.split("=");
|
||||
if (cookieKey === undefined || cookieValue === undefined)
|
||||
continue;
|
||||
parsedCookies[cookieKey] = cookieValue;
|
||||
}
|
||||
}
|
||||
expect(mockCookies).toEqual(parsedCookies);
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user