Files
outline/plugins/slack/server/auth/slack.test.ts
T
Tom Moor f50bb00b29 Refactor of OAuth account linking flows (#12246)
* Refactor of OAuth account linking flows

* PR feedback
2026-05-02 18:54:38 -04:00

87 lines
2.8 KiB
TypeScript

import { IntegrationType } from "@shared/types";
import { buildUser } from "@server/test/factories";
import { getTestServer } from "@server/test/support";
import { parseEmail } from "@shared/utils/email";
const server = getTestServer();
describe("#slack.post", () => {
it("should fail with status 400 bad request if query param state is not valid", async () => {
const user = await buildUser();
const res = await server.get(
`/auth/slack.post?state=${JSON.stringify(
{}
)}&code=123&token=${user.getJwtToken()}`
);
expect(res.status).toEqual(400);
});
it("should fail with status 400 bad request if query param state is not JSON", async () => {
const user = await buildUser();
const res = await server.get(
`/auth/slack.post?state=bad&code=123&token=${user.getJwtToken()}`
);
expect(res.status).toEqual(400);
});
it("should fail with status 400 bad request when both code and error are missing in query params", async () => {
const res = await server.get(
"/auth/slack.post?state=182d14d5-0dbd-4521-ac52-25484c25c96e"
);
const body = await res.json();
expect(res.status).toEqual(400);
expect(body.message).toEqual("query: one of code or error is required");
});
it("should reject callback when state nonce does not match cookie", async () => {
const user = await buildUser();
const state = JSON.stringify({
type: IntegrationType.LinkedAccount,
teamId: user.teamId,
nonce: "attacker-nonce",
});
const res = await server.get(
`/auth/slack.post?state=${encodeURIComponent(
state
)}&code=123&token=${user.getJwtToken()}`,
{ redirect: "manual" }
);
const body = await res.json();
expect(res.status).toEqual(400);
expect(body.error).toEqual("state_mismatch");
});
it("should reject callback when nonce is missing from state", async () => {
const user = await buildUser();
const state = JSON.stringify({
type: IntegrationType.LinkedAccount,
teamId: user.teamId,
});
const res = await server.get(
`/auth/slack.post?state=${encodeURIComponent(
state
)}&code=123&token=${user.getJwtToken()}`,
{ redirect: "manual" }
);
expect(res.status).toEqual(400);
});
});
describe("Slack authentication domain extraction", () => {
it("should correctly extract domain from user email", () => {
const testCases = [
{ email: "user@gmail.com", expectedDomain: "gmail.com" },
{ email: "test@company.com", expectedDomain: "company.com" },
{
email: "admin@subdomain.domain.com",
expectedDomain: "subdomain.domain.com",
},
];
testCases.forEach(({ email, expectedDomain }) => {
const { domain } = parseEmail(email);
expect(domain).toEqual(expectedDomain);
});
});
});