Skip to content

Commit 0580949

Browse files
committed
fix(auth): make uuid() SSR-aware for Next.js 16 compatibility
1 parent d1ba7d9 commit 0580949

File tree

1 file changed

+39
-5
lines changed

1 file changed

+39
-5
lines changed

packages/core/auth-js/src/lib/helpers.ts

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,46 @@ export function expiresAt(expiresIn: number) {
99
return timeNow + expiresIn
1010
}
1111

12+
// Counter for SSR-safe UUID generation
13+
let ssrUuidCounter = 0
14+
15+
/**
16+
* Generates a UUID v4 string.
17+
*
18+
* This function is SSR-aware to handle Next.js 16 pre-rendering constraints:
19+
* - In browsers: Uses crypto.randomUUID() or crypto.getRandomValues() for cryptographic randomness
20+
* - During SSR: Uses a deterministic fallback (timestamp + counter)
21+
*
22+
* Note: The SSR fallback is safe because:
23+
* 1. UUIDs from this function are only used for internal subscription IDs, not security-critical operations
24+
* 2. During SSR/pre-rendering, auth callbacks don't actually fire
25+
* 3. Once in the browser, proper cryptographic APIs are always used
26+
*/
1227
export function uuid() {
13-
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
14-
const r = (Math.random() * 16) | 0,
15-
v = c == 'x' ? r : (r & 0x3) | 0x8
16-
return v.toString(16)
17-
})
28+
// Modern browsers and Node.js 19+ - use native crypto.randomUUID()
29+
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
30+
return crypto.randomUUID()
31+
}
32+
33+
// Browsers with crypto.getRandomValues() support
34+
if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {
35+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
36+
const array = new Uint8Array(1)
37+
crypto.getRandomValues(array)
38+
const r = array[0] % 16
39+
const v = c == 'x' ? r : (r & 0x3) | 0x8
40+
return v.toString(16)
41+
})
42+
}
43+
44+
// SSR/pre-render fallback - deterministic but unique within session
45+
// This only generates subscription IDs during pre-render; real UUIDs use crypto in browser
46+
const timestamp = Date.now()
47+
const counter = ssrUuidCounter++
48+
const random1 = Math.floor(timestamp / 1000000) % 10000
49+
const random2 = (timestamp % 1000000) % 10000
50+
51+
return `ssr-${timestamp.toString(16)}-${counter.toString(16)}-${random1.toString(16)}-${random2.toString(16)}`
1852
}
1953

2054
export const isBrowser = () => typeof window !== 'undefined' && typeof document !== 'undefined'

0 commit comments

Comments
 (0)