feat: add POST /v1/admin/api-keys and supporting admin routes - #21
Merged
Merged
Conversation
Closes Astraguard#4. - Add POST /v1/admin/api-keys: issues a new API key for a user (by email, creating the user if they don't exist). Scopes, rate-limit tier, and role are configurable. The raw key is returned exactly once. - Add GET /v1/admin/api-keys: admin-wide list of all keys with owner email joined. Supports includeRevoked, limit/offset pagination, and ownerId filtering. - Add DELETE /v1/admin/api-keys/:id: soft-revokes a key (sets revoked_at). Returns 404 if the key doesn't exist, 409 if already revoked. - All three routes are gated behind the admin:api-keys scope. - Add revokeApiKey() and listAllApiKeys() helpers to shared/api-keys.ts. - Add admin:api-keys scope to the seed key so the bootstrap key can immediately provision further keys via the new endpoint. - Update db/seed.ts comment to reflect that POST /v1/admin/api-keys is the intended path after initial bootstrap. - Document all three routes + ApiKeyRecord / IssueApiKeyRequest / IssuedApiKeyResponse schemas in openapi.yaml. - Update README Getting started section to call out the admin endpoint.
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.
Summary
Closes #4.
The only previous way to create an API key was
npm run seed— a one-time local bootstrap script. This PR adds a full admin API key management surface gated behind theadmin:api-keysscope so registry analysts and partner integrations can be provisioned without direct DB/script access.Changes
New route file:
src/api/routes/admin.tsPOST/v1/admin/api-keysadmin:api-keysGET/v1/admin/api-keysadmin:api-keysDELETE/v1/admin/api-keys/:idadmin:api-keysPOST /v1/admin/api-keys
ownerEmail,label,scopes(one or more ofadmin:api-keys,registry:review,certification:decide,claims:review),rateLimitTier(standard/partner/internal), optionalroleensureUser)rawKeyexactly once — not stored, not retrievable againGET /v1/admin/api-keys
includeRevoked(defaultfalse),limit/offset(pagination),ownerId(filter to one user)usersto surfaceownerEmailalongside each key recordkey_hashis never returnedDELETE /v1/admin/api-keys/:id
revoked_at— the auth middleware already filtersWHERE revoked_at IS NULLsrc/shared/api-keys.tsrevokeApiKey(keyId)— soft-delete helper returning a boolean indicating whether the key was active and is now revokedlistAllApiKeys(opts)— admin-wide key listing helper (not used directly by admin.ts which does a richer join, but exported for use in tests or future CLI tooling)src/api/app.tsregisterAdminRoutes(app)src/api/openapi.yamlAdded:
/v1/admin/api-keys(GET + POST)/v1/admin/api-keys/{id}(DELETE)ApiKeyRecordschemaIssueApiKeyRequestschemaIssuedApiKeyResponseschemadb/seed.tsadmin:api-keysscope to the bootstrap seed key so it can immediately provision further keys via the new endpointREADME.mdadmin:api-keysand can provision additional keys viaPOST /v1/admin/api-keysBehaviour details
Raw key visibility — consistent with the existing
issueApiKeycontract and the webhooks endpoint: the key is generated withrandomBytes(24), hashed with SHA-256 + salt, and only the hash is persisted. The raw key appears once in the201response body.Revocation —
DELETEsetsrevoked_at. The existingresolveApiKeyinauth.tsalready queriesWHERE revoked_at IS NULL, so revoked keys are immediately rejected on the next request without any cache invalidation step.Scope gating — the
admin:api-keysscope is not granted by the public key-issuance path; only an existingadmin:api-keys-scoped key (or the seed key) can issue new admin-scoped keys.What was tested
tsc --noEmitpasses clean — only the four pre-existingssrf-guard.tserrors remain (unrelated to this change)