Store API Key in Firebase Function

0

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

Before we begin, make sure you have the following tools and accounts ready:

  • 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 includes npm (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 inpackage.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:

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.

Previous articleFlutter Flavors Setup For Android and IOS
Next articleFlutter Firebase Setup for Android and IOS

LEAVE A REPLY

Please enter your comment!
Please enter your name here