NextAuth with Supabase Adapter

10 min read

Integrating NextAuth with Supabase Adapter in Next.js

If you're working on Next.js application and looking for a way to implement authentication, combining NextAuth with Supabase's Adapter offers a powerful and streamlined approach. This guide walks you through setting up NextAuth with Supabase to handle authentication in your Next.js application, additionally I'm going to show you how you can protect your routes!

Before we start, make sure you have:

Done? Let's get started!

Step 1: Install dependencies

First, we need to add NextAuth and the Supabase Adapter to our project. Run the following command in your project directory

pnpm add next-auth @auth/supabase-adapter

Step 2: Configure NextAuth

Create a route.ts file inside the app/api/auth[...nextauth] directory. This file will configure NextAuth and specify Supabase as the provider. In this tutorial we're gonna use Github Provider, you can use whatever provider you want.

import { SupabaseAdapter } from "@auth/supabase-adapter";
import type { NextAuthOptions } from "next-auth";
import GithubProvider from "next-auth/providers/github";
import jwt from "jsonwebtoken";

export const authOptions: NextAuthOptions = {
	adapter: SupabaseAdapter({
		url: process.env.SUPABASE_URL as string,
		secret: process.env.SUPABASE_SERVICE as string,
	}),
	providers: [
		GithubProvider({
			clientId: process.env.GITHUB_ID as string,
			clientSecret: process.env.GITHUB_SECRET as string,
		}),
	],

	callbacks: {
		async session({ session, user }) {
			const signingSecret = process.env.SUPABASE_JWT_SECRET;
			if (signingSecret) {
				const payload = {
					aud: "authenticated",
					exp: Math.floor(new Date(session.expires).getTime() / 1000),
					sub: user.id,
					email: user.email,
				};
				session.user.id = user.id;
				session.supabaseAccessToken = jwt.sign(payload, signingSecret);
			}
			return session;
		},
	},
};

const handler = NextAuth(authOptions);

export { handler as GET, handler as POST };

Step 3: Setting Up Environment Variables

You can find these details in your Supabase project settings under the API section:

SUPABASE_URL=
SUPABASE_SERVICE=
SUPABASE_JWT_SECRET=

GITHUB_ID=
GITHUB_SECRET=

Step 4: Using NextAuth for Authentication

With NextAuth and Supabase configured, you can now use NextAuth functions such as signIn, signOut, and useSession to manage user authentication in your application.

import { signIn, signOut, useSession } from "next-auth/react"

const Header = () => {
  const { data: session } = useSession()

  return (
    <header>
      {!session ? (
        <button onClick={() => signIn("github")}>Sign In</button>
      ) : (
        <button onClick={() => signOut()}>Sign Out</button>
      )}
    </header>
  )
}

Protecting Routes

To ensure that certain pages of your app are accessible only to logged-in users, you can protect your routes by checking the session status.

Client Side

"use client";

import { useSession } from "next-auth/react";
import { redirect } from "next/navigation";

export default function ProtectedClientPage() {
	const { data: session } = useSession({
		required: true,
		onUnauthenticated() {
			redirect("/signin");
		},
	});

	return (
		<section className="mt-20">
			<h1>Hello {session?.user.name}</h1>
		</section>
	);
};

Server Side

import { authOptions } from "@/app/api/auth/[...nextauth]/route";
import { getServerSession } from "next-auth";
import { redirect } from "next/navigation";

export default async function ProtectedServerPage()  {
	const session = await getServerSession(authOptions);

	if (!session) {
		redirect("/signin");
	}

	return (
		<section className="mt-20">
			<h1>Hello {session?.user.name}</h1>
		</section>
	);
};

Conclusion

Integrating NextAuth with Supabase in Next.js not only streamlines user authentication but also simplifies protecting your routes. This setup offers a robust yet user-friendly way to manage access to your app, ensuring both a smooth experience and enhanced security for your users.