Sam Donaghy-Bell
Sam Donaghy-Bell

Reputation: 35

Supabase and Stripe Customer ID with RLS

In a NextJS project I'm trying to add a stripe_customer_id to a Supabase user when they first sign up.

I can get this working fine when RLS isn't enabled but I need RLS to hide user data from anyone who isn't authenticated.

Can anyone help with what RLS policy I need to write to allow the create-stripe-customer api to update the customer_id column in Supabase?

Below is the create-stripe-customer (the file that works when RLS isn't enabled but not when RLS is enabled)

import initStripe from "stripe";
import { supabase } from "../../utils/supabaseClient";

const handler = async (req, res) => {

  if (req.query.API_ROUTE_SECRET !== process.env.API_ROUTE_SECRET) {
    return res.status(401).send('You are not authorized to call the API');
  }

  const stripe = initStripe(process.env.STRIPE_SECRET_KEY);

  const customer = await stripe.customers.create({
    email: req.body.record.email,
  });

  console.log("REQUEST-", req.body.record.id);
  console.log("CUST ID-", customer.id);

  await supabase
    .from("profiles")
    .update({
      stripe_customer: customer.id,
    })
    .eq("id", req.body.record.id);

  res.send({ message: `stripe customer creaded: ${customer.id}` });

  console.log("TESTTESTTEST");
};

export default handler;

Upvotes: 0

Views: 1149

Answers (2)

thorwebdev
thorwebdev

Reputation: 1152

To append to this, you should store the Stripe customer ID in a private table that only your SERVICE_ROLE key can access. The client-side, even if the user is authenticated, should never be able to modify this, as they could change their own customer ID.

So make sure to store this in a secure table that only your server-side code can access.

Create a private mapping table: https://github.com/vercel/nextjs-subscription-payments/blob/main/schema.sql#L34-L45

/**
* CUSTOMERS
* Note: this is a private table that contains a mapping of user IDs to Stripe customer IDs.
*/
create table customers (
  -- UUID from auth.users
  id uuid references auth.users not null primary key,
  -- The user's customer ID in Stripe. User must not be able to update this.
  stripe_customer_id text
);
alter table customers enable row level security;
-- No policies as this is a private table that the user must not have access to.

Use your SERVICE_ROLE key in a secure server side environment to access this private table: https://github.com/vercel/nextjs-subscription-payments/blob/main/utils/supabase-admin.ts#L7-L12

// Note: supabaseAdmin uses the SERVICE_ROLE_KEY which you must only use in a secure server-side context
// as it has admin priviliges and overwrites RLS policies!
const supabaseAdmin = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL || '',
  process.env.SUPABASE_SERVICE_ROLE_KEY || ''
);

Upvotes: 1

dshukertjr
dshukertjr

Reputation: 18680

When updating data on Supabase, using the service role key instead of the anon key to create Supabase client will allow you to bypass row-level security policies.

You can find your service role key just below your anon key in your Supabase dashboard. Here is a video explaining how to use service role key to bypass RLS. https://egghead.io/lessons/supabase-use-the-supabase-service-key-to-bypass-row-level-security

Upvotes: 1

Related Questions