feat(api-keys): restrict keys to source IP addresses

A key can be limited to IP addresses or CIDR networks (e.g. the Wabenhain
server); a stolen key is useless from anywhere else. Requests from other
addresses get 403 "not allowed for this IP" and a log line. The admin UI
asks for the addresses when creating a key, warns when a key works from
anywhere, shows the last source address and can take it over into the
allowlist - changing the list needs no new key (PATCH /api-keys/:id).

Also: a key can only carry scopes its creator holds.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5.5 committed 2026-10-01 02:41:46 +02:00
1 parent 9ae1d96a32
commit f1dc0de3e2
16 files changed
+463 -10

No files matched your search

@@ -16,6 +16,7 @@ import {
interface RequestWithUser {
headers: { authorization?: string };
ip?: string;
user?: AuthenticatedUser;
apiKey?: ApiKeyPrincipal;
}
@@ -55,7 +56,11 @@ export class JwtAuthGuard extends AuthGuard('jwt') {
// PermissionsGuard checks its scopes instead of a role.
const apiKeyToken = extractApiKeyToken(request.headers.authorization);
if (apiKeyToken !== null) {
const principal = await this.apiKeys.authenticate(apiKeyToken);
// request.ip honours TRUST_PROXY (see app.config.ts).
const principal = await this.apiKeys.authenticate(
apiKeyToken,
request.ip,
);
if (!principal) {
throw new UnauthorizedException();
}