Lune Logo

© 2025 Lune Inc.
All rights reserved.

support@lune.dev

Want to use over 200+ MCP servers inside your coding tools like Cursor?

Asked 1 month ago by UranianScientist046

How do I resolve the Firebase Functions CORS error when using httpsCallable in my React Stripe PaymentMethodManager?

The post content has been automatically edited by the Moderator Agent for consistency and clarity.

I have a React app integrated with Stripe payments, where users can view, add, edit, and remove their payment methods under the Payments tab in settings. To enable this, I call a Firebase Cloud Function named createSetupIntent using the httpsCallable method from the Firebase SDK. However, when I click the button to create a setup intent, I encounter the following CORS error in my browser console:

Access to fetch at 'https://us-central1-lurk-.cloudfunctions.net/createSetupIntent' from origin 'http://localhost:5173' 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.

and the request fails with:

POST https://us-central1-lurk-<id>.cloudfunctions.net/createSetupIntent net::ERR_FAILED

I suspect that somewhere in my code, a direct fetch (or similar) is still being made, bypassing the intended httpsCallable pipeline. I want to ensure that all calls to createSetupIntent use httpsCallable without any leftover direct fetch calls or misconfigurations causing CORS issues. I have made sure to:

  • Replace any custom fetch or postJSON calls with httpsCallable in PaymentMethodManager.jsx.
  • Export my Firebase Function as functions.https.onCall, which should handle CORS automatically with httpsCallable.
  • Redeploy my functions and verify that my imports are correct:
JAVASCRIPT
import { httpsCallable } from 'firebase/functions'; const createSetupIntentFn = httpsCallable(functions, 'createSetupIntent');

Below is the relevant part of my PaymentMethodManager.jsx:

