Supabase: CORS errors from browser [2026 fix]
Browser blocks Supabase API calls due to missing CORS headers. Fix: Configure allowed origins in Supabase dashboard or use proper auth headers.
Supabase CORS Errors from Browser – Emergency Fix
TL;DR
Cause: Your browser is blocking requests to Supabase because the origin (your domain) isn't registered in Supabase's CORS allowlist. Fix: Add your domain to Supabase Project Settings → API → CORS Allowed Origins, or switch to authenticated requests with proper JWT tokens.---
Real Console Error Messages
Here are the exact errors you're seeing at 2am:
``` 1. Access to XMLHttpRequest at 'https://xxxxx.supabase.co/rest/v1/users?select=*' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
2. Uncaught (in promise) TypeError: Failed to fetch (Network tab shows OPTIONS request returning 403)
3. Access to XMLHttpRequest at 'https://xxxxx.supabase.co/rest/v1/tables' from origin 'https://myapp.com' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'.
4. Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://xxxxx.supabase.co/rest/v1/auth/v1/token. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
5. TypeError: NetworkError when attempting to fetch resource (usually means preflight OPTIONS failed before actual request even sent) ```
---
Broken Code vs. Exact Fix
❌ BROKEN: Anonymous Requests Without CORS Configuration
```javascript // This fails at 2am because your origin isn't whitelisted const { data, error } = await supabase .from('users') .select('*') .eq('active', true);
if (error) console.log('CORS blocked:', error); ```
Why it breaks: Supabase's REST API requires either: 1. Your origin in CORS allowlist (for anonymous/public requests), OR 2. A valid JWT in Authorization header (for authenticated requests)
✅ FIX #1: Add Domain to CORS Allowlist (Simplest)
In Supabase Dashboard:
1. Go to Project Settings → API
2. Find "CORS Allowed Origins"
3. Add: http://localhost:3000 (dev) and https://yourdomain.com (prod)
4. Click Save
5. Hard refresh browser (Cmd+Shift+R or Ctrl+Shift+R)
```javascript // Same code now works because your origin is whitelisted const { data, error } = await supabase .from('users') .select('*') .eq('active', true); ```
✅ FIX #2: Use Authenticated Requests (More Secure)
Broken: ```javascript const supabase = createClient(url, anonKey); // Anon key + your origin not in CORS list = blocked const { data } = await supabase.from('users').select('*'); ```
Fixed: ```javascript const supabase = createClient(url, anonKey);
// First authenticate user const { data: session } = await supabase.auth.getSession();
if (session?.access_token) { // Authenticated requests include JWT header automatically const { data } = await supabase .from('users') .select('*'); // CORS check is bypassed for authenticated requests } ```
When you use supabase.auth.* methods, the client automatically adds the Authorization header with your JWT. CORS restrictions don't apply the same way to authenticated requests—Supabase validates your token instead.
✅ FIX #3: Explicit Headers (Raw Fetch)
If using raw fetch() instead of Supabase client:
Broken: ```javascript fetch('https://xxxxx.supabase.co/rest/v1/users?select=*') .then(r => r.json()) .catch(e => console.log('CORS error:', e)); ```
Fixed:
```javascript
fetch('https://xxxxx.supabase.co/rest/v1/users?select=*', {
headers: {
'apikey': 'your-anon-key',
'Authorization': Bearer ${jwtToken},
'Content-Type': 'application/json'
}
})
.then(r => r.json())
.catch(e => console.log('Error:', e));
```
Note on version specificity: Supabase client library (v2+) handles auth headers automatically. If you're on v1.x, behavior may differ slightly—check your package.json.
---
Still Broken? Check These Too
1. Localhost CORS vs. Production
Add both http://localhost:3000 AND https://yourdomain.com to CORS allowlist. Supabase treats them as separate origins.
2. Browser Cache and Service Workers Hard refresh (Cmd+Shift+R) doesn't always clear service worker cache. Open DevTools → Application → Service Workers → Unregister, then refresh.
3. Supabase Client Initialization Ensure your client is using correct credentials: ```javascript const supabase = createClient( process.env.REACT_APP_SUPABASE_URL, process.env.REACT_APP_SUPABASE_ANON_KEY ); // Verify these are real values, not undefined console.log(process.env.REACT_APP_SUPABASE_URL); ```
---
Related Guides
---
Official Documentation
[Supabase CORS Configuration](https://supabase.com/docs/guides/api/cors)
---
Found a Different Variation?
Drop it in the comments. CORS errors have subtle variations (preflight timeouts, credential mode mismatches, wildcard origin issues). Your edge case helps others at 2am.