Files
sage-graphql-mcp/tests/auth.test.ts
2026-03-13 15:00:22 +00:00

96 lines
3.1 KiB
TypeScript

import { describe, it, expect } from "bun:test";
import { generateJWT, getAuthHeaders } from "../src/auth/index.js";
import type { X3Config } from "../src/config.js";
function makeConfig(overrides: Partial<X3Config> = {}): X3Config {
return {
url: "https://example.com/api",
endpoint: "SEED",
clientId: "test-client-id",
secret: "test-secret-key-for-hs256",
user: "TEST_USER",
tokenLifetime: 600,
mode: "authenticated",
tlsRejectUnauthorized: true,
...overrides,
};
}
function decodeJwtPayload(token: string): Record<string, unknown> {
const parts = token.split(".");
const payload = Buffer.from(parts[1], "base64url").toString();
return JSON.parse(payload);
}
describe("generateJWT", () => {
it("produces a token with 3 dot-separated parts", async () => {
const token = await generateJWT(makeConfig());
const parts = token.split(".");
expect(parts).toHaveLength(3);
expect(parts.every((p) => p.length > 0)).toBe(true);
});
it("encodes correct claims in the payload", async () => {
const config = makeConfig({ tokenLifetime: 900 });
const beforeTime = Math.floor(Date.now() / 1000) - 30;
const token = await generateJWT(config);
const afterTime = Math.floor(Date.now() / 1000) - 30;
const claims = decodeJwtPayload(token);
expect(claims.iss).toBe("test-client-id");
expect(claims.sub).toBe("TEST_USER");
expect(claims.aud).toBe("");
const iat = claims.iat as number;
expect(iat).toBeGreaterThanOrEqual(beforeTime);
expect(iat).toBeLessThanOrEqual(afterTime);
expect(claims.exp).toBe(iat + 900);
});
it("throws when clientId is missing", async () => {
expect(generateJWT(makeConfig({ clientId: undefined }))).rejects.toThrow(
"clientId, secret, and user are required",
);
});
it("throws when secret is missing", async () => {
expect(generateJWT(makeConfig({ secret: undefined }))).rejects.toThrow(
"clientId, secret, and user are required",
);
});
it("throws when user is missing", async () => {
expect(generateJWT(makeConfig({ user: undefined }))).rejects.toThrow(
"clientId, secret, and user are required",
);
});
});
describe("getAuthHeaders", () => {
it("returns only Content-Type in sandbox mode", async () => {
const headers = await getAuthHeaders(makeConfig({ mode: "sandbox" }));
expect(headers["Content-Type"]).toBe("application/json");
expect(headers["Authorization"]).toBeUndefined();
expect(headers["x-xtrem-endpoint"]).toBeUndefined();
});
it("returns Authorization and x-xtrem-endpoint in authenticated mode", async () => {
const headers = await getAuthHeaders(makeConfig());
expect(headers["Content-Type"]).toBe("application/json");
expect(headers["Authorization"]).toStartWith("Bearer ");
expect(headers["x-xtrem-endpoint"]).toBe("SEED");
});
it("sets x-xtrem-endpoint to empty string when endpoint is undefined", async () => {
const headers = await getAuthHeaders(
makeConfig({ endpoint: undefined }),
);
expect(headers["x-xtrem-endpoint"]).toBe("");
});
});