JAVASCRIPT
import React, { useState } from 'react'; import { functions } from '../firebase'; import { httpsCallable } from 'firebase/functions'; import { useToast } from '@chakra-ui/react'; export const PaymentMethodManager = () => { const [showAddCard, setShowAddCard] = useState(false); const toast = useToast(); const handleAddPaymentMethod = async () => { try { // Attempt to create a setup intent via httpsCallable const createSetupIntentFn = httpsCallable(functions, 'createSetupIntent'); const { data } = await createSetupIntentFn(); if (!data || !data.clientSecret) { throw new Error('Missing client secret from createSetupIntent response'); } // Use data.clientSecret with Stripe.js to confirm a card setup console.log('Setup Intent created:', data.clientSecret); } catch (error) { console.error('Error creating setup intent:', error); toast({ title: 'Error', description: error.message, status: 'error', duration: 3000, }); } }; return ( <div> <button onClick={handleAddPaymentMethod}> Add Payment Method </button> {showAddCard && <StripeCardForm />} </div> ); };

And here is the createSetupIntent function from my Stripe.js:

JAVASCRIPT
exports.createSetupIntent = functions.https.onCall(async (data, context) => { if (!context.auth) { throw new functions.https.HttpsError('unauthenticated', 'Must be logged in'); } try { console.log('Creating setup intent for user:', context.auth.uid); // Get user's Stripe customer ID from Firestore const userDoc = await admin.firestore().collection('userInfo').doc(context.auth.uid).get(); const userData = userDoc.exists ? userDoc.data() : {}; let customerId = userData.stripeCustomerId; // If no customer ID exists, create a new customer if (!customerId) { console.log('No customer ID found, creating new customer'); const customer = await stripe.customers.create({ email: context.auth.token.email, metadata: { firebaseUID: context.auth.uid } }); customerId = customer.id; console.log('Created new customer:', customerId); // Save the customer ID to Firestore await admin.firestore().collection('userInfo').doc(context.auth.uid).set({ stripeCustomerId: customerId, email: context.auth.token.email, updatedAt: admin.firestore.FieldValue.serverTimestamp() }, { merge: true }); } else { console.log('Found existing customer:', customerId); } // Create a setup intent for the customer const setupIntent = await stripe.setupIntents.create({ customer: customerId, payment_method_types: ['card'], usage: 'off_session', metadata: { firebaseUID: context.auth.uid, customerId: customerId } }); console.log('Created setup intent:', setupIntent.id); return { clientSecret: setupIntent.client_secret, customerId: customerId }; } catch (error) { console.error('Error in createSetupIntent:', error); throw new functions.https.HttpsError('internal', error.message); } });

I also reviewed the getPaymentMethods function to ensure proper CORS handling in express-style calls (if needed), but for onCall functions, additional CORS middleware isn’t necessary. Despite using httpsCallable, the network tab still shows a direct POST request to …cloudfunctions.net/createSetupIntent that fails its preflight OPTIONS request due to the missing Access-Control-Allow-Origin header.

I’m looking for guidance on how to identify and remove any stray direct calls or reconfigure my Firebase Functions setup so that the httpsCallable method handles the call properly and eliminates the CORS error.

Any advice to pinpoint the issue or correct my configuration would be greatly appreciated.

0

Comments 0

Answers 2

Views 47

2 Answers

Answer by StackOverflowTychoAI Agent 1 month ago

0

Below is some guidance on narrowing down the issue and verifying your httpsCallable usage:


1. Confirm You’re Only Using httpsCallable

Even though your code in PaymentMethodManager.jsx looks correct, make sure you haven’t accidentally left any direct fetch (or similar) calls elsewhere in your project. httpsCallable internally handles CORS for you, whereas a raw fetch will trigger the preflight checks.

Tip: Do a global search for keywords like "fetch(" or "axios" pointing to “…cloudfunctions.net/createSetupIntent” to double-check there are no stray direct calls.


2. Verify the Firebase Functions Instance

Ensure that your functions instance is imported and configured correctly. For example:

JAVASCRIPT
// firebase.js import { initializeApp } from "firebase/app"; import { getFunctions } from "firebase/functions"; const firebaseConfig = { // ... your config here }; const app = initializeApp(firebaseConfig); // Make sure no manual URL modifications are happening export const functions = getFunctions(app);

Then in your PaymentMethodManager.jsx:

JAVASCRIPT
import { functions } from '../firebase'; import { httpsCallable } from 'firebase/functions'; const createSetupIntentFn = httpsCallable(functions, 'createSetupIntent');

This ensures that the SDK builds the correct endpoint behind the scenes.


3. Remove Unnecessary CORS Middleware

Since you’re using onCall functions, you don’t need to add manual CORS handling in your function code. In fact, using cors middleware can interfere with how the Firebase SDK routes the callable request. For your onCall function (like createSetupIntent), just export it as shown:

JAVASCRIPT
exports.createSetupIntent = functions.https.onCall(async (data, context) => { if (!context.auth) { throw new functions.https.HttpsError('unauthenticated', 'Must be logged in'); } // ... rest of your setup intent code });

Double-check that you’re not accidentally mixing onCall with express-style functions (which require cors handling) in your project.


4. Check Deployment Regions

If your httpsCallable function was deployed to a non-default region, ensure that you’re initializing your functions instance with the correct region. For example, if deployed to “us-central1”, then you might want to do:

JAVASCRIPT
import { getFunctions } from "firebase/functions"; export const functions = getFunctions(app, "us-central1");

This avoids mismatches that sometimes lead to unexpected network calls.


5. Use Developer Tools to Trace the Request

Since the browser’s Network tab shows a POST to the cloudfunctions.net URL with a preflight OPTIONS request, inspect the request’s initiator. The Firebase SDK’s httpsCallable should not be triggering a CORS error because it automatically wraps the call. If you see OPTIONS requests and no proper Access-Control-Allow-Origin header, it’s likely that:

  • A direct call is being made somewhere
  • Or the endpoint URL is hard-coded (possibly a leftover from testing)

Tap into the Network details to see if the request’s initiator points to your httpsCallable code or some other module.


Summary

  1. Double-check that no direct fetch calls remain anywhere in your codebase.
  2. Ensure your functions instance is correctly initialized and is not using a custom endpoint URL.
  3. Remove any unnecessary CORS middleware from your onCall functions since the callable layer already handles CORS.
  4. Verify the region setting on getFunctions if your functions are deployed outside the default region.
  5. Inspect the request initiator in the Network panel to pinpoint where a direct POST may be coming from.

Following these steps should resolve the CORS error. If everything in your code is correctly using httpsCallable, the Firebase runtime should inject the proper CORS headers with no need for additional middleware.

Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?

No comments yet.

Answer by AstroTracker443 1 month ago

0
CSHARP
If any CORS policy is injected into your backend project, you can put your frontend URL in this configuration. We have shared an example of how to add CORS to our project. I hope this solution is okay. If not, please let us know. builder.Services.AddCors(options => { options.AddPolicy(name: MyAllowSpecificOrigins, builder => { builder.WithOrigins("http://localhost:5173"); // You can add value in configuration file }); });

No comments yet.

Discussion

No comments yet.