- Symptom
- The service_role key or an sb_secret_ key is set in a NEXT_PUBLIC_ variable or passed to createClient in a client componentThe key can be found in the JavaScript your site sends to visitorsRequests made with a new secret key from the browser fail with HTTP 401 Unauthorized
- Cause
- Secret keys and the legacy service_role key act as the service_role role, which has the BYPASSRLS attribute, so a request made with one ignores every Row Level Security policy. Supabase blocks new secret keys in browsers by User-Agent, but anyone who copies a key out of a web page, a shipped app or source control can still use it outside a browser.
- Fix
- Use only the publishable key (or the legacy anon key) in browser and mobile code, and keep secret keys in server-only environment variables without the NEXT_PUBLIC_ prefix. If a secret key was ever shipped or committed, fix the cause of the leak first, then create a new secret key, replace it everywhere, confirm every component uses it, and delete the old one.
- Apply
// lib/supabase/browser.ts: safe in the browser import { createClient } from '@supabase/supabase-js' export const supabase = createClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!, ) // lib/supabase/admin.ts: server only, never imported by a client component import 'server-only' import { createClient } from '@supabase/supabase-js' export const admin = createClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.SUPABASE_SECRET_KEY!, )- Affected
- Supabase projects using a secret key or the legacy service_role key; Supabase is deprecating the anon and service_role keys by the end of 2026
- Sources
Last verified 2026-10-27 · Confirmed by 0 builders