diff --git a/src/utils/verifyAuthToken.ts b/src/utils/verifyAuthToken.ts index 52c64f01..859b587e 100644 --- a/src/utils/verifyAuthToken.ts +++ b/src/utils/verifyAuthToken.ts @@ -24,3 +24,25 @@ export async function verifyAuthToken(authHeader: string, env: env) { throw new Error(AUTHENTICATION_ERROR); } } + +/** + * + * @param authHeader { string } : the auth header of request + * @param env { env }: the ctx (context) which contains the secrets put in as wrangler secrets. + */ +export async function verifyCronJobsToken(authHeader: string, env: env) { + if (!authHeader) { + throw new Error(INVALID_TOKEN_FORMAT); + } + const authHeaderParts = authHeader.split(" "); + if (authHeaderParts.length !== 2 || authHeaderParts[0] !== "Bearer") { + throw new Error(INVALID_TOKEN_FORMAT); + } + const authToken = authHeaderParts[1]; + const isValid = await jwt.verify(authToken, env.CRON_JOBS_PUBLIC_KEY, { + algorithm: "RS256", + }); + if (!isValid) { + throw new Error(AUTHENTICATION_ERROR); + } +} diff --git a/tests/unit/utils/verifyToken.test.ts b/tests/unit/utils/verifyToken.test.ts index 2c3c63f5..c533b268 100644 --- a/tests/unit/utils/verifyToken.test.ts +++ b/tests/unit/utils/verifyToken.test.ts @@ -1,5 +1,8 @@ import jwt from "@tsndr/cloudflare-worker-jwt"; -import { verifyAuthToken } from "../../../src/utils/verifyAuthToken"; +import { + verifyAuthToken, + verifyCronJobsToken, +} from "../../../src/utils/verifyAuthToken"; import { AUTHENTICATION_ERROR, INVALID_TOKEN_FORMAT, @@ -45,3 +48,46 @@ describe("verifyAuthToken", () => { ); }); }); + +describe("verifyCronJobsToken", () => { + const authToken = "validToken"; + const mockEnv = { CRON_JOBS_PUBLIC_KEY: "publicKey" }; + + afterEach(() => { + jest.clearAllMocks(); + }); + + it("should verify a valid token successfully", async () => { + jwt.verify = jest.fn().mockResolvedValue(true); + const authHeader = `Bearer ${authToken}`; + await expect( + verifyCronJobsToken(authHeader, mockEnv) + ).resolves.not.toThrow(); + expect(jwt.verify).toHaveBeenCalledWith( + authToken, + mockEnv.CRON_JOBS_PUBLIC_KEY, + { algorithm: "RS256" } + ); + }); + + it("should throw an error for an invalid token", async () => { + const authHeader = "Bearer invalidToken"; + jwt.verify = jest.fn().mockResolvedValue(false); + await expect(verifyCronJobsToken(authHeader, mockEnv)).rejects.toThrow( + AUTHENTICATION_ERROR + ); + }); + it("should throw an error when Bearer is not passed", async () => { + const authHeader = "Beaer invalidToken"; + await expect(verifyCronJobsToken(authHeader, mockEnv)).rejects.toThrow( + INVALID_TOKEN_FORMAT + ); + }); + + it("should throw an error for a malformed auth header", async () => { + const malformedHeader = "invalidformat"; + await expect(verifyCronJobsToken(malformedHeader, mockEnv)).rejects.toThrow( + INVALID_TOKEN_FORMAT + ); + }); +});