feat: add detailed request logging and error tracing to API key and JWT guards
Build and Push Multi-Platform Images / build-and-push (push) Successful in 29s

This commit is contained in:
2026-05-09 09:55:30 +02:00
parent a207b3057e
commit 367c8fe002
2 changed files with 31 additions and 18 deletions
+19 -9
View File
@@ -1,19 +1,25 @@
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { CanActivate, ExecutionContext, Injectable, Logger, UnauthorizedException } from '@nestjs/common';
import { ApiKeysService } from './api-keys.service';
@Injectable()
export class ApiKeyGuard implements CanActivate {
private readonly logger = new Logger(ApiKeyGuard.name);
constructor(private readonly apiKeysService: ApiKeysService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const method: string = request.method;
const url: string = request.url;
// Check header (X-API-Key)
let apiKey = request.headers['x-api-key'] || request.headers['X-API-Key'];
let source = 'X-API-Key header';
// Fallback to query parameter (apiKey)
if (!apiKey) {
apiKey = request.query['apiKey'];
if (apiKey) source = 'apiKey query param';
}
// Fallback to Authorization: Bearer (used by SSE clients that can't set X-API-Key)
@@ -21,24 +27,28 @@ export class ApiKeyGuard implements CanActivate {
const auth: string | undefined = request.headers['authorization'];
if (auth?.startsWith('Bearer ')) {
apiKey = auth.slice(7);
source = 'Authorization: Bearer';
}
}
this.logger.debug(
`[${method} ${url}] key source: ${apiKey ? source : 'NONE'} | ` +
`headers: ${JSON.stringify(Object.keys(request.headers))} | ` +
`key prefix: ${apiKey ? String(apiKey).slice(0, 8) + '…' : 'n/a'}`,
);
if (!apiKey) {
this.logger.warn(`[${method} ${url}] rejected no API key found`);
throw new UnauthorizedException('API Key missing');
}
try {
const keyEntry = await this.apiKeysService.validateKey(apiKey as string);
// Attach metadata to request if needed later
request.apiKeyMetadata = {
id: keyEntry.id,
name: keyEntry.name,
};
this.logger.debug(`[${method} ${url}] accepted key "${keyEntry.name}" (id=${keyEntry.id})`);
request.apiKeyMetadata = { id: keyEntry.id, name: keyEntry.name };
return true;
} catch (err) {
this.logger.warn(`[${method} ${url}] rejected validation failed: ${err.message}`);
throw new UnauthorizedException(err.message || 'Invalid API Key');
}
}