Payments Preflight · Check 11 of 15

Let customers manage billing safely

Use the Stripe customer portal for card updates, plan changes and cancellation. Create portal sessions on the server for the signed-in user's own customer id.

What it is

The customer portal is a Stripe-hosted page where customers update payment methods, view invoices and change or cancel subscriptions. You create a short-lived portal session on your server.

Why it matters

Building your own billing UI is extra surface for bugs. And if your portal route takes a customer id from the request, one user can open another user's billing.

How to check

How to fix it

  1. Look up the customer id from your database for the authenticated user. Never accept it from the client.
  2. Configure allowed actions in the Dashboard and set a return_url.
  3. Keep handling subscription webhooks, because changes made in the portal arrive that way.
const user = await requireUser(req); // your auth
const portal = await stripe.billingPortal.sessions.create({
  customer: user.stripeCustomerId, // from your DB, not the request
  return_url: `${origin}/account`,
});
return Response.redirect(portal.url, 303);

Prompt for your AI coding tool

Paste into Cursor, Claude Code, Lovable or similar. Review the diff before you accept it.

Review my Stripe customer portal route. It must require an authenticated user, look up that user's Stripe customer id from the database, never accept a customer id from the request, and create the billing portal session with a return_url. Confirm subscription changes from the portal are handled by my webhook. Show the diff.

Sources

Related checks

All payments checks

Sponsor this page: get in touch.

Get new checks by email

New checks and real leak post-mortems, about once a month. No spam.