Store your Stripe secret key or API Key in a Firebase function as a backend?
Security is crucial when developing an app that takes payments for goods, services, or subscriptions. Stripe is one of the most well-known and developer-friendly payment systems.
However, a common error made by beginners is to use Stripe’s secret key (sk_…) directly in the frontend, which is very dangerous. Anyone with that key could fabricate charges or worse.
In this guide, we’ll learn how to safely store your Stripe secret-key
using Firebase Cloud Functions. This method keeps your secret key secure on the backend — never exposed to the client side — so your app (whether it’s Flutter, web, or mobile) only talks to a safe, serverless API. That way, you can focus on building your app with peace of mind, knowing your keys are protected.
In this article, we are going to discuss how we can store a Stripe Secret Key in a Firebase Function; the process will be the same for all
Prerequisites
Before we begin, make sure you have the following tools and accounts ready:
✅ Accounts
- Firebase Project: Create one at console.firebase.google.com.
- Stripe Account: Sign up at stripe.com to get your secret API key
Create a Both account if you have not created at. At the latest update of Firebase, you need to upgrade your plan to use a Firebase Cloud Function.
- Node.js: Required to run Firebase Functions. If you don’t have Node.js on your system, then add the latest stable version greater than v20. Check the version with this command
node --version
. Also, install npm if not installed. When you install Node.js, it includesnpm (Node Package Manager) by default. Check it with this command
npm — v
.


Step-by-Step Process to Set Up Firebase Functions and Store Stripe Secret Key:
Step 1: Install Firebase CLI
If not already installed, install the Firebase CLI.
npm install -g firebase-tools
Verify installation:
firebase --version
Log in to Firebase:
firebase login
This opens a browser for authentication with your Google account if you are not logged in yet, or shows your email address if you are already logged in.
Step 2: Initialize Firebase Functions
Since you’ve used FlutterFire CLI, your project likely has a firebase.json file, but may not have a functions directory fully set up. Navigate to your project root and initialize Cloud Functions:
firebase init functions
- Select your Firebase project when prompted.
- Choose JavaScript as the language for Cloud Functions.
- Choose to install dependencies with npm.
- This creates a functions directory with:
—index.js
Main Cloud Functions file.
—package.json
Dependency configuration.
—eslintrc.js
and other config files.
Step 3 — Store Stripe Secret Key in Firebase Config
To securely store the Stripe secret key, first set the environment variable:
firebase functions:config:set stripe.secret_key="sk_test_your_key_here"
Verify whether the configuration is set or not
firebase functions:config:get
If your Expected output is like this, then confirm it is configured.
{ "stripe": { "secret_key": "sk_test_your_stripe_secret_key" } }
Additionally, watch the Stripe payment integration in Flutter
Step 4 — Write Your
index.js File
Replace your original index.js code with this code:
require("dotenv").config(); // Load .env file
const functions = require("firebase-functions");
const express = require("express");
const admin = require("firebase-admin");
const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY ||
functions.config().stripe.secret_key,
);
// Initialize Firebase Admin
admin.initializeApp();
const app = express();
// Enable CORS
app.use((req, res, next) => {
res.set("Access-Control-Allow-Origin", "*");
res.set("Access-Control-Allow-Methods", "POST, OPTIONS");
res.set("Access-Control-Allow-Headers", "Content-Type, Authorization");
if (req.method === "OPTIONS") {
res.status(204).send("");
return;
}
next();
});
// Parse JSON bodies
app.use(express.json());
// Main endpoint: /createPaymentIntent
app.post("/createPaymentIntent", async (req, res) => {
try {
// Get and parse Authorization header
const authHeader = req.headers.authorization || "";
const idToken = authHeader.startsWith("Bearer ") ?
authHeader.split("Bearer ")[1] :
null;
let uid = "guest";
// Optional: Verify token if present
if (idToken) {
try {
const decodedToken = await admin.auth().verifyIdToken(idToken);
uid = decodedToken.uid;
console.log("Verified UID:", uid);
} catch (err) {
console.warn("Invalid token, continuing as guest");
}
} else {
console.log("No auth token provided,continuing as guest");
}
// Extract Stripe payment details from body
const {amount, currency, paymentMethodTypes} = req.body;
// Create Stripe Payment Intent
const paymentIntent = await stripe.paymentIntents.create({
amount: parseInt(amount),
currency: currency.toLowerCase(),
payment_method_types: paymentMethodTypes || ["card"],
metadata: {
uid: uid,
},
});
// Respond with client secret
res.status(200).json({client_secret: paymentIntent.client_secret});
} catch (error) {
console.error("Error in createPaymentIntent:", error.message);
res.status(500).json({error: error.message});
}
});
// ✅ Export the function (DO NOT start app.listen() manually!)
exports.createPaymentIntent = functions.https.onRequest(app);
After you have added all these conditions to your index.js file, you need to format this code. If you try to deploy it without formatting, you will get an error. To format it, go to your functions directory of your project and run these three commands.
cd functions
npm run lint -- --fix
cd ..
Local testing support with .env(Optional)
Create .env
in functions/
STRIPE_SECRET_KEY=sk_test_...(your secret stripe key)
Now you can run the emulator for local testing by using this command
firebase emulators:start --only functions
Step 5— Add the required package in
package.json File
Replace your original package.json code with this code, where we have added all the packages.
{
"name": "functions",
"description": "Cloud Functions for Firebase",
"scripts": {
"lint": "eslint .",
"serve": "firebase emulators:start --only functions",
"shell": "firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"engines": {
"node": "22"
},
"main": "index.js",
"dependencies": {
"dotenv": "^17.2.0",
"express": "^4.21.2",
"firebase-admin": "^13.4.0",
"firebase-functions": "^6.3.2",
"stripe": "^18.3.0"
},
"devDependencies": {
"@eslint/js": "^9.0.0",
"eslint": "^8.15.0",
"eslint-config-google": "^0.14.0",
"firebase-functions-test": "^3.1.0",
"globals": "^15.0.0"
},
"private": true
}
Step 6: Add dotenv to your system
Run this command in the function directory:
cd functions
npm install dotenv
Create a .env file inside the functions folder and add your STRIPE_SECRET_KEY for local testing. (.env file is not deployed during app public)
STRIPE_SECRET_KEY=sk_test_51Rhk0S07xSw69OWloXCe4UwuyqNQLz3...(your api key)
Step 7: Deploy the function
From the root of your project, run:
firebase deploy --only functions
If it is successfully deployed, then it looks like this on VS Code:

Firebase console after successfully deploying:

Conclusion
Integrating payments into your app doesn’t have to be daunting. However, it is crucial to do it securely.
In this article, we explored how to integrate Stripe with Firebase Cloud Functions while maintaining the security of your secret keys and keeping your backend clean. We started from scratch, set everything up correctly, and addressed those tricky deployment errors that can confuse beginners, such as the Express v5 issue in Firebase’s 2nd Gen functions.
By using this method, you are not just creating a payment system. You are also building trust with your users.
Whether you are developing a Flutter app, a web platform, or something in between, this setup provides a strong foundation for secure and scalable Stripe integration.
If this article helped you, feel free to share it with others who might be struggling to store an API Key in a Firebase Function. And if you want to see more content like this — especially focused on Flutter, Firebase, and real-world app architecture — check out my YouTube channel, WTF Code.
Let’s keep building smart, secure apps.