Supabase Auth With Next.js 15: A Comprehensive Guide
Hey everyone! Today, we're diving deep into setting up Supabase authentication in a Next.js 15 application. If you're looking to add user authentication to your Next.js project, you've come to the right place. We'll walk through the entire process step-by-step, ensuring you have a solid understanding of how everything works. Let's get started!
What is Supabase and Why Use It With Next.js 15?
Supabase is an open-source Firebase alternative that provides a suite of tools to help you build scalable and secure applications. It offers features like a Postgres database, authentication, real-time subscriptions, and storage. Combining Supabase with Next.js 15 gives you a powerful and flexible stack for building modern web applications. Next.js on the other hand, is a React framework that enables functionalities such as server-side rendering and static site generation. This combination allows developers to create fast, SEO-friendly, and dynamic web applications with ease.
Why should you use Supabase with Next.js 15? There are several compelling reasons:
- Simplified Authentication: Supabase Auth handles all the complexities of user authentication, including signup, sign-in, password reset, and social logins. This saves you valuable development time and reduces the risk of security vulnerabilities.
- Real-time Data: Supabase's real-time capabilities allow you to build interactive and engaging user experiences. With Next.js 15, you can efficiently manage and display this data in your application.
- Scalability: Supabase is built on top of Postgres, a robust and scalable database. This ensures that your application can handle a growing number of users and data without performance bottlenecks.
- Developer-Friendly: Both Supabase and Next.js have excellent documentation and active communities, making it easy to find solutions to any problems you encounter. The developer experience is really smooth, allowing you to focus on building features rather than wrestling with infrastructure.
- Enhanced Security: Supabase's authentication system includes built-in security measures such as JWT (JSON Web Tokens) and secure password hashing. These features protect your application and user data from common security threats. Integrating Supabase with Next.js also allows you to leverage Next.js's security features, creating a secure and robust application environment.
By leveraging these benefits, you can build powerful and efficient applications with enhanced user authentication and data management capabilities. This makes the combination of Supabase and Next.js a go-to choice for modern web development projects.
Setting Up Your Next.js 15 Project
First things first, let's set up a new Next.js 15 project. If you already have one, you can skip this step. Open your terminal and run the following command:
npx create-next-app@latest supabase-nextjs-auth
This command uses the create-next-app tool to scaffold a new Next.js project named supabase-nextjs-auth. You'll be prompted to answer a few questions about your project setup. Here’s a typical configuration:
- Would you like to use TypeScript? Yes
- Would you like to use ESLint? Yes
- Would you like to use Tailwind CSS? Yes (or No, depending on your preference)
- Would you like to use
src/directory? Yes - Would you like to use App Router? Yes
- Would you like to customize the default import alias? No
Once the project is created, navigate into the project directory:
cd supabase-nextjs-auth
Now, let’s install the necessary dependencies. We'll need the Supabase client library and the @supabase/auth-helpers-nextjs package to simplify authentication handling in Next.js:
npm install @supabase/supabase-js @supabase/auth-helpers-nextjs
Or, if you prefer using Yarn:
yarn add @supabase/supabase-js @supabase/auth-helpers-nextjs
These packages will provide the tools and utilities needed to interact with Supabase and manage user authentication within your Next.js application efficiently. With these dependencies installed, you're well-prepared to start integrating Supabase authentication into your project. Ensure you have these set up correctly before moving on to the next steps, as they are crucial for the proper functioning of your authentication flow.
Setting Up Your Supabase Project
Next, you'll need to set up a Supabase project. Head over to Supabase and create an account if you don't already have one. Once you're logged in, create a new project.
- Create a New Project: Click on the "New Project" button. Give your project a name, choose a database password, and select a region. Make sure to choose a region that's geographically close to your users for the best performance.
- Wait for Project Initialization: Supabase will take a few minutes to set up your project. Once it's ready, you'll be able to access your project dashboard.
- Retrieve API Keys: In your project dashboard, go to the "Settings" tab and then to "API". Here, you'll find your Supabase URL and anon key. You'll need these to connect your Next.js application to your Supabase project. Keep these keys secure and avoid exposing them in client-side code.
Now, let's add the Supabase URL and anon key to your Next.js project as environment variables. Create a .env.local file in the root of your Next.js project and add the following:
NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
Replace your_supabase_url and your_supabase_anon_key with the actual values from your Supabase project. Remember to restart your Next.js development server after adding these environment variables to ensure they are loaded correctly.
Creating the Supabase Client
Now that we have our Supabase project set up and our API keys ready, let's create a Supabase client in our Next.js application. This client will be used to interact with the Supabase API.
Create a new file named supabaseClient.js (or .ts if you're using TypeScript) in your src directory. Add the following code:
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
if (!supabaseUrl || !supabaseAnonKey) {
throw new Error('Missing Supabase URL or anon key');
}
const supabase = createClient(supabaseUrl, supabaseAnonKey);
export default supabase;
This code initializes a Supabase client using the URL and anon key from your environment variables. It also includes a check to ensure that the environment variables are defined, which can help prevent errors in production. Exporting the client allows you to import and use it in other parts of your application.
If you're using TypeScript, your supabaseClient.ts file should look like this:
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
if (!supabaseUrl || !supabaseAnonKey) {
throw new Error('Missing Supabase URL or anon key');
}
const supabase = createClient(supabaseUrl, supabaseAnonKey);
export default supabase;
The ! operator tells TypeScript that you're sure these environment variables are defined and won't be null or undefined. This is necessary because TypeScript's type system requires explicit handling of potentially undefined variables.
Implementing User Authentication
With the Supabase client set up, we can now implement user authentication. We'll start by creating a simple signup form.
Creating the Signup Form
Create a new component called SignupForm.jsx (or .tsx) in your src/components directory. Add the following code:
import React, { useState } from 'react';
import supabase from '../supabaseClient';
const SignupForm = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
setError(null);
try {
const { data, error } = await supabase.auth.signUp({
email,
password,
});
if (error) {
setError(error.message);
} else {
console.log('Signup successful:', data);
// Handle successful signup (e.g., redirect to confirmation page)
}
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
return (
<form onSubmit={handleSubmit}>
{error && <p style={{ color: 'red' }}>{error}</p>}
<label>
Email:
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</label>
<label>
Password:
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
</label>
<button type="submit" disabled={loading}>
{loading ? 'Signing up...' : 'Sign Up'}
</button>
</form>
);
};
export default SignupForm;
This component renders a simple form with email and password fields. When the form is submitted, it calls the supabase.auth.signUp method to create a new user in your Supabase project. The component also handles loading and error states to provide feedback to the user.
Creating the Sign-in Form
Similarly, create a SigninForm.jsx (or .tsx) component in your src/components directory:
import React, { useState } from 'react';
import supabase from '../supabaseClient';
const SigninForm = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
setError(null);
try {
const { data, error } = await supabase.auth.signInWithPassword({
email,
password,
});
if (error) {
setError(error.message);
} else {
console.log('Signin successful:', data);
// Handle successful signin (e.g., redirect to dashboard)
}
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
return (
<form onSubmit={handleSubmit}>
{error && <p style={{ color: 'red' }}>{error}</p>}
<label>
Email:
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</label>
<label>
Password:
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
</label>
<button type="submit" disabled={loading}>
{loading ? 'Signing in...' : 'Sign In'}
</button>
</form>
);
};
export default SigninForm;
This component is similar to the SignupForm, but it calls the supabase.auth.signInWithPassword method to sign in an existing user.
Displaying the Forms
Now, let's display these forms in our app/page.jsx (or .tsx) file. Replace the existing code with the following:
import SignupForm from './components/SignupForm';
import SigninForm from './components/SigninForm';
const Home = () => {
return (
<div>
<h1>Supabase Auth Example</h1>
<SignupForm />
<SigninForm />
</div>
);
};
export default Home;
This code imports the SignupForm and SigninForm components and renders them in the Home component. Now, when you run your Next.js application, you should see both forms displayed on the page.
Handling User Sessions
To manage user sessions, we'll use the @supabase/auth-helpers-nextjs package. This package provides a set of utilities to simplify authentication handling in Next.js.
Creating a Session Context
Create a new file named SessionContext.jsx (or .tsx) in your src/context directory. Add the following code:
import { createContext, useState, useEffect, useContext } from 'react';
import { useSupabaseClient, useUser } from '@supabase/auth-helpers-react';
const SessionContext = createContext(null);
export const SessionProvider = ({ children }) => {
const [session, setSession] = useState(null);
const supabaseClient = useSupabaseClient();
const user = useUser();
useEffect(() => {
const getSession = async () => {
const { data: { session } } = await supabaseClient.auth.getSession()
setSession(session)
}
getSession()
}, [supabaseClient, user]);
const value = {
session,
user,
supabaseClient,
};
return (
<SessionContext.Provider value={value}>
{children}
</SessionContext.Provider>
);
};
export const useSession = () => {
return useContext(SessionContext);
};
This code creates a SessionContext that provides access to the user session, Supabase client, and user object. The useSession hook allows you to easily access these values in your components. The SessionProvider component wraps your application and provides the session context to all its children.
Wrapping Your Application
To use the SessionProvider, wrap your application in the _app.jsx (or .tsx) file. Replace the existing code with the following:
import '../styles/globals.css';
import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs'
import { SessionProvider } from '../src/context/SessionContext';
import { useState } from 'react'
import { SessionContextProvider } from '@supabase/auth-helpers-react'
function MyApp({ Component, pageProps }) {
const [supabaseClient] = useState(() => createBrowserSupabaseClient())
return (
<SessionContextProvider
supabaseClient={supabaseClient}
initialSession={pageProps.initialSession}
>
<Component {...pageProps} />
</SessionContextProvider>
)
}
export default MyApp;
This code imports the SessionProvider component and wraps the Component with it. This makes the session context available to all pages and components in your application.
Accessing the Session
Now, you can access the session in your components using the useSession hook. For example, to display the user's email address, you can use the following code:
import { useSession } from '../src/context/SessionContext';
const Profile = () => {
const { user } = useSession();
if (!user) {
return <p>Please sign in.</p>;
}
return (
<p>Welcome, {user.email}!</p>
);
};
export default Profile;
This code imports the useSession hook and uses it to access the user object. If the user is signed in, it displays a welcome message with their email address. Otherwise, it displays a message prompting the user to sign in.
Conclusion
And that's it! You've successfully set up Supabase authentication in your Next.js 15 application. You've learned how to create a Supabase project, set up a Next.js project, create a Supabase client, implement user signup and sign-in forms, and manage user sessions. With this foundation, you can now build more complex authentication flows and integrate them into your application.
Remember to consult the Supabase and Next.js documentation for more information and advanced features. Happy coding!