Skip to content

migration(rs256): phase 119 — Implement /v1/api-keys + x-api-key middleware#20

Merged
kjgbot merged 3 commits intomainfrom
migration/rs256/119-api-keys
Apr 22, 2026
Merged

migration(rs256): phase 119 — Implement /v1/api-keys + x-api-key middleware#20
kjgbot merged 3 commits intomainfrom
migration/rs256/119-api-keys

Conversation

@kjgbot
Copy link
Copy Markdown
Contributor

@kjgbot kjgbot commented Apr 22, 2026

Phase 119 — Implement /v1/api-keys + x-api-key middleware

Part of the api-keys + RS256 migration. See specs/api-keys-and-rs256-migration.md for the full design.

Generated by workflows/119-*.ts and committed by scripts/run-rs256-migration.sh. Every workflow runs the strict review template (implementer self-review + 2 parallel specialist peer reviewers + architect synthesis + approval gate); this PR exists because the gate passed.

Run order in the migration

118 → 119 → 120 → 121 → publish + propagate → 122 → 123

This PR is phase 119. Merge in order; each phase assumes its predecessors are deployed.

Review focus

The workflow already enforced security + spec/compat review. Human review here should focus on:

  • Cross-cutting concerns the workflow couldn't see (production load, capacity, customer-facing impact)
  • Anything in the diff that isn't in the spec — flag it before merge
  • Test coverage gaps the agents may have missed in their domain

kjgbot and others added 3 commits April 22, 2026 22:54
…leware

Generated by workflows/119-*.ts via scripts/run-rs256-migration.sh.
Spec: specs/api-keys-and-rs256-migration.md (phase 119).

Co-Authored-By: agent-relay <agent@agent-relay.com>
- Mount apiKeyAuth() on /v1/identities/* (wildcard) and /v1/tokens/*
  so PATCH/DELETE/suspend/retire/reactivate accept x-api-key.
- Global auth gate admits x-api-key as an alternate credential when
  the middleware has authenticated the request.
- Enforce scopes ⊆ caller.scopes on POST /v1/api-keys to prevent
  privilege escalation via caller-supplied scope arrays.
- Regression tests for every identity sub-path via x-api-key, plus
  scope-subset enforcement and legitimate-subset cases.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous gate admitted any request carrying a non-empty x-api-key
header, relying on per-route handlers to validate. That's a footgun:
a future route added without mounting apiKeyAuth() would silently
accept unvalidated keys.

apiKeyAuth() already rewrites Authorization into a synthesized Bearer
on valid-key success, so every path that accepts x-api-key already
reaches the gate with Authorization set. The gate now only checks for
Authorization — no raw-x-api-key escape hatch.

Regression test: request with only x-api-key to a path that doesn't
mount apiKeyAuth() must return 401 missing_authorization.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@kjgbot kjgbot force-pushed the migration/rs256/119-api-keys branch from 2cc9a69 to 184cdb9 Compare April 22, 2026 20:55
@kjgbot kjgbot merged commit 042ceb6 into main Apr 22, 2026
2 checks passed
@kjgbot kjgbot deleted the migration/rs256/119-api-keys branch April 22, 2026 20:57
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.

1 participant