Get supabase `user` server side in next.js

Viewed 2664

I am attempting to get the current logged in supabase user while server side.

I have attempted to use const user = supabase.auth.user(); but I always get a null response.

I have also attempted const user = supabase.auth.getUserByCookie(req) but it also returns null. I think because I am not sending a cookie to the api when calling it from the hook.

I have tried passing the user.id from the hook to the api but the api is not receiving the parameters.

I also attempted this approach but the token is never fetched. It seems to not exist in req.cookies.

    let supabase = createClient(supabaseUrl, supabaseKey);
    let token = req.cookies['sb:token'];
    if (!token) {
        return 
    }
    let authRequestResult = await fetch(`${supabaseUrl}/auth/v1/user`, {
        headers: {
            'Authorization': `Bearer ${token}`,
            'APIKey': supabaseKey
        }
    });
`

Does anyone know how to get the current logged in user in server side code?

3 Answers

If you need to get the user in server-side, you need to set the Auth Cookie in the server using the given Next.js API.

// pages/api/auth.js
import { supabase } from "../path/to/supabaseClient/definition";

export default function handler(req, res) {
    if (req.method === "POST") {
        supabase.auth.api.setAuthCookie(req, res);
    } else {
        res.setHeader("Allow", ["POST"]);
        res.status(405).json({
            message: `Method ${req.method} not allowed`,
        });
    }
}

This endpoint needs to be called every time the state of the user is changed, i.e. the events SIGNED_IN and SIGNED_OUT

You can set up a useEffect in _app.js or probably in a User Context file.

// _app.js

import "../styles/globals.css";
import { supabase } from '../path/to/supabaseClient/def'

function MyApp({ Component, pageProps }) {

    useEffect(() => {
    const { data: authListener } = supabase.auth.onAuthStateChange((event, session) => {
      handleAuthChange(event, session)
      if (event === 'SIGNED_IN') {
         // TODO: Actions to Perform on Sign In
      }
      if (event === 'SIGNED_OUT') {
         // TODO: Actions to Perform on Logout
      }
    })
    checkUser()
    return () => {
      authListener.unsubscribe()
    }
  }, [])

    return <Component {...pageProps} />;
}

async function handleAuthChange(event, session) {
    await fetch('/api/auth', {
      method: 'POST',
      headers: new Headers({ 'Content-Type': 'application/json' }),
      credentials: 'same-origin',
      body: JSON.stringify({ event, session }),
    })
  }

export default MyApp;

You can now handle this user with a state and pass it to the app or whichever way you'd like to.

You can get the user in the server-side in any Next.js Page

// pages/user_route.js

import { supabase } from '../path/to/supabaseClient/def'

export default function UserPage ({ user }) {

  return (
    <h1>Email: {user.email}</h1>
  )

}

export async function getServerSideProps({ req }) {
  const { user } = await supabase.auth.api.getUserByCookie(req)

  if (!user) {
    return { props: {}, redirect: { destination: '/sign-in' } }
  }

  return { props: { user } }
}

Here's a YouTube Tutorial from Nader Dabit - https://www.youtube.com/watch?v=oXWImFqsQF4
And his GitHub Repository - https://github.com/dabit3/supabase-nextjs-auth

supabase have a library of helpers for managing auth for both client- and server-side auth and fetching in a couple of frameworks including Next.js: https://github.com/supabase/auth-helpers and appears to be the recommended solution for similar problems based on this thread: https://github.com/supabase/supabase/issues/3783

This is how I'm using it in an API handler, but provided you have access to req, you can access the user object this way:

import { supabaseServerClient } from '@supabase/auth-helpers-nextjs';

const { user } = await supabaseServerClient({ req, res }).auth.api.getUser(req.cookies["sb-access-token"]);

Note that you will need to use the helper library supabaseClient and supabaseServerClient on the client and server side respectively for this to work as intended.

I was following a tutorial today and was having a similar issue and the below is how i managed to fix it.

I've got this package installed github.com/jshttp/cookie which is why i'm calling cookie.parse.

Supabase Instance:

`//../../../utils/supabase`

import { createClient } from "@supabase/supabase-js";

export const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_KEY
);

In my case this was my API page:

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

const handler = async (req, res) => {
const { user } = await supabase.auth.api.getUserByCookie(req);

  if (!user) {
    return res.status(401).send("Unathorized");
  }

  const token = cookie.parse(req.headers.cookie)["sb-access-token"];

  supabase.auth.session = () => ({
    access_token: token,
   });`

  const {
    data: { stripe_customer },
  } = await supabase
    .from("profile")
    .select("stripe_customer")
    .eq("id", user.id)
    .single();
Related