feat(backend, website): add API key authentication for collections API#1218
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
d103f69 to
9cdceb4
Compare
00d6037 to
f3d3660
Compare
#1200) Implements one-key-per-user API key auth as an alternative to OAuth sessions, allowing programmatic/script access via Authorization: Bearer <key> header. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend: ApiKeyClient + ApiKeyControllerTest covering all CRUD endpoints and the internal validate endpoint. Frontend: Playwright e2e test for the full lifecycle — generate key via UI, create a collection with Bearer auth, verify it, revoke the key, confirm the revoked key returns 401. Also fixes ktlint issues: rename package api_key → apikey, wrap long description line in ApiKeyController; fix eslint naming-convention violations in authMiddleware and apiKey.spec.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
064185d to
4563e22
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
Adds API key authentication to enable programmatic access to the collections API (without browser/OAuth session), including backend storage/validation, proxy support in the website middleware, a UI management page, and end-to-end + backend test coverage.
Changes:
- Backend: introduce API key persistence + key management endpoints (
/api-keys) and internal validation endpoint (/internal/api-keys/validate), including 409 handling. - Website/proxy: extend
authMiddlewareto acceptAuthorization: Bearer <key>and populategsUserId; add/api-keysUI and/api/api-keysproxy route. - Tests: add backend controller tests and Playwright E2E coverage for full key lifecycle + using Bearer auth to create collections.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| website/tests/e2e.fixture.ts | Adds authenticated fixture for the new API keys page object. |
| website/tests/api-keys/ApiKeyPage.ts | New Playwright page object for /api-keys interactions. |
| website/tests/api-keys/apiKey.spec.ts | New E2E test covering generate/use/revoke API key workflow. |
| website/src/types/pages.ts | Adds /api-keys route constant. |
| website/src/types/ApiKey.ts | Adds Zod schemas/types for API key metadata and generated key response. |
| website/src/pages/api/api-keys/index.ts | Proxies API key CRUD calls to the backend. |
| website/src/pages/api-keys/index.astro | Adds /api-keys page shell + auth gating. |
| website/src/middleware/authMiddleware.ts | Adds Bearer API key validation flow before cookie-session auth. |
| website/src/components/api-keys/ApiKeyManager.tsx | New UI for viewing metadata, generating, showing-once, and revoking keys. |
| website/src/backendApi/backendService.ts | Adds client methods for API key GET/POST/DELETE. |
| backend/src/test/kotlin/org/genspectrum/dashboardsbackend/controller/ApiKeyControllerTest.kt | Backend integration tests for API key endpoints and validation behavior. |
| backend/src/test/kotlin/org/genspectrum/dashboardsbackend/controller/ApiKeyClient.kt | Test client helpers for API key endpoints. |
| backend/src/main/resources/db/migration/V1.4__add_api_keys_table.sql | Adds api_keys_table migration (UUID PK, per-user uniqueness, hash index). |
| backend/src/main/kotlin/org/genspectrum/dashboardsbackend/model/apikey/ApiKeyTable.kt | Exposed table/entity for API keys + lookup helpers. |
| backend/src/main/kotlin/org/genspectrum/dashboardsbackend/model/apikey/ApiKeyModel.kt | Service logic for generate/revoke/validate and hash handling. |
| backend/src/main/kotlin/org/genspectrum/dashboardsbackend/controller/ExceptionHandler.kt | Adds ConflictException → HTTP 409 mapping. |
| backend/src/main/kotlin/org/genspectrum/dashboardsbackend/controller/ApiKeyController.kt | New REST controller for API key CRUD and internal validation endpoint. |
| backend/src/main/kotlin/org/genspectrum/dashboardsbackend/api/ApiKey.kt | Adds API DTOs for metadata, generation response, and validation request/response. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Enable pgcrypto extension in migration; use BackendError instanceof check instead of structural cast for 404 handling in ApiKeyManager. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Catch the unique constraint violation (SQLState 23505) on insert so concurrent requests for the same user get a 409 instead of a 500. The pre-check remains as a fast path for the common case. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Simpler and more idiomatic than catching SQLException and checking SQLState. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…convention Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The page is singular since a user can only have one key. Also adds an "API Key" link to the user dropdown menu. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…utton Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ode in description Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rated API key Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fengelniederhammer
approved these changes
May 27, 2026
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.
Closes #1200
Summary
api_keys_table(UUID PK, unique FK tousers_table, SHA-256 key hash, timestamps)GET/POST/DELETE /api-keys?userId=for key management;POST /internal/api-keys/validatefor proxy use;ConflictException(409) added to exception handlerauthMiddlewarenow checksAuthorization: Bearer <key>first — validates against the backend, populatesgsUserId, then falls through to the existing session cookie check if absent/invalid; unexpected validation errors are logged/api-keyspage with a React component to view key metadata, generate a new key (shown once in a modal), and revoke itNotes
SecureRandomvalue hex-encoded (64 chars); only its SHA-256 digest is storedTests
Backend (
ApiKeyControllerTest): covers all endpoints — GET/POST/DELETE/api-keysandPOST /internal/api-keys/validate. Cases include: no key returns 404, generated key is 64 hex chars, second key returns 409, revoked key returns 404 on validate,lastUsedAtupdates on each validation call, two users can hold independent keys.Playwright (
apiKey.spec.ts): full lifecycle test — navigates to/api-keysas an authenticated user, generates a key via the UI, captures it from the show-once modal, creates a collection viaAuthorization: Bearer <key>, verifies the collection is returned, revokes the key in the UI, then confirms a subsequent Bearer request returns 401.Screenshots
Screen.Recording.2026-05-21.at.15.04.15.mov
🤖 Generated with Claude Code