fix(oauth-provider): improve allowed paths for oauth_query for client plugin (#8320)

This commit is contained in:
Dylan Vanmali
2026-03-18 09:55:12 -07:00
committed by GitHub
parent 40b5e23b3b
commit 40e7676155
2 changed files with 90 additions and 28 deletions

View File

@@ -33,24 +33,14 @@ export const oauthProviderClient = () => {
: safeJSONParse<Record<string, unknown>>(ctx.body ?? "{}") : safeJSONParse<Record<string, unknown>>(ctx.body ?? "{}")
: ctx.body; : ctx.body;
if (body?.oauth_query) return; if (body?.oauth_query) return;
const pathname =
typeof ctx.url === "string"
? new URL(ctx.url).pathname
: ctx.url.pathname;
// Should only need to run for /sign-in/email, /sign-in/social, /sign-in/oauth2, /oauth2/consent, /oauth2/continue
if ( if (
pathname.endsWith("/sign-in/email") || typeof window !== "undefined" &&
pathname.endsWith("/sign-in/social") || window?.location?.search &&
pathname.endsWith("/sign-in/oauth2") || !(ctx.method === "GET" || ctx.method === "DELETE")
pathname.endsWith("/oauth2/consent") ||
pathname.endsWith("/oauth2/continue")
) { ) {
ctx.body = JSON.stringify({ ctx.body = JSON.stringify({
...body, ...body,
oauth_query: oauth_query: parseSignedQuery(window.location.search),
typeof window !== "undefined"
? parseSignedQuery(window?.location?.search)
: undefined,
}); });
} }
}, },

View File

@@ -447,6 +447,7 @@ describe("oauth - prompt", async () => {
const scopes = ["openid", "profile", "email", "offline_access", "read:posts"]; const scopes = ["openid", "profile", "email", "offline_access", "read:posts"];
let enableSelectAccount = false; let enableSelectAccount = false;
let enablePostLogin = false; let enablePostLogin = false;
let selectedPostLogin = false;
let isUserRegistered = true; let isUserRegistered = true;
const { const {
auth: authorizationServer, auth: authorizationServer,
@@ -481,10 +482,12 @@ describe("oauth - prompt", async () => {
page: "/select-organization", page: "/select-organization",
shouldRedirect({ session }) { shouldRedirect({ session }) {
if (!enablePostLogin) return false; if (!enablePostLogin) return false;
if (selectedPostLogin) return false;
return !session?.activeOrganizationId; return !session?.activeOrganizationId;
}, },
consentReferenceId({ session }) { consentReferenceId({ session }) {
if (!enablePostLogin) return undefined; if (!enablePostLogin) return undefined;
if (selectedPostLogin) return undefined;
const activeOrganizationId = (session?.activeOrganizationId ?? const activeOrganizationId = (session?.activeOrganizationId ??
undefined) as string | undefined; undefined) as string | undefined;
if (!activeOrganizationId) if (!activeOrganizationId)
@@ -1426,6 +1429,84 @@ describe("oauth - prompt", async () => {
enableSelectAccount = false; enableSelectAccount = false;
}); });
it("shall allow user to post login via continue", async ({
onTestFinished,
}) => {
if (!oauthClient?.client_id || !oauthClient?.client_secret) {
throw Error("beforeAll not run properly");
}
enablePostLogin = true;
const { customFetchImpl: customFetchImplRP, cookieSetter } =
await createTestInstance();
const client = createAuthClient({
plugins: [genericOAuthClient(), organization()],
baseURL: rpBaseUrl,
fetchOptions: {
customFetchImpl: customFetchImplRP,
},
});
// Generate authorize url
const oauthHeaders = new Headers();
const data = await client.signIn.oauth2(
{
providerId,
callbackURL: "/success",
},
{
headers,
throw: true,
onSuccess: cookieSetter(oauthHeaders),
},
);
expect(data.url).toContain(
`${authServerBaseUrl}/api/auth/oauth2/authorize`,
);
expect(data.url).toContain(`client_id=${oauthClient.client_id}`);
// Check for redirection to /select-organization
let selectOrgRedirectUri = "";
await serverClient.$fetch(data.url, {
method: "GET",
headers,
onError(context) {
selectOrgRedirectUri = context.response.headers.get("Location") || "";
cookieSetter(headers)(context);
},
});
expect(selectOrgRedirectUri).toContain(`/select-organization`);
expect(selectOrgRedirectUri).toContain(
`client_id=${oauthClient.client_id}`,
);
expect(selectOrgRedirectUri).toContain(`scope=`);
expect(selectOrgRedirectUri).toContain(`state=`);
vi.stubGlobal("window", {
location: {
search: new URL(selectOrgRedirectUri, authServerBaseUrl).search,
},
});
onTestFinished(() => {
vi.unstubAllGlobals();
});
selectedPostLogin = true;
const continueRes = await serverClient.oauth2.continue(
{
postLogin: true,
},
{
headers,
throw: true,
onResponse: cookieSetter(headers),
},
);
expect(continueRes.url).toContain(redirectUri);
expect(continueRes.url).toContain(`code=`);
selectedPostLogin = false;
enablePostLogin = false;
});
it("shall allow user to select an organization/team post login and consent", async ({ it("shall allow user to select an organization/team post login and consent", async ({
onTestFinished, onTestFinished,
}) => { }) => {
@@ -1487,6 +1568,7 @@ describe("oauth - prompt", async () => {
vi.unstubAllGlobals(); vi.unstubAllGlobals();
}); });
let consentRedirectUri = "";
// Select Account and continue auth flow // Select Account and continue auth flow
await serverClient.organization.setActive( await serverClient.organization.setActive(
{ {
@@ -1495,22 +1577,12 @@ describe("oauth - prompt", async () => {
}, },
{ {
headers, headers,
throw: true, onResponse(context) {
onResponse: cookieSetter(headers), consentRedirectUri = context.response.headers.get("Location") || "";
cookieSetter(headers)(context);
},
}, },
); );
const selectedAccountRes = await serverClient.oauth2.continue(
{
postLogin: true,
},
{
headers,
throw: true,
onResponse: cookieSetter(headers),
},
);
expect(selectedAccountRes.redirect).toBeTruthy();
const consentRedirectUri = selectedAccountRes?.url;
expect(consentRedirectUri).toContain(`/consent`); expect(consentRedirectUri).toContain(`/consent`);
expect(consentRedirectUri).toContain(`client_id=${oauthClient.client_id}`); expect(consentRedirectUri).toContain(`client_id=${oauthClient.client_id}`);
expect(consentRedirectUri).toContain(`scope=`); expect(consentRedirectUri).toContain(`scope=`);