Supabase does not automatically set an auth cookie for our signed-in user. If we want to know who our user is on the server, we need to call supabase.auth.api.setAuthCookie
.
We will create an API route to set a Supabase auth cookie. Additionally, we modify our useUser
hook to call this endpoint anytime the state of our user changes. In order to make our HTTP requests slightly more readable, we install the axios
library.
Now that we have a cookie being automatically sent with every request, we can use the getUserByCookie
function to get the requesting user. If our API route requires a signed-in user, we can immediately send a 401
response if a user is not present.
We need to know our user's stripe_customer to initiate a checkout session with Stripe (next lesson), so need to enrich this user data with their profile.
While our request from the client to the API route contains our auth cookie, it is not automatically attached to server-side calls using our Supabase client.
Instructor: [0:00] When we click the Subscribe button, we want to call a function to process our subscription. We need to tell it which plan our user wants to subscribe to. We can create this function above. Here, we can make a request to an API route to handle charging our customer for that subscription.
[0:19] I'm going to install a library called Axios to do this. This is just because I prefer its API over the built-in Fetch library. We can import that above, and use it to call our endpoint at /api/subscription/our plan ID. We can then just console log the data that we get back. Now we can create our API route at subscription/, and I'm going to call this priceID, as that's what it maps to in Stripe.
[0:47] We can then create our handler function. The first thing we need to know is, which Stripe customer are we charging for this subscription. Unfortunately, Supabase doesn't set an auth cookie by default.
[1:00] If we want to know who our Supabase users are in our API routes, we just need to tell Supabase to set that auth cookie. Let's create another API route called setSupabaseCookie and declare our handler function.
[1:11] We want to import our Supabase client and call Supabase.auth.API.setauthcookie and pass it our request and our response. We then want to call this API route whenever the state of our user changes and so we can do that in our user provider.
[1:28] We want a second use effect that triggers whenever our user object changes. We're going to want to make another request here so let's import Axios. Then we want to make a post request to /API/setSupabaseCookie and pass it an object with the event.
[1:46] Which if we have a user, will be set to the string signed in, and otherwise, signed out. We also want to send the session, which will be Supabase.auth.session. We can then trigger this logic for our current user by logging out and back in.
[2:01] Then back in our subscription API route, we can import Supabase. Remember, we're three levels deep at the moment. We can then get our user from that cookie by saying Supabase.auth.API.getUser by cookie and passing it our request.
[2:18] If we don't actually have a user, then we want to send a response with the status code 401 and just the message unauthorized. We can send back the response, which will be our user object. If we open up the console, clear out what's there and click Subscribe, we'll see our user object.
[2:35] This is our Supabase user, and so won't contain any of the fields from our profile. To initiate our payment with Stripe, we need to know who the Stripe customer is. Let's get that from the profile table.
[2:46] If we try to send back our user object with our Stripe customer included, and trigger our API route, we get a big scary 500 error. This means something's gone wrong in our server.
[3:11] Let's have a look. This is saying, "Cannot read property, stripe_customer of NULL." That's because this request to Supabase is happening from our handler function, which is actually getting executed on the server, not the client. Supabase is not automatically passing that cookie across to tell us who that user is.
[3:28] Since we have row-level security enabled for the profile table, Supabase is not going to let us select that row, unless it knows that it's that user that's making the request.
[3:38] Let's install the cookie package. We can then import that at the top. Then, before we make a request to Supabase, we can extract the token by saying, cookie.pass, and passing it our request.headers.cookie, and then pulling out the sb:token.
[3:55] We can then set this to our Supabase session by saying, supabase.auth.session. This takes a function that returns an object with the key access token. We can set that to the token that we got from the cookie. Now when we trigger that API route, we get our user, but this time, including our Stripe customer.
Good call out! Thanks! 🙌
supabase.auth.session
is being reassigned to a function? In other areas, it's being called as a function. Not understanding this part..supabase.auth.session
is asking for a token_type
and user
req.headers.cookie &&
and if (token)
is added here const token = req.headers.cookie && cookie.parse(req.headers.cookie)['sb-access-token']
if (token) {
supabase.auth.session = () => ({
access_token: token,
token_type: 'Bearer',
user
})
}
Supabase now exposes a helper function called setAuth
for providing a custom access_token. Check out the docs for a full example, but basically we want to replace:
supabase.auth.session = () => ({
access_token: token,
});
with:
supabase.auth.setAuth(token)
https://supabase.com/docs/reference/javascript/auth-setauth
Note that
sb:token
should now besb-access-token
instead