1
12import { CanActivate, ExecutionContext, Injectable } from "@nestjs/common";
13import type { Request } from "express";
14import { loadEnv } from "../../config/env.js";
15import { verifyToken, TokenError } from "../../lib/jwt.js";
16import type { AuthContext } from "../../common/types.js";
17
18@Injectable()
19export class OptionalAuthGuard implements CanActivate {
20 canActivate(context: ExecutionContext): boolean {
21 const req = context.switchToHttp().getRequest<Request>();
22 const header = req.headers.authorization;
23 if (!header || !header.startsWith("Bearer ")) return true;
24 const token = header.slice(7).trim();
25 if (!token || token.startsWith("fk_")) return true;
26 try {
27 const claims = verifyToken(token, loadEnv().JWT_SECRET);
28 if (typeof claims.sub !== "string" || claims.sub.length === 0) return true;
29 const auth: AuthContext = {
30 kind: "user",
31 userId: claims.sub,
32 workspaces: Array.isArray(claims.workspaces) ? claims.workspaces : undefined,
33 sessionId: typeof claims.sid === "string" ? claims.sid : undefined
34 };
35 (req as Request & { auth?: AuthContext }).auth = auth;
36 } catch (err) {
37 if (err instanceof TokenError) return true;
38 throw err;
39 }
40 return true;
41 }
42}
43