Supabase: CORS errors from browser [2026 fix]
Browser blocks Supabase requests due to missing CORS headers in auth config. Fix: Add your domain to allowed origins in project settings.
Supabase CORS Errors from Browser: Emergency Fix
TL;DR
Cause: Your browser is blocking Supabase API requests because your domain isn't whitelisted in Supabase's CORS policy. Fix: Add your frontend domain to "Authorized redirect URLs" and CORS allowed origins in your Supabase project dashboard under Authentication → URL Configuration.---
Exact Error Messages You'll See
``` Access to XMLHttpRequest at 'https://[project-ref].supabase.co/auth/v1/token' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control checks: No 'Access-Control-Allow-Origin' header is present on the requested resource. ```
``` CORS error: No 'Access-Control-Allow-Credentials' header was received when credentials mode is 'include' ```
``` Failed to load resource: the server responded with a status of 403 (Forbidden) (supabase.co) ```
``` OPTIONS https://[project-ref].supabase.co/rest/v1/ 403 ```
``` TypeError: Failed to fetch - CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response is '' which must not be the wildcard '*' when the request's credentials mode is 'include' ```
---
Broken Code → Fixed Code
❌ BROKEN: Creating Supabase client without CORS configuration
```javascript // pages/index.js or app.js import { createClient } from '@supabase/supabase-js'
const supabase = createClient( 'https://yourproject.supabase.co', 'your-anon-key' )
// This will fail with CORS errors on production domain export async function getServerSideProps() { const { data } = await supabase .from('users') .select('*') return { props: { data } } } ```
✅ FIXED: Configure Supabase project settings first, then use client
Step 1: Dashboard Configuration 1. Go to your Supabase project dashboard 2. Navigate to Authentication → URL Configuration 3. Add these to "Authorized redirect URLs": ``` http://localhost:3000/auth/callback http://localhost:3000 https://yourdomain.com/auth/callback https://yourdomain.com https://www.yourdomain.com ``` 4. In the same section, ensure "Site URL" is set to your production domain
Step 2: Client Code (no changes needed if Step 1 is done)
```javascript // pages/index.js or app.js - code stays the same import { createClient } from '@supabase/supabase-js'
const supabase = createClient( process.env.NEXT_PUBLIC_SUPABASE_URL, // Use env vars process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY )
// Now this works because domain is whitelisted export async function getServerSideProps() { const { data } = await supabase .from('users') .select('*') return { props: { data } } } ```
Step 3: Environment Variables
```bash
.env.local (development)
NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321 NEXT_PUBLIC_SUPABASE_ANON_KEY=your-local-anon-keyProduction - deployed to Vercel/Netlify/etc
Add same vars to your hosting platform's secrets
NEXT_PUBLIC_SUPABASE_URL=https://yourproject.supabase.co NEXT_PUBLIC_SUPABASE_ANON_KEY=your-prod-anon-key ```---
Critical Details
Behavior we're uncertain about: Supabase's exact caching duration for CORS policy changes varies by their CDN configuration—changes sometimes apply instantly, sometimes within 5-10 minutes. We recommend: make dashboard changes, wait 2 minutes, then hard-refresh your browser (Ctrl+Shift+R).
Important: Never include your SUPABASE_SERVICE_ROLE_KEY in frontend code. Only use NEXT_PUBLIC_SUPABASE_ANON_KEY in browsers.
---
Still Broken? Check These Too
1. [LocalHost + Supabase mismatch](/guide=localhost-supabase) — If testing locally, ensure you've added http://localhost:3000 (exact port) to Authorized redirect URLs. Different ports = different origins.
2. [Auth callback URL not matching](/guide=auth-callback-mismatch) — Your redirect callback in code must match dashboard exactly. https://yourdomain.com/auth/callback ≠ https://yourdomain.com/auth/login.
3. Stale browser cache — Open DevTools (F12), go to Application → Storage → Clear site data, then refresh. Or test in private/incognito window.
---
Official Resources
---
Found a different variation? Drop it in the comments
Are you seeing a unique CORS error that doesn't match these patterns? Reply below with:
We update this guide based on real production issues from the community.