Skip to content

Commit 7d09d30

Browse files
Adds a function to verify cron jobs auth token (#181)
* feat: adds new function to verify cron jobs auth token * chore: renames key names * feat: adds null check
1 parent 1d253c5 commit 7d09d30

File tree

2 files changed

+69
-1
lines changed

2 files changed

+69
-1
lines changed

src/utils/verifyAuthToken.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,25 @@ export async function verifyAuthToken(authHeader: string, env: env) {
2424
throw new Error(AUTHENTICATION_ERROR);
2525
}
2626
}
27+
28+
/**
29+
*
30+
* @param authHeader { string } : the auth header of request
31+
* @param env { env }: the ctx (context) which contains the secrets put in as wrangler secrets.
32+
*/
33+
export async function verifyCronJobsToken(authHeader: string, env: env) {
34+
if (!authHeader) {
35+
throw new Error(INVALID_TOKEN_FORMAT);
36+
}
37+
const authHeaderParts = authHeader.split(" ");
38+
if (authHeaderParts.length !== 2 || authHeaderParts[0] !== "Bearer") {
39+
throw new Error(INVALID_TOKEN_FORMAT);
40+
}
41+
const authToken = authHeaderParts[1];
42+
const isValid = await jwt.verify(authToken, env.CRON_JOBS_PUBLIC_KEY, {
43+
algorithm: "RS256",
44+
});
45+
if (!isValid) {
46+
throw new Error(AUTHENTICATION_ERROR);
47+
}
48+
}

tests/unit/utils/verifyToken.test.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import jwt from "@tsndr/cloudflare-worker-jwt";
2-
import { verifyAuthToken } from "../../../src/utils/verifyAuthToken";
2+
import {
3+
verifyAuthToken,
4+
verifyCronJobsToken,
5+
} from "../../../src/utils/verifyAuthToken";
36
import {
47
AUTHENTICATION_ERROR,
58
INVALID_TOKEN_FORMAT,
@@ -45,3 +48,46 @@ describe("verifyAuthToken", () => {
4548
);
4649
});
4750
});
51+
52+
describe("verifyCronJobsToken", () => {
53+
const authToken = "validToken";
54+
const mockEnv = { CRON_JOBS_PUBLIC_KEY: "publicKey" };
55+
56+
afterEach(() => {
57+
jest.clearAllMocks();
58+
});
59+
60+
it("should verify a valid token successfully", async () => {
61+
jwt.verify = jest.fn().mockResolvedValue(true);
62+
const authHeader = `Bearer ${authToken}`;
63+
await expect(
64+
verifyCronJobsToken(authHeader, mockEnv)
65+
).resolves.not.toThrow();
66+
expect(jwt.verify).toHaveBeenCalledWith(
67+
authToken,
68+
mockEnv.CRON_JOBS_PUBLIC_KEY,
69+
{ algorithm: "RS256" }
70+
);
71+
});
72+
73+
it("should throw an error for an invalid token", async () => {
74+
const authHeader = "Bearer invalidToken";
75+
jwt.verify = jest.fn().mockResolvedValue(false);
76+
await expect(verifyCronJobsToken(authHeader, mockEnv)).rejects.toThrow(
77+
AUTHENTICATION_ERROR
78+
);
79+
});
80+
it("should throw an error when Bearer is not passed", async () => {
81+
const authHeader = "Beaer invalidToken";
82+
await expect(verifyCronJobsToken(authHeader, mockEnv)).rejects.toThrow(
83+
INVALID_TOKEN_FORMAT
84+
);
85+
});
86+
87+
it("should throw an error for a malformed auth header", async () => {
88+
const malformedHeader = "invalidformat";
89+
await expect(verifyCronJobsToken(malformedHeader, mockEnv)).rejects.toThrow(
90+
INVALID_TOKEN_FORMAT
91+
);
92+
});
93+
});

0 commit comments

Comments
 (0)