[{"data":1,"prerenderedAt":163},["ShallowReactive",2],{"blog-blueprints/supabase-stripe":3},{"id":4,"title":5,"body":6,"category":143,"date":144,"dateModified":144,"description":145,"draft":146,"extension":147,"faq":148,"featured":146,"headerVariant":149,"image":148,"keywords":148,"meta":150,"navigation":151,"ogDescription":152,"ogTitle":148,"path":153,"readTime":154,"schemaOrg":155,"schemaType":156,"seo":157,"sitemap":158,"stem":159,"tags":160,"twitterCard":161,"__hash__":162},"blog/blog/blueprints/supabase-stripe.md","Supabase + Stripe Integration Security",{"type":7,"value":8,"toc":133},"minimark",[9,20,24,30,35,50,54,63,72,76,81,84,87,90,93,96,107,121],[10,11,12],"blueprint-summary",{},[13,14,15,19],"p",{},[16,17,18],"strong",{},"To secure Supabase + Stripe integration,"," you need to: (1) handle all Stripe webhooks in Supabase Edge Functions with signature verification, (2) use the service role key only in Edge Functions for subscription updates, (3) link checkout sessions to Supabase user IDs via client_reference_id, (4) enforce RLS on subscription tables, and (5) never trust client-side payment confirmations. This blueprint ensures payment state stays server-authoritative.",[21,22],"blueprint-meta",{"time":23},"2-3 hours",[25,26,27],"tldr",{},[13,28,29],{},"Stripe webhooks are your source of truth for payment state-never trust client-side payment confirmations. Use Supabase Edge Functions for webhook handling, verify signatures on every request, and use the service key only in Edge Functions to update subscription status.",[31,32,34],"h2",{"id":33},"webhook-handler-edge-function-supabase-stripe","Webhook Handler (Edge Function) Supabase Stripe",[36,37,39],"code-block",{"label":38},"supabase/functions/stripe-webhook/index.ts",[40,41,46],"pre",{"className":42,"code":44,"language":45},[43],"language-text","import Stripe from 'stripe'\nimport { createClient } from '@supabase/supabase-js'\n\nconst stripe = new Stripe(Deno.env.get('STRIPE_SECRET_KEY')!)\nconst webhookSecret = Deno.env.get('STRIPE_WEBHOOK_SECRET')!\n\nDeno.serve(async (req) => {\n  const signature = req.headers.get('stripe-signature')!\n  const body = await req.text()\n\n  let event: Stripe.Event\n\n  try {\n    event = stripe.webhooks.constructEvent(body, signature, webhookSecret)\n  } catch (err) {\n    console.error('Webhook signature verification failed')\n    return new Response('Invalid signature', { status: 400 })\n  }\n\n  // Use service key for admin operations\n  const supabase = createClient(\n    Deno.env.get('SUPABASE_URL')!,\n    Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!\n  )\n\n  switch (event.type) {\n    case 'checkout.session.completed': {\n      const session = event.data.object as Stripe.Checkout.Session\n      await supabase.from('subscriptions').upsert({\n        user_id: session.client_reference_id,\n        stripe_customer_id: session.customer,\n        status: 'active',\n      })\n      break\n    }\n    case 'customer.subscription.deleted': {\n      const subscription = event.data.object as Stripe.Subscription\n      await supabase.from('subscriptions').update({\n        status: 'canceled',\n      }).eq('stripe_customer_id', subscription.customer)\n      break\n    }\n  }\n\n  return new Response(JSON.stringify({ received: true }))\n})\n","text",[47,48,44],"code",{"__ignoreMap":49},"",[31,51,53],{"id":52},"creating-checkout-sessions","Creating Checkout Sessions",[36,55,57],{"label":56},"supabase/functions/create-checkout/index.ts",[40,58,61],{"className":59,"code":60,"language":45},[43],"import Stripe from 'stripe'\nimport { createClient } from '@supabase/supabase-js'\n\nconst stripe = new Stripe(Deno.env.get('STRIPE_SECRET_KEY')!)\n\nDeno.serve(async (req) => {\n  // Verify user auth\n  const authHeader = req.headers.get('Authorization')!\n  const supabase = createClient(\n    Deno.env.get('SUPABASE_URL')!,\n    Deno.env.get('SUPABASE_ANON_KEY')!,\n    { global: { headers: { Authorization: authHeader } } }\n  )\n\n  const { data: { user } } = await supabase.auth.getUser()\n  if (!user) {\n    return new Response('Unauthorized', { status: 401 })\n  }\n\n  const session = await stripe.checkout.sessions.create({\n    mode: 'subscription',\n    payment_method_types: ['card'],\n    line_items: [{ price: 'price_xxx', quantity: 1 }],\n    success_url: `${req.headers.get('origin')}/success`,\n    cancel_url: `${req.headers.get('origin')}/cancel`,\n    client_reference_id: user.id,  // Link to Supabase user\n  })\n\n  return new Response(JSON.stringify({ url: session.url }))\n})\n",[47,62,60],{"__ignoreMap":49},[64,65,66],"warning-box",{},[13,67,68,71],{},[16,69,70],{},"Never trust client payment confirmations."," Users can manipulate client-side code. Only update subscription status from verified webhook events.",[31,73,75],{"id":74},"security-checklist","Security Checklist",[77,78,80],"h4",{"id":79},"pre-launch-checklist","Pre-Launch Checklist",[13,82,83],{},"Webhook signatures verified",[13,85,86],{},"Service key only in Edge Functions",[13,88,89],{},"Subscription status from webhooks only",[13,91,92],{},"RLS on subscriptions table",[13,94,95],{},"Checkout session linked to user",[97,98,99,104],"stack-comparison",{},[100,101,103],"h3",{"id":102},"related-integration-stacks","Related Integration Stacks",[13,105,106],{},"Stripe Webhooks Deep Dive\nFirebase + Stripe Alternative\nOAuth Security Patterns",[108,109,110,116],"related-articles",{},[111,112],"related-card",{"description":113,"href":114,"title":115},"Deep dive","/blog/blueprints/stripe-webhooks","Stripe Webhooks Guide",[111,117],{"description":118,"href":119,"title":120},"Alternative backend","/blog/blueprints/firebase-stripe","Firebase + Stripe",[122,123,126,130],"cta-box",{"href":124,"label":125},"/","Start Free Scan",[31,127,129],{"id":128},"check-your-payment-integration","Check Your Payment Integration",[13,131,132],{},"Scan for webhook and payment security issues.",{"title":49,"searchDepth":134,"depth":134,"links":135},2,[136,137,138,142],{"id":33,"depth":134,"text":34},{"id":52,"depth":134,"text":53},{"id":74,"depth":134,"text":75,"children":139},[140],{"id":102,"depth":141,"text":103},3,{"id":128,"depth":134,"text":129},"blueprints","2026-02-11","Security guide for integrating Stripe payments with Supabase. Secure webhook handling, verify signatures, sync subscription data safely, and protect payment flows.",false,"md",null,"purple",{},true,"Secure Stripe payment integration with Supabase backend.","/blog/blueprints/supabase-stripe","11 min read","[object Object]","Article",{"title":5,"description":145},{"loc":153},"blog/blueprints/supabase-stripe",[],"summary_large_image","4X51DTgxf_pqSfUrb_UOrynr_d36spIsO1r_N4rmIYU",1775843932074]