Always use supabase.auth.getUser() on the server side to verify identity. getSession() reads the JWT from cookies and decodes it without verifying the signature against the auth server — so if an attacker tampers with the token (changing the user ID, role, or email), your server-side code will trust the forged claims as legitimate. This is a complete authentication bypass: the attacker can impersonate any user, escalate privileges, or access data they were never authorized to see.
getSession() reads the JWT from cookies without re-verifying the token with the auth server. An attacker can forge or tamper with the JWT payload (e.g., changing the user ID or role) and your server will trust it. This is a critical authentication bypass on the server side.
BeforeMerge scans your pull requests against this rule and 3+ others. Get actionable feedback before code ships.
supabase.auth.getSession() reads the JWT from the browser's cookies and decodes it without re-verifying the token with the Supabase Auth server. This means:
session.user are completely bypassableThis is not a minor issue — it is a full authentication bypass on the server side.
On the server side (Server Components, Server Actions, API Routes, middleware), always use getUser() instead of getSession() when you need to verify who the user is.
getUser() sends the token to the Supabase Auth server for verification, confirming it has not been tampered with or revoked.
// Server Action — INSECURE
export async function deleteAccount() {
const supabase = await createClient();
const { data: { session } } = await supabase.auth.getSession();
if (!session) throw new Error("Not authenticated");
// DANGER: session.user.id could be forged!
await supabase.from("profiles").delete().eq("id", session.user.id);
}// Server Action — SECURE
export async function deleteAccount() {
const supabase = await createClient();
const { data: { user }, error } = await supabase.auth.getUser();
if (error || !user) throw new Error("Not authenticated");
// user.id is verified by the auth server
await supabase.from("profiles").delete().eq("id", user.id);
}Search your server-side code for getSession():
grep -rn "getSession()" app/ lib/ --include="*.ts" --include="*.tsx"Any occurrence in a Server Component, Server Action, API route, or middleware is a finding.
supabase.auth.getSession() with supabase.auth.getUser() on all server-side code pathsgetUser() returns { data: { user }, error } instead of { data: { session } }