Docs: Google Nonce Example Declares HashedNonce Inside Promise Callback Causing ReferenceError And Potential Security Bypass
The Supabase Google login documentation contains a code snippet where hashedNonce is declared inside a .then() callback, making it inaccessible outside the callback. Users following the guide encounter a ReferenceError when trying to use hashedNonce, and may skip the nonce or pass the raw nonce to both Google and Supabase, reducing security.
The example uses a const declaration inside the .then() callback, which limits the variable's scope to that callback. Additionally, the asynchronous nature of the promise means any subsequent code runs before the digest resolves, so even hoisting would not make the value available. The documentation fails to use async/await or an appropriate pattern to keep both nonce and hashedNonce in scope.
1. Copy the code snippet from the Supabase Google pre-built nonce section.\n2. Run it in a browser or Node.js environment.\n3. Attempt to access 'hashedNonce' after the .then() block.\n4. Observe the ReferenceError: hashedNonce is not defined.
Fixing Code Block
const nonce = btoa(String.fromCharCode(...crypto.getRandomValues(new Uint8Array(32))))
const encoder = new TextEncoder()
const encodedNonce = encoder.encode(nonce)
const hashBuffer = await crypto.subtle.digest('SHA-256', encodedNonce)
const hashArray = Array.from(new Uint8Array(hashBuffer))
const hashedNonce = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('')
// Use 'hashedNonce' when making the authentication request to Google
// Use 'nonce' when invoking the supabase.auth.signInWithIdToken() method
Replace the promise-based .then() call with a top-level await on crypto.subtle.digest. This makes the code synchronous within an async context, ensuring hashedNonce is defined and available in the surrounding scope before the next lines execute. It aligns with the existing generateNonce() helper later in the document.
Edge Case Audit
This fix assumes a JavaScript environment that supports top-level await (ES2022 modules) and a secure context (HTTPS) for crypto.subtle. In non-module scripts or older browsers, top-level await will cause a syntax error. For compatibility, wrap the logic in an async function or use .then() with the variable properly assigned in an outer scope. If concurrency is a concern, avoid storing nonce/hashedNonce in global mutable state; prefer a function that generates and returns both values. Rollback: if the await version breaks in a target environment, revert to the .then() pattern but declare hashedNonce in the outer scope and handle the asynchronous result via a callback, promise chain, or async function call.