This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

semble / src / shared / infrastructure / http / services / CookieService.ts
4.1 kB 149 lines
1import { Response, Request } from 'express'; 2import { 3 EnvironmentConfigService, 4 Environment, 5} from '../../config/EnvironmentConfigService'; 6 7export interface CookieOptions { 8 httpOnly: boolean; 9 secure: boolean; 10 sameSite: 'strict' | 'lax' | 'none'; 11 maxAge: number; 12 path: string; 13 domain?: string; 14} 15 16export class CookieService { 17 private readonly ACCESS_TOKEN_COOKIE = 'accessToken'; 18 private readonly REFRESH_TOKEN_COOKIE = 'refreshToken'; 19 20 constructor(private configService: EnvironmentConfigService) {} 21 22 /** 23 * Get cookie domain based on environment 24 * - local: undefined (defaults to localhost) 25 * - dev: .dev.semble.so (allows cookies across api.dev.semble.so and dev.semble.so) 26 * - prod: .semble.so (allows cookies across api.semble.so and semble.so) 27 */ 28 private getCookieDomain(): string | undefined { 29 const environment = this.configService.get().environment; 30 31 switch (environment) { 32 case Environment.PROD: 33 return '.semble.so'; 34 case Environment.DEV: 35 return '.dev.semble.so'; 36 case Environment.LOCAL: 37 default: 38 return undefined; // Don't set domain for localhost 39 } 40 } 41 42 /** 43 * Get base cookie options based on environment 44 */ 45 private getBaseCookieOptions(): Omit<CookieOptions, 'maxAge'> { 46 const environment = this.configService.get().environment; 47 const isProduction = environment === Environment.PROD; 48 49 return { 50 httpOnly: true, 51 secure: isProduction, // Only use secure cookies in production (requires HTTPS) 52 sameSite: 'lax', // 'lax' allows cookies on same-site navigation, better than 'strict' for auth flows 53 path: '/', 54 domain: this.getCookieDomain(), 55 }; 56 } 57 58 /** 59 * Set access token cookie 60 */ 61 public setAccessToken(res: Response, accessToken: string): void { 62 const accessTokenExpiresIn = 63 this.configService.getAuthConfig().accessTokenExpiresIn; 64 65 const options: CookieOptions = { 66 ...this.getBaseCookieOptions(), 67 maxAge: accessTokenExpiresIn * 1000, // Convert seconds to milliseconds 68 }; 69 70 res.cookie(this.ACCESS_TOKEN_COOKIE, accessToken, options); 71 } 72 73 /** 74 * Set refresh token cookie 75 */ 76 public setRefreshToken(res: Response, refreshToken: string): void { 77 const refreshTokenExpiresIn = 78 this.configService.getAuthConfig().refreshTokenExpiresIn; 79 80 const options: CookieOptions = { 81 ...this.getBaseCookieOptions(), 82 maxAge: refreshTokenExpiresIn * 1000, // Convert seconds to milliseconds 83 }; 84 85 res.cookie(this.REFRESH_TOKEN_COOKIE, refreshToken, options); 86 } 87 88 /** 89 * Set both access and refresh tokens 90 */ 91 public setTokens( 92 res: Response, 93 tokens: { accessToken: string; refreshToken: string }, 94 ): void { 95 this.setAccessToken(res, tokens.accessToken); 96 this.setRefreshToken(res, tokens.refreshToken); 97 } 98 99 /** 100 * Get access token from cookies 101 */ 102 public getAccessToken(req: Request): string | undefined { 103 return req.cookies?.[this.ACCESS_TOKEN_COOKIE]; 104 } 105 106 /** 107 * Get refresh token from cookies 108 */ 109 public getRefreshToken(req: Request): string | undefined { 110 return req.cookies?.[this.REFRESH_TOKEN_COOKIE]; 111 } 112 113 /** 114 * Clear both access and refresh token cookies 115 */ 116 public clearTokens(res: Response): void { 117 const cookieOptions = { 118 ...this.getBaseCookieOptions(), 119 maxAge: 0, // Expire immediately 120 }; 121 122 res.clearCookie(this.ACCESS_TOKEN_COOKIE, cookieOptions); 123 res.clearCookie(this.REFRESH_TOKEN_COOKIE, cookieOptions); 124 } 125 126 /** 127 * Clear access token cookie only 128 */ 129 public clearAccessToken(res: Response): void { 130 const cookieOptions = { 131 ...this.getBaseCookieOptions(), 132 maxAge: 0, 133 }; 134 135 res.clearCookie(this.ACCESS_TOKEN_COOKIE, cookieOptions); 136 } 137 138 /** 139 * Clear refresh token cookie only 140 */ 141 public clearRefreshToken(res: Response): void { 142 const cookieOptions = { 143 ...this.getBaseCookieOptions(), 144 maxAge: 0, 145 }; 146 147 res.clearCookie(this.REFRESH_TOKEN_COOKIE, cookieOptions); 148 } 149}