Skip to content
Advertisement

Req.params and req.user missing after hitting stripe checkout flow

I’m trying to integrate Stripe subscriptions billing in my app with a tiered pricing model and based on my understanding, I need to do two things:

  1. Allow my new users to also create a stripe customer account (via the integration)
  2. Monitor Stripe webhook ‘events’ to provision access while customer subscription payments are active

My userflow is as follows:

  • create profile in my app (saved to database) -> redirected to stripe checkout portal for billing info (saved to stripe database) -> attempt to save stripe customerId to my database so I can monitor subscription status

However, I can’t figure out how to save the customerId info in my app because req.user and req.params are empty as the users are sent back to my app from the stripe billing portal

Controller function

module.exports.stripeWebhook = async (req, res) => {
    let data;
    const webhookSecret = stripeWebhookSecret;
         if (webhookSecret) {
      let event;
      let signature = req.headers["stripe-signature"];

      try {
        event = stripe.webhooks.constructEvent(
          req.body,
          signature,
          webhookSecret
        );
      } catch (err) {
        console.log(`⚠️  Webhook signature verification failed.`);
        return res.sendStatus(400);
      }
      data = event.data;
      eventType = event.type;
    } else {
      // retrieve the event data directly from the request body.
      data = req.body.data;
      eventType = req.body.type;
    }

    switch (eventType) {
        case 'payment_intent.succeeded': {
          console.log('PaymentIntent was successful!');
          break;
      }
    case 'checkout.session.completed':
          // Payment is successful and the subscription is created.
          // You should provision the subscription and save the customer ID to your database.
          console.log(data.object.customer);  <- works
          const user = await User.findById(req.user.id); <- comes back empty so my next two lines of code don't work
          user.stripeId.push(data.object.customer);
          await user.save();
      break;
        default:
      }
      res.sendStatus(200);
  };

App.js

app.use(bodyParser.raw({type: "application/json"}));
app.use(express.json({ limit: '1mb' }));
app.use(express.urlencoded({ extended: true }));

I included the app.js code because the bodyparser.raw has an impact on how the body comes through in my controller function.

I was counting on the req.user or req.params to find the user in my database but it’s not working. How do I save the customerId to my database like the stripe comments suggest?

Advertisement

Answer

You should create Stripe customer account before creating checkout session for the customer.

  1. Check if customer already have stripe_customer account (Stripe customer account). If yes, use that one. If not, create one for him and save it in database.

  2. Set stripe_customer for the checkout session, so customer will be automatically authenticated in the Stripe checkout

  3. You can optionally put user’s _id in the metadata of the Stripe checkout session, so you access that data later in the webhook.

Note: You should create one stripe_customer account for each currency. So one user can have multiple stripe_customer accounts, one for each currency.

router.post('/create-checkout-session', authenticate.verifyUser, async (req, res) => {
    const { currency } = req.body;

    ...

    // If user does not have stripe customer for order currency, create a new one.
    if (!(req.user.stripe_customer && req.user.stripe_customer[currency])) {
      const new_stripe_customer = await stripe.customers.create({
        email: req.user.email,
        metadata: {
          user_id: req.user._id.toString(),
        },
      });

      let update = {};
      update[`stripe_customer.${currency}`] = new_stripe_customer.id;
      await Users.findByIdAndUpdate(req.user._id, update);

      if (!req.user.stripe_customer) {
        req.user.stripe_customer = {};
        req.user.stripe_customer[currency] = new_stripe_customer.id;
      } else {
        req.user.stripe_customer[currency] = new_stripe_customer.id;
      }
    }

    ...

    // Set `stripe_customer` for checkout session.
    const session = await stripe.checkout.sessions.create({
      customer: req.user.stripe_customer[currency],
      ...
    });
 
    ...

}
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement