fix(api): accept the Bearer scheme in any casing - #84
Merged
ralyodio merged 1 commit intoJul 30, 2026
Merged
Conversation
RFC 7235 section 2.1 makes the Authorization auth-scheme name case-insensitive, but bearer() matched the literal string "Bearer ". A client sending `authorization: bearer mck_...` was turned away with 401 "invalid or missing API key" on every API-key endpoint: the CLI ingest POST /api/approvals, the poll GET /api/approvals/:id, and GET /api/me. The key was valid; only its scheme casing was not. Match the scheme with a case-insensitive test. The token itself is still taken byte-exact, so a wrong key, a missing header, a different scheme, and a scheme with no space after it all still 401. Adds apps/pwa/test/apikey-bearer-scheme.test.mjs (6 tests) covering lowercase and uppercase schemes on /api/me and /api/approvals, plus the canonical Bearer path and the rejection cases as controls.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
bearer()inapps/pwa/src/lib/apikey.mjsmatched the literal string"Bearer ":RFC 7235 §2.1 makes the auth-scheme name case-insensitive, so
authorization: bearer mck_…is a valid way to present a moshcode API key. The exact-string check turned those requests away with401 {"error":"invalid or missing API key"}— the same error a revoked or mistyped key gets, so it reads as a key problem rather than a casing problem.Every API-key endpoint is affected, because they all go through
bearer():POST /api/approvals— CLI ingest (routes/approvals.mjs:26)GET /api/approvals/:id— CLI long-poll (routes/approvals.mjs:97)GET /api/me(routes/cli.mjs:98)Scope, stated honestly
The bundled CLI is not affected —
src/auth.mjs:140andsrc/notify.mjs:37,71both sendBearer, so nothing in this repo hits it. This shows up for third-party and hand-rolled clients: curl one-liners, CI scripts, and HTTP libraries that normalise or lowercase the scheme. The settings page tells people to "sendAuthorization: Bearer <key>", and a client that follows the spec rather than the exact casing gets a 401 with nothing to go on.Reproduction
Against unmodified
main(df9d1e0), realcliRouter+approvalsRouteron a throwaway libsql database, one real API key minted throughcreateApiKey. No stubs, no fault injection:Bearer <key>→/api/mebearer <key>→/api/meBEARER <key>→/api/mebearer <key>→POST /api/approvalsThe fix
One line, plus a comment explaining why:
Only the scheme is matched loosely. The token is still sliced and compared byte-exact, so nothing about key verification changes.
Tests
New
apps/pwa/test/apikey-bearer-scheme.test.mjs, 6 tests, built on the existingcli-token.test.mjsharness (skip-guard for missing PWA deps + throwaway libsql).Three of them are the bug: lowercase and uppercase schemes on
/api/me, and a lowercase scheme onPOST /api/approvals. The other three are controls that pass both before and after the patch, which is what shows the scheme match was widened rather than auth being loosened:Bearerpath still authenticatesBearer,bearerandBEARERBasicscheme, a bare token with no scheme, andBearer<key>with no space all still 401Fail-before verified by restoring the pristine
apikey.mjsand re-running: 3 fail / 33 pass unpatched, 36/36 patched.apps/pwagoes 30 → 36 tests, rootnpm test204 → 210, zero failures either way.