Brenton Beltrami
Brenton Beltrami

Reputation: 413

Get supabase `user` server side in next.js

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?

Upvotes: 5

Views: 12269

Answers (6)

sharkwire
sharkwire

Reputation: 29

If you're using Next 14 am sure you're also using supabase.ssr Create a project using this command:

npx create-next-app@latest -e with-supabase

Install dependencies and run a dev server, you'll see how get user in the server and a lot more about supabase/ssr. I also recommend you read the docs for supabase/ssr.

Also check out this article: https://supabase.com/blog/supabase-is-now-compatible-with-nextjs-14

Upvotes: 0

user16942962
user16942962

Reputation:

UPDATE: 2023. Available now on Supabase Docs here

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

export default function Profile({ user }) {
  return <div>Hello {user.name}</div>
}

export const getServerSideProps = async (ctx) => {
  // Create authenticated Supabase Client
  const supabase = createServerSupabaseClient(ctx)
  // Check if we have a session
  const {
    data: { session },
  } = await supabase.auth.getSession()

  if (!session)
    return {
      redirect: {
        destination: '/',
        permanent: false,
      },
    }

  return {
    props: {
      initialSession: session,
      user: session.user,
    },
  }
}

Upvotes: -1

Jack Tsin
Jack Tsin

Reputation: 61

For anyone who tries to figure out how to get the user server side with the new @supabase/auth-helpers-nextjs, Michele gave the answer.

Just a note: If you're trying to get the user on nextJs's Middleware, instead of:

... req.cookies["sb-access-token"]

You have to use: req.cookies.get('sb-access-token')

For example:

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

const { user } = await supabaseServerClient({ req, res }).auth.api.getUser(req.cookies.get('sb-access-token'))

Upvotes: 2

Michele
Michele

Reputation: 101

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.

Upvotes: 2

FRowe8
FRowe8

Reputation: 11

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();

Upvotes: 1

Sreekesh Iyer
Sreekesh Iyer

Reputation: 101

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

Upvotes: 7

Related Questions