@@ -39,9 +39,30 @@ import type {
3939 SafeUser ,
4040} from './auth.service' ;
4141import type { Response , Request , CookieOptions } from 'express' ;
42+ import * as crypto from 'crypto' ;
4243
4344// Cookie configuration for secure token storage
4445// In monorepo deployment, frontend and API are on the same domain,
46+
47+ /**
48+ * Encrypt a token value for storage in a cookie using AES-256-GCM.
49+ * The secret should come from configuration (e.g., OAUTH_TOKEN_COOKIE_SECRET).
50+ *
51+ * The output format is base64-encoded concatenation of IV, authTag and ciphertext:
52+ * base64( iv || authTag || ciphertext )
53+ */
54+ function encryptTokenForCookie ( token : string , secret : string ) : string {
55+ const iv = crypto . randomBytes ( 12 ) ; // 96-bit IV recommended for GCM
56+ const key = crypto . createHash ( 'sha256' ) . update ( secret , 'utf8' ) . digest ( ) ; // 32 bytes
57+ const cipher = crypto . createCipheriv ( 'aes-256-gcm' , key , iv ) ;
58+ const ciphertext = Buffer . concat ( [
59+ cipher . update ( token , 'utf8' ) ,
60+ cipher . final ( ) ,
61+ ] ) ;
62+ const authTag = cipher . getAuthTag ( ) ;
63+ const combined = Buffer . concat ( [ iv , authTag , ciphertext ] ) ;
64+ return combined . toString ( 'base64' ) ;
65+ }
4566// so we can use 'lax' for better security
4667const getCookieOptions = ( ) : CookieOptions => {
4768 const isProduction = process . env . NODE_ENV === 'production' ;
@@ -175,7 +196,18 @@ export class AuthController {
175196 ) ;
176197
177198 // Set HTTP-only cookie - in monorepo deployment, this cookie works directly
178- res . cookie ( 'access_token' , result . access_token , COOKIE_OPTIONS ) ;
199+ const tokenEncryptionSecret =
200+ this . configService . get < string > ( 'OAUTH_TOKEN_COOKIE_SECRET' ) ;
201+ if ( ! tokenEncryptionSecret ) {
202+ // Fallback: do not set the cookie if no secret is configured
203+ // (avoids storing sensitive data in clear text).
204+ } else {
205+ const encryptedAccessToken = encryptTokenForCookie (
206+ result . access_token ,
207+ tokenEncryptionSecret ,
208+ ) ;
209+ res . cookie ( 'access_token' , encryptedAccessToken , COOKIE_OPTIONS ) ;
210+ }
179211
180212 // Redirect to frontend callback page
181213 res . redirect ( `${ frontendUrl } /auth/callback?token=${ result . access_token } ` ) ;
0 commit comments