import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { UserService } from '../user/user.service'; import { Request } from 'express'; import { IS_PUBLIC_KEY } from './public.decorator'; @Injectable() export class ApiKeyGuard implements CanActivate { constructor( private reflector: Reflector, private userService: UserService, ) { } async canActivate(context: ExecutionContext): Promise { const isPublic = this.reflector.getAllAndOverride(IS_PUBLIC_KEY, [ context.getHandler(), context.getClass(), ]); if (isPublic) { return true; } const request = context.switchToHttp().getRequest(); const apiKey = this.extractApiKeyFromHeader(request); if (apiKey) { const user = await this.userService.findByApiKey(apiKey); if (user) { request.user = user; request.tenantId = user.tenantId; return true; } throw new UnauthorizedException('Invalid API key'); } throw new UnauthorizedException('Missing API key'); } private extractApiKeyFromHeader(request: Request): string | undefined { const authHeader = request.headers.authorization; if (authHeader && authHeader.startsWith('Bearer kb_')) { return authHeader.substring(7, authHeader.length); } const headerKey = request.headers['x-api-key'] as string; if (headerKey) return headerKey; return undefined; } }