From 4f4fe0ac3025297b17d1036f64b3ab3204d8b5ca Mon Sep 17 00:00:00 2001 From: Jonathan Baldie Date: Mon, 31 Aug 2026 12:24:06 +0100 Subject: [PATCH] fix: make auth Bearer scheme match case-insensitive (RFC 9110) Parses the Authorization header into scheme and token instead of comparing the whole header against a fixed-case literal, so bearer, BEARER, etc. authenticate the same as Bearer. Fixes #66 Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01Q25veeccRvgA5zjp6Fhijq --- src/middleware.ts | 4 +++- tests/handler_test.ts | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/middleware.ts b/src/middleware.ts index 4707118..aea9330 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -12,7 +12,9 @@ export function withAuth(apiToken: string): Middleware { return next(request, info); } const authHeader = request.headers.get("Authorization"); - if (!authHeader || authHeader !== `Bearer ${apiToken}`) { + const [scheme, ...rest] = (authHeader ?? "").split(" "); + const token = rest.join(" "); + if (!scheme || scheme.toLowerCase() !== "bearer" || token !== apiToken) { return new Response("Unauthorized", { status: 401 }); } return next(request, info); diff --git a/tests/handler_test.ts b/tests/handler_test.ts index 043edf7..3476adc 100644 --- a/tests/handler_test.ts +++ b/tests/handler_test.ts @@ -275,6 +275,16 @@ Deno.test("response body: unauthorized returns 'Unauthorized'", async () => { assertEquals(await res.text(), "Unauthorized"); }); +Deno.test("auth: scheme name is case-insensitive per RFC 9110", async () => { + const handler = makeHandler(); + for (const scheme of ["bearer", "BEARER", "BeArEr"]) { + const res = await handler(new Request("http://localhost/queues", { + headers: { "Authorization": `${scheme} ${API_TOKEN}` }, + })); + assertEquals(res.status, 200, `scheme "${scheme}" should authenticate`); + } +}); + Deno.test("response body: rate limited returns 'Too many requests'", async () => { const handler = makeHandler(undefined, undefined, 1); await handler(new Request("http://localhost/length/q", { headers: auth }));