Skip to content

fix(auth): two-tier 401 distinguishing bad Bearer scheme from key failure#106

Merged
SyniRon merged 1 commit into
developfrom
agent/issue-99
May 31, 2026
Merged

fix(auth): two-tier 401 distinguishing bad Bearer scheme from key failure#106
SyniRon merged 1 commit into
developfrom
agent/issue-99

Conversation

@SyniRon
Copy link
Copy Markdown
Collaborator

@SyniRon SyniRon commented May 31, 2026

Closes #99

Splits the bare Unauthorized / codes.Unauthenticated into two tiers on both auth surfaces:

  • Bearer-scheme problem (no/empty/oversized token from ParseBearerToken): 401 body names the expected format — Unauthorized: expected 'Authorization: Bearer <key>' header (gRPC mirrors with codes.Unauthenticated + metadata-accurate wording).
  • Key-validation failure (token present, ValidateApiKey nil/err): generic Unauthorized — no leak about key existence/expiry/scopes.

ParseBearerToken unchanged (contract is fine — fix is caller-side reaction). HTTP + gRPC kept consistent in spirit.

Tests

  • New servers/gateway/auth_test.go (gateway had no test file): 5 cases across both 401 branches.
  • servers/grpc/auth_test.go: +3 cases (no header, raw-key-no-prefix → names Bearer; bad key → generic no-leak).

Gate

build ✅ · go test ./... ✅ · buf lint + buf breaking --against develop ✅ · auth local-stack smoke pending pre-land.

🤖 Generated with Claude Code

…lure

HTTP authMiddleware and gRPC unary interceptor collapsed both the
bad/missing Bearer scheme case and the key-validation failure case into a
bare Unauthorized / codes.Unauthenticated. Callers pasting a raw cav7_ key
without the "Bearer " prefix got a generic 401 with no hint.

Split into two tiers on both surfaces:
- Bearer-scheme problem (ParseBearerToken returns empty): name the expected
  format. HTTP body "Unauthorized: expected 'Authorization: Bearer <key>'
  header"; gRPC codes.Unauthenticated with mirrored message. gRPC unifies
  the missing-metadata / missing-header / empty-token branches here.
- Key-validation failure (token present, ValidateApiKey nil/err): keep the
  generic message, leaking nothing about key existence/expiry/scopes.

ParseBearerToken unchanged (empty-return contract intact). Adds gateway
auth_test.go (no prior coverage) and grpc interceptor cases exercising both
401 branches on both surfaces.

Closes #99

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@SyniRon SyniRon merged commit 502a716 into develop May 31, 2026
2 checks passed
@SyniRon SyniRon deleted the agent/issue-99 branch May 31, 2026 12:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

auth: 401 message should hint at expected "Bearer <key>" scheme

1 participant