Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ const sha256 = (value: string) => createHash("sha256").update(value).digest();
export const bearerToken = (expected: string) => {
const expectedDigest = sha256(expected);
return (req: Request, res: Response, next: NextFunction) => {
const presented = req.headers.authorization?.match(/^Bearer (.+)$/)?.[1];
// The scheme name is case-insensitive (RFC 9110); the token is not.
const presented = req.headers.authorization?.match(/^Bearer +(.+)$/i)?.[1];
if (!presented || !timingSafeEqual(sha256(presented), expectedDigest)) {
throw new UnauthorizedError("Invalid bearer token");
}
Expand Down
14 changes: 9 additions & 5 deletions test/auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,21 @@ describe("bearerToken", () => {
return { headers: { authorization } } as unknown as Request;
}

it("calls next for the configured token", () => {
const next = vi.fn();
guard(request("Bearer release-sync-secret"), res, next);
expect(next).toHaveBeenCalledOnce();
});
it.each(["Bearer release-sync-secret", "bearer release-sync-secret", "BEARER release-sync-secret"])(
"calls next for %j",
authorization => {
const next = vi.fn();
guard(request(authorization), res, next);
expect(next).toHaveBeenCalledOnce();
},
);

it.each([
["no header", undefined],
["wrong token", "Bearer nope"],
["missing scheme", "release-sync-secret"],
["prefix of the token", "Bearer release-sync"],
["token in a different case", "Bearer RELEASE-SYNC-SECRET"],
])("rejects %s without calling next", (_label, authorization) => {
const next = vi.fn();
expect(() => guard(request(authorization), res, next)).toThrow(UnauthorizedError);
Expand Down
Loading