import { describe, expect, it } from "vitest"; import { SignJWT, generateKeyPair } from "jose"; import { makeVerifier } from "../server/utils/auth"; const ISS = "https://auth.kuns.dev"; async function setup() { const { publicKey, privateKey } = await generateKeyPair("RS256"); const verify = makeVerifier({ issuer: ISS, audiences: ["aud-web", "proj-1"], allowedSubs: ["owner-1"], keyResolver: async () => publicKey, }); const sign = (claims: Record) => new SignJWT(claims) .setProtectedHeader({ alg: "RS256" }) .setIssuer(ISS) .setIssuedAt() .setExpirationTime("5m") .sign(privateKey); return { verify, sign }; } describe("token verification", () => { it("accepts an owner token with a valid audience", async () => { const { verify, sign } = await setup(); const t = await sign({ sub: "owner-1", aud: ["aud-web"] }); await expect(verify(t)).resolves.toMatchObject({ sub: "owner-1" }); }); it("accepts when aud is a single string in the allowed set", async () => { const { verify, sign } = await setup(); const t = await sign({ sub: "owner-1", aud: "proj-1" }); await expect(verify(t)).resolves.toMatchObject({ sub: "owner-1" }); }); it("rejects a non-owner sub", async () => { const { verify, sign } = await setup(); const t = await sign({ sub: "intruder", aud: ["aud-web"] }); await expect(verify(t)).rejects.toThrow(); }); it("rejects a token with no accepted audience", async () => { const { verify, sign } = await setup(); const t = await sign({ sub: "owner-1", aud: ["other"] }); await expect(verify(t)).rejects.toThrow(); }); it("rejects a wrong issuer", async () => { const { publicKey, privateKey } = await generateKeyPair("RS256"); const verify = makeVerifier({ issuer: ISS, audiences: ["aud-web"], allowedSubs: ["owner-1"], keyResolver: async () => publicKey, }); const t = await new SignJWT({ sub: "owner-1", aud: ["aud-web"] }) .setProtectedHeader({ alg: "RS256" }) .setIssuer("https://evil.example") .setExpirationTime("5m") .sign(privateKey); await expect(verify(t)).rejects.toThrow(); }); });