feat(auth): add optional API key authentication middleware#188
Merged
Conversation
|
@AGWAM001 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
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 #59
Summary
Adds an opt-in API key authentication middleware that restricts access to the API when REQUIRE_API_KEY=true is set. Deployments that don't set the variable get identical behaviour to today — zero breaking changes for existing consumers.
Changes
Middleware — apiKeyAuth
Created src/middleware/api_key_auth.ts with a single exported apiKeyAuth middleware function.
On every inbound request (except /health — see below), when REQUIRE_API_KEY=true:
Reads the X-API-Key header from the request.
Checks the value against the parsed API_KEYS allow-list.
Returns 401 with { "error": "Unauthorized", "message": "Missing or invalid API key" } if the header is absent or the key is not in the list.
Calls next() if the key is valid.
When REQUIRE_API_KEY is unset or not "true", the middleware calls next() immediately without reading any headers.
/health Always Public
Health route is bound before the auth middleware is registered so it is unconditionally exempt — load balancers and uptime monitors are never blocked.
Environment Variables
REQUIRE_API_KEY — No — Set to true to enable key enforcement. Defaults to off.
API_KEYS — When auth enabled — Comma-separated valid keys e.g. key1,key2,key3.
Startup Guard
If REQUIRE_API_KEY=true and API_KEYS resolves to an empty list, the server throws a hard configuration error at boot rather than silently rejecting every request.
App Registration
apiKeyAuth is mounted globally in app.ts after /health and before all other route handlers.
Testing
Middleware is a no-op when REQUIRE_API_KEY is unset
Valid key in X-API-Key passes through to the handler
Missing X-API-Key header returns 401
Invalid key value returns 401
GET /health returns 200 with and without a valid key
All keys in a multi-key API_KEYS list are individually accepted
Boot throws when REQUIRE_API_KEY=true and API_KEYS is empty
Notes
Key comparison uses constant-time equality to prevent timing side-channel attacks.
API_KEYS entries are whitespace-trimmed at parse time so formatting like key1, key2, key3 is handled safely.
No changes to existing route handlers, response shapes, or other config — this is purely additive.
Key rotation, expiry, and per-key permission scopes are intentionally out of scope for this PR.Sonnet 4.6 Low