Skip to content

Commit 778da01

Browse files
ralyodioclaude
andauthored
fix: resolve SESSION_SECRET lazily to unblock production build (#29)
PR #20 removed the insecure SESSION_SECRET fallback by throwing at module import when the env var is unset. But `next build` imports API route modules during "Collecting page data", so the top-level throw broke every deploy after #20 (build failed at /api/auth/me with "SESSION_SECRET environment variable is required"). Move the check into a lazy getSessionSecret() called from hmac() at request time. This preserves #20's security intent (no fallback, requests fail if unset) while letting the build import route modules cleanly. Verified: `next build` now succeeds with SESSION_SECRET unset. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 12b0e31 commit 778da01

1 file changed

Lines changed: 13 additions & 5 deletions

File tree

apps/web/lib/auth.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,23 @@ import 'server-only';
22
import { cookies } from 'next/headers';
33

44
const COOKIE = 'cp_session';
5-
const SESSION_SECRET = process.env.SESSION_SECRET;
6-
if (!SESSION_SECRET) {
7-
throw new Error('SESSION_SECRET environment variable is required');
8-
}
95
const enc = new TextEncoder();
106

7+
// Resolve the secret lazily (at request time) rather than at module import.
8+
// Throwing at import breaks `next build` page-data collection, which imports
9+
// route modules in an environment without runtime secrets. This still enforces
10+
// #20's intent: no insecure fallback, and requests fail if the secret is unset.
11+
function getSessionSecret(): string {
12+
const secret = process.env.SESSION_SECRET;
13+
if (!secret) {
14+
throw new Error('SESSION_SECRET environment variable is required');
15+
}
16+
return secret;
17+
}
18+
1119
async function hmac(data: string): Promise<string> {
1220
const key = await crypto.subtle.importKey(
13-
'raw', enc.encode(SESSION_SECRET),
21+
'raw', enc.encode(getSessionSecret()),
1422
{ name: 'HMAC', hash: 'SHA-256' }, false, ['sign']
1523
);
1624
const sig = await crypto.subtle.sign('HMAC', key, enc.encode(data));

0 commit comments

Comments
 (0)