because I got bored of customising my CV for every job
1import { Injectable } from "@nestjs/common";
2import type { Response } from "express";
3import { JwtConfigService } from "../config/jwt.config";
4import { CookieService } from "../cookie/cookie.service";
5
6@Injectable()
7export class AuthCookieService {
8 constructor(
9 private readonly cookieService: CookieService,
10 private readonly jwtConfig: JwtConfigService,
11 ) {}
12
13 private parseExpiryToSeconds(expiryString: string): number {
14 if (!expiryString || typeof expiryString !== "string") {
15 throw new Error(
16 `Invalid expiry string: ${JSON.stringify(expiryString)}. Expected format like "15m", "1h", "7d"`,
17 );
18 }
19
20 const match = expiryString.match(/^(\d+)([smhd])$/);
21 if (!(match?.[1] && match[2])) {
22 throw new Error(
23 `Failed to parse expiry string: ${expiryString}. Expected format like "15m", "1h", "7d"`,
24 );
25 }
26
27 const value = Number.parseInt(match[1], 10);
28 const unit = match[2];
29
30 if (Number.isNaN(value) || value <= 0) {
31 throw new Error(
32 `Invalid expiry value: ${value}. Must be a positive number`,
33 );
34 }
35
36 switch (unit) {
37 case "s":
38 return value;
39 case "m":
40 return value * 60;
41 case "h":
42 return value * 60 * 60;
43 case "d":
44 return value * 60 * 60 * 24;
45 default:
46 throw new Error(`Invalid expiry unit: ${unit}. Expected s, m, h, or d`);
47 }
48 }
49
50 setAuthCookies(
51 res: Response,
52 accessToken: string,
53 refreshToken: string,
54 ): void {
55 const accessTokenMaxAgeSeconds = this.parseExpiryToSeconds(
56 this.jwtConfig.getAccessTokenExpiry(),
57 );
58
59 if (accessTokenMaxAgeSeconds <= 0) {
60 throw new Error("Invalid access token expiry");
61 }
62
63 const accessTokenMaxAgeMs = accessTokenMaxAgeSeconds * 1000;
64 const refreshTokenMaxAgeMs = 60 * 60 * 24 * 7 * 1000; // 7 days
65
66 this.cookieService.setCookie(res, "access_token", accessToken, {
67 maxAge: accessTokenMaxAgeMs,
68 });
69
70 this.cookieService.setCookie(res, "refresh_token", refreshToken, {
71 maxAge: refreshTokenMaxAgeMs,
72 path: "/api/auth/credentials/refresh",
73 });
74 }
75
76 clearAuthCookies(res: Response): void {
77 this.cookieService.clearCookie(res, "access_token");
78 this.cookieService.clearCookie(res, "refresh_token", {
79 path: "/api/auth/credentials/refresh",
80 });
81 }
82}