Firebase Hosting blocks cross-origin requests to Cloud Functions and APIs unless CORS headers are explicitly configured. Enable CORS by setting headers in firebase.json or adding CORS middleware to your Cloud Functions.
Cross-Origin Resource Sharing (CORS) is a security mechanism that prevents scripts on one domain from accessing resources on another domain without explicit permission. By default, Firebase Hosting and Cloud Functions don't include CORS headers in their responses, which means browsers will block requests from frontend applications running on different origins. This error occurs when your frontend (hosted on one domain or port) tries to fetch data from a Firebase Cloud Function, API endpoint, or storage bucket on a different origin, but the server hasn't been configured to allow such requests.
If your Firebase project uses Cloud Functions as the backend, CORS must be configured in the function code itself using the cors npm package.
First, check your functions directory to see if the cors package is already installed:
cd functions
npm list corsIf not installed, add it:
npm install corsThen update your Cloud Function to wrap your logic with CORS:
import * as functions from 'firebase-functions';
import * as cors from 'cors';
const corsHandler = cors({ origin: true });
export const myApi = functions.https.onRequest((req, res) => {
corsHandler(req, res, () => {
// Your function logic here
res.json({ message: 'Success' });
});
});The origin: true setting allows requests from any origin. For production, specify allowed origins:
const corsHandler = cors({
origin: ['https://yourdomain.com', 'https://app.yourdomain.com']
});Deploy the updated functions:
firebase deploy --only functionsIf you're using Firebase Hosting rewrites to proxy requests to Cloud Functions or external APIs, add CORS headers in your firebase.json:
{
"hosting": {
"rewrites": [
{
"source": "/api/**",
"function": "myApi"
}
],
"headers": [
{
"source": "/api/**",
"headers": [
{
"key": "Access-Control-Allow-Origin",
"value": "*"
},
{
"key": "Access-Control-Allow-Methods",
"value": "GET, POST, OPTIONS, PUT, DELETE"
},
{
"key": "Access-Control-Allow-Headers",
"value": "Content-Type, Authorization"
}
]
}
]
}
}For specific origins instead of wildcard:
{
"key": "Access-Control-Allow-Origin",
"value": "https://yourdomain.com"
}Redeploy hosting:
firebase deploy --only hostingBrowsers send an OPTIONS preflight request before actual requests when using certain methods or headers. Make sure your Cloud Function responds to OPTIONS requests:
import * as functions from 'firebase-functions';
import * as cors from 'cors';
const corsHandler = cors({ origin: true });
export const myApi = functions.https.onRequest((req, res) => {
corsHandler(req, res, () => {
if (req.method === 'OPTIONS') {
res.sendStatus(204);
return;
}
// Handle GET, POST, etc.
if (req.method === 'GET') {
res.json({ message: 'Success' });
} else {
res.status(405).send('Method not allowed');
}
});
});The cors middleware handles OPTIONS automatically, so this is only needed if you're not using the middleware.
If the error involves Firebase Storage (serving images, files directly from Cloud Storage), configure CORS using the Google Cloud CLI:
First, create a cors.json file:
[
{
"origin": ["https://yourdomain.com"],
"method": ["GET", "HEAD"],
"responseHeader": ["Content-Type"],
"maxAgeSeconds": 3600
}
]For development with multiple origins:
[
{
"origin": ["http://localhost:3000", "https://yourdomain.com"],
"method": ["GET", "HEAD", "PUT", "POST", "DELETE"],
"responseHeader": ["Content-Type", "Authorization"],
"maxAgeSeconds": 3600
}
]Apply the CORS configuration to your storage bucket:
gsutil cors set cors.json gs://your-bucket-name.appspot.comVerify it was applied:
gsutil cors get gs://your-bucket-name.appspot.comFor local development, start by testing with a permissive CORS configuration:
{
"key": "Access-Control-Allow-Origin",
"value": "*"
}Use browser DevTools to check headers in the Network tab:
1. Open DevTools (F12)
2. Go to Network tab
3. Make the request
4. Click on the request and check Response Headers
5. Look for access-control-allow-origin header
From the terminal, test with curl:
curl -i -X OPTIONS https://yourdomain.com/api/endpoint \
-H "Origin: http://localhost:3000" \
-H "Access-Control-Request-Method: GET"You should see Access-Control-Allow-Origin in the response headers.
CORS is a browser security feature that only applies to web requests, not server-to-server communication. Testing with curl or Postman will bypass CORS because these tools are not browsers.
When using Firebase Emulator Suite locally, CORS errors may occur because your frontend (localhost:3000) and emulated functions (localhost:5001) are on different origins. Configure CORS to allow localhost during development.
The wildcard origin (*) is convenient for development but should not be used in production. Instead, explicitly list allowed domains. If you need multiple subdomains, use a regex pattern in the cors middleware:
const corsHandler = cors({
origin: /^https:\/\/.*\.yourdomain\.com$/,
credentials: true
});For sensitive endpoints, always specify credentials: true and avoid using wildcard origins to prevent unauthorized access.
Callable Functions: INTERNAL - Unhandled exception
How to fix "Callable Functions: INTERNAL - Unhandled exception" in Firebase
auth/invalid-hash-algorithm: Hash algorithm doesn't match supported options
How to fix "auth/invalid-hash-algorithm: Hash algorithm doesn't match supported options" in Firebase
auth/reserved-claims: Custom claims use reserved OIDC claim names
How to fix "reserved claims" error when setting custom claims in Firebase
Callable Functions: UNAUTHENTICATED - Invalid credentials
How to fix "UNAUTHENTICATED - Invalid credentials" in Firebase Callable Functions
messaging/message-rate-exceeded: Overall sending rate too high
Overall sending rate too high in Firebase Cloud Messaging