Skip to content

Commit debb07b

Browse files
Potential fix for code scanning alert no. 164: Clear text storage of sensitive information
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
1 parent 9dd29d0 commit debb07b

File tree

1 file changed

+33
-1
lines changed

1 file changed

+33
-1
lines changed

apps/api/src/auth/auth.controller.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,30 @@ import type {
3939
SafeUser,
4040
} from './auth.service';
4141
import 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
4667
const 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

Comments
 (0)