firebase / firebase-functions

Firebase SDK for Cloud Functions
https://firebase.google.com/docs/functions/
MIT License
1.02k stars 201 forks source link

[Cloudfunctions V2] Error: Cannot access the value of secret "STRIPE_SECRET_KEY" during function deployment. Secret values are only available at runtime. #1483

Closed Patrick386 closed 10 months ago

Patrick386 commented 10 months ago

I registered the key using the command line or Secret Manager. I'm unable to retrieve the key in my Cloud Function. Please refer to the error message below. How can I fetch the key value?

Functions

import {Response} from 'express';
import * as functions from "firebase-functions/v2";

import {defineSecret} from "firebase-functions/params";
import {setGlobalOptions} from "firebase-functions/v2";
import Stripe from "stripe";

const stripeSecretKey = defineSecret("STRIPE_SECRET_KEY");
const stripeWebhookSecretKey = defineSecret("STRIPE_WEBHOOK_SECRET_KEY");

const stripe = new Stripe(stripeSecretKey.value(), {
    apiVersion: "2023-10-16",
    typescript: true,
});

exports.stripePaymentIntent = functions
    .https.onRequest( (request, response) => {
        // defined elsewhere
        return paymentIntent(request, response);
    });

async function paymentIntent(req: functions.https.Request, res: Response) {
    // get the first secret key value
    const secretKey = stripeSecretKey.value();
    // if it's empty, throw an error
    if (secretKey.length === 0) {
        console.error("⚠️ Stripe Secret Key is not set");
        res.sendStatus(400);
    }
    // get the second secret key value
    const webhookSecretKey = stripeWebhookSecretKey.value();
    // if it's empty, throw an error
    if (webhookSecretKey.length === 0) {
        console.error("⚠️ Stripe webhook secret is not set");
        res.sendStatus(400);
    }

    try {
        let customerId;
        const customerList = await stripe.customers.list({
            email: req.body.email,
            limit: 1,
        });

        if (customerList.data.length !== 0) {
            customerId = customerList.data[0].id;
        } else {
            const customer = await stripe.customers.create({email: req.body.email});
            customerId = customer.id;
        }
        const ephemeralKey = await stripe.ephemeralKeys.create(
            {customer: customerId}, {apiVersion: "2023-10-16"}
        );

        const paymentIntent = await stripe.paymentIntents.create({
            amount: parseInt(req.body.amount),
            currency: req.body.currency,
            customer: customerId,
        });

        res.status(200).send({
           paymentIntent: paymentIntent.client_secret,
            ephemeralKey: ephemeralKey.secret,
            success: true,
        });
    } catch (e) {
       res.status(404).send({success: false, error: e});
    }
}
Error: Cannot access the value of secret "STRIPE_SECRET_KEY" during function deployment. Secret values are only available at runtime.
    at SecretParam.value (/Users/patrick386/development/pronto_functions/functions/node_modules/firebase-functions/lib/params/types.js:248:19)
    at Object.<anonymous> (/Users/patrick386/development/pronto_functions/functions/lib/_sevice/stripe/stripe_api.js:14:53)
    at Module._compile (node:internal/modules/cjs/loader:1218:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1272:10)
    at Module.load (node:internal/modules/cjs/loader:1081:32)
    at Module._load (node:internal/modules/cjs/loader:922:12)
    at Module.require (node:internal/modules/cjs/loader:1105:19)
    at require (node:internal/modules/cjs/helpers:103:18)
    at Object.<anonymous> (/Users/patrick386/development/pronto_functions/functions/lib/index.js:82:14)
    at Module._compile (node:internal/modules/cjs/loader:1218:14)

Error: Functions codebase could not be analyzed successfully. It may have a syntax or runtime error
스크린샷 2023-11-08 오후 6 46 34

https://firebase.google.com/docs/functions/2nd-gen-upgrade#special_case_api_keys

robert-mccausland commented 10 months ago

I have a similar issue, I need variables to be defined during function deployment to I can configure third party dependencies - also this looks like people are having the same problem in this issue: https://github.com/firebase/firebase-functions/issues/1342

I think this specific use case could be fixed by moving the following code to run inside the function itself:

const stripe = new Stripe(stripeSecretKey.value(), {
    apiVersion: "2023-10-16",
    typescript: true,
});
blidd-google commented 10 months ago

The parametrized configuration of secrets is indeed working as intended here - Params cannot be accessed at load time during function deployment. @robert-mccausland's suggestion is correct in that you can initialize the Stripe client at runtime if you place the initialization code inside the function. If you'd like a singleton client object, you can define a global stripe variable and assign the initialized client object upon the first invocation of stripePaymentIntent.