[{"data":1,"prerenderedAt":177},["ShallowReactive",2],{"blog-blueprints/firebase-stripe":3},{"id":4,"title":5,"body":6,"category":157,"date":158,"dateModified":158,"description":159,"draft":160,"extension":161,"faq":162,"featured":160,"headerVariant":163,"image":162,"keywords":162,"meta":164,"navigation":165,"ogDescription":166,"ogTitle":162,"path":167,"readTime":168,"schemaOrg":169,"schemaType":170,"seo":171,"sitemap":172,"stem":173,"tags":174,"twitterCard":175,"__hash__":176},"blog/blog/blueprints/firebase-stripe.md","Firebase + Stripe Integration Security",{"type":7,"value":8,"toc":146},"minimark",[9,20,24,30,35,50,54,63,67,76,85,89,94,97,100,103,106,109,120,134],[10,11,12],"blueprint-summary",{},[13,14,15,19],"p",{},[16,17,18],"strong",{},"To secure Firebase + Stripe integration,"," you need to: (1) handle Stripe webhooks in Cloud Functions using rawBody for signature verification, (2) use Firebase Admin SDK to update Firestore subscription fields, (3) protect subscription fields in Security Rules so users cannot modify them, (4) link checkout sessions to Firebase UIDs, and (5) verify authentication in callable functions. This blueprint keeps payment state secure and server-authoritative.",[21,22],"blueprint-meta",{"time":23},"2-3 hours",[25,26,27],"tldr",{},[13,28,29],{},"Handle Stripe webhooks in Cloud Functions, not client-side. Verify webhook signatures, use Firebase Admin SDK to update Firestore, and protect subscription status with Security Rules. Never trust client payment confirmations.",[31,32,34],"h2",{"id":33},"webhook-cloud-function-firebase-stripe","Webhook Cloud Function Firebase Stripe",[36,37,39],"code-block",{"label":38},"functions/src/stripe.ts",[40,41,46],"pre",{"className":42,"code":44,"language":45},[43],"language-text","import * as functions from 'firebase-functions'\nimport Stripe from 'stripe'\nimport * as admin from 'firebase-admin'\n\nconst stripe = new Stripe(functions.config().stripe.secret_key)\nconst webhookSecret = functions.config().stripe.webhook_secret\n\nexport const stripeWebhook = functions.https.onRequest(async (req, res) => {\n  const signature = req.headers['stripe-signature'] as string\n\n  let event: Stripe.Event\n\n  try {\n    event = stripe.webhooks.constructEvent(\n      req.rawBody,\n      signature,\n      webhookSecret\n    )\n  } catch (err) {\n    console.error('Webhook signature verification failed')\n    res.status(400).send('Invalid signature')\n    return\n  }\n\n  const db = admin.firestore()\n\n  switch (event.type) {\n    case 'checkout.session.completed': {\n      const session = event.data.object as Stripe.Checkout.Session\n      await db.collection('users').doc(session.client_reference_id!).update({\n        stripeCustomerId: session.customer,\n        subscriptionStatus: 'active',\n        updatedAt: admin.firestore.FieldValue.serverTimestamp(),\n      })\n      break\n    }\n    case 'customer.subscription.deleted': {\n      const subscription = event.data.object as Stripe.Subscription\n      const userQuery = await db.collection('users')\n        .where('stripeCustomerId', '==', subscription.customer)\n        .get()\n\n      if (!userQuery.empty) {\n        await userQuery.docs[0].ref.update({\n          subscriptionStatus: 'canceled',\n        })\n      }\n      break\n    }\n  }\n\n  res.json({ received: true })\n})\n","text",[47,48,44],"code",{"__ignoreMap":49},"",[31,51,53],{"id":52},"create-checkout-callable-function","Create Checkout (Callable Function)",[36,55,57],{"label":56},"functions/src/checkout.ts",[40,58,61],{"className":59,"code":60,"language":45},[43],"import * as functions from 'firebase-functions'\nimport Stripe from 'stripe'\n\nconst stripe = new Stripe(functions.config().stripe.secret_key)\n\nexport const createCheckout = functions.https.onCall(async (data, context) => {\n  // Verify authentication\n  if (!context.auth) {\n    throw new functions.https.HttpsError('unauthenticated', 'Must be logged in')\n  }\n\n  const session = await stripe.checkout.sessions.create({\n    mode: 'subscription',\n    payment_method_types: ['card'],\n    line_items: [{ price: data.priceId, quantity: 1 }],\n    success_url: `${data.origin}/success`,\n    cancel_url: `${data.origin}/cancel`,\n    client_reference_id: context.auth.uid,  // Link to Firebase user\n  })\n\n  return { sessionId: session.id, url: session.url }\n})\n",[47,62,60],{"__ignoreMap":49},[31,64,66],{"id":65},"firestore-security-rules-firebase","Firestore Security Rules Firebase",[36,68,70],{"label":69},"firestore.rules",[40,71,74],{"className":72,"code":73,"language":45},[43],"rules_version = '2';\nservice cloud.firestore {\n  match /databases/{database}/documents {\n    match /users/{userId} {\n      // Users can read their own data\n      allow read: if request.auth.uid == userId;\n\n      // Users cannot modify subscription fields\n      allow update: if request.auth.uid == userId\n        && !request.resource.data.diff(resource.data)\n            .affectedKeys()\n            .hasAny(['subscriptionStatus', 'stripeCustomerId']);\n    }\n  }\n}\n",[47,75,73],{"__ignoreMap":49},[77,78,79],"warning-box",{},[13,80,81,84],{},[16,82,83],{},"Protect subscription fields in rules."," Users should never be able to modify their own subscription status. Only Cloud Functions with Admin SDK can update these fields.",[31,86,88],{"id":87},"security-checklist","Security Checklist",[90,91,93],"h4",{"id":92},"pre-launch-checklist","Pre-Launch Checklist",[13,95,96],{},"Webhook signatures verified",[13,98,99],{},"rawBody used for signature verification",[13,101,102],{},"Subscription fields protected in rules",[13,104,105],{},"Callable functions check auth",[13,107,108],{},"Checkout linked to Firebase UID",[110,111,112,117],"stack-comparison",{},[113,114,116],"h3",{"id":115},"related-integration-stacks","Related Integration Stacks",[13,118,119],{},"Supabase + Stripe Alternative\nStripe Webhooks Deep Dive\nCloudflare Workers Edge Security",[121,122,123,129],"related-articles",{},[124,125],"related-card",{"description":126,"href":127,"title":128},"Alternative backend","/blog/blueprints/supabase-stripe","Supabase + Stripe",[124,130],{"description":131,"href":132,"title":133},"Deep dive","/blog/blueprints/stripe-webhooks","Stripe Webhooks Guide",[135,136,139,143],"cta-box",{"href":137,"label":138},"/","Start Free Scan",[31,140,142],{"id":141},"check-your-payment-integration","Check Your Payment Integration",[13,144,145],{},"Scan for webhook and payment security issues.",{"title":49,"searchDepth":147,"depth":147,"links":148},2,[149,150,151,152,156],{"id":33,"depth":147,"text":34},{"id":52,"depth":147,"text":53},{"id":65,"depth":147,"text":66},{"id":87,"depth":147,"text":88,"children":153},[154],{"id":115,"depth":155,"text":116},3,{"id":141,"depth":147,"text":142},"blueprints","2026-02-04","Security guide for integrating Stripe payments with Firebase. Secure Cloud Function webhooks, verify signatures, sync subscription data, and protect payment flows.",false,"md",null,"purple",{},true,"Secure Stripe payment integration with Firebase backend.","/blog/blueprints/firebase-stripe","11 min read","[object Object]","Article",{"title":5,"description":159},{"loc":167},"blog/blueprints/firebase-stripe",[],"summary_large_image","6ssvMOzLbqMOExyXWiOkfDXeE__f4Z0yZJc2uSuIVNk",1775843932317]