Anurag
Anurag's Blog

Anurag's Blog

Authenticate users using Email/Password combination with Supabase in NextJS!

Authenticate users using Email/Password combination with Supabase in NextJS!

Anurag
·Dec 21, 2021·

6 min read

Subscribe to my newsletter and never miss my upcoming articles

Listen to this article

Hey There fellow human!

hello

In this post, You will learn how to build Email/Pass authentication using Supabase in NextJS!

What we are building today:

  • Sign In/Sign Up
  • Logout

Let's get started!

First, you will need to create a new project in supabase

Click on the New Project button to create a new project, choose a name, and you're good to go! image.png

Set up a new NextJS Project

Then, you need to set up a Next.js app, I'm also using tailwind as my preferred UI library, you can use whatever you want.

npx create-next-app -e with-tailwindcss supabase-auth

Now, let's move to that folder and install the only required dependency, supabase-js

cd supabase-auth
# for npm
npm i @supabase/supabase-js

# for yarn
yarn add @supabase/supabase-js

Now in the index.js file, remove the boilerplate

- pages/index.js

const Home = () => {
  return <div>hello world</div>;
}

export default Home;

Now, let's initialize supabase client For this, we will create a new file named supabase.config.js at the root of the project and initialize the client like this:

Replace the keys with the actual keys that you copied in the first step.

- supabase.config.js

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

// Create a single supabase client for interacting with your database
const supabase = createClient(
  "<your_project_url>",
  "<your_public_anon_key>"
);

export default supabase;

Now, we are gonna make a header for navigation across pages and we will setup a Logout button in the header itself

Create a new page named Header.js inside the components directory at the root of your project:

- components/Header.js

const Header = () => {
  return (
    <header className="bg-gray-900 px-8 py-6 flex flex-row items-center">
      <a
        href="/"
        className="mx-2 text-xl px-4 py-1 rounded-full bg-emerald-500 text-white hover:bg-emerald-400 duration-100"
      >
        Home
      </a>
      <a
        href="/sign-up"
        className="mx-2 text-xl px-4 py-1 rounded-full bg-emerald-500 text-white hover:bg-emerald-400 duration-100"
      >
        Sign Up
      </a>
      <a
        href="/sign-in"
        className="mx-2 text-xl px-4 py-1 rounded-full bg-emerald-500 text-white hover:bg-emerald-400 duration-100"
      >
        Sign In
      </a>
    </header>
  );
};

export default Header

Now, we will import the Header component in the index.js file:

- pages/index.js

import Header from "../components/Header";

const Home = () => {
  return (
    <>
      <Header />
    </>
  );
};

export default Home;

Now, you should have a header like this:

image.png

Now, the auth part:

First, We are going to make a sign-up page It will contain a form to fill in details and create a new account.

- pages/sign-up.js

import Header from "../components/Header";

const SignUp = () => {
  return (
    <>
      <Header />

      <div className="min-h-screen min-w-screen bg-gray-700 flex justify-center items-center">
        <form className="px-10 py-8 rounded-sm bg-white shadow flex flex-col gap-4">
          <input
            type="text"
            placeholder="Enter your email..."
            className="w-64 px-2 py-2 bg-slate-50 rounded outline-none font-medium text-gray-700"
          />
          <input
            type="password"
            placeholder="Enter a pasword..."
            className="w-64 px-2 py-2 bg-slate-50 rounded outline-none font-medium text-gray-700"
          />

          <button className="px-4 py-2 rounded-sm bg-emerald-500 text-white hover:bg-emerald-400 duration-100">
            Sign Up
          </button>
        </form>
      </div>
    </>
  );
};

export default SignUp;

Now, we are going to create variables to store values. First, let's import the useState hook

import { useState } from "react";

Now, let's make two new variables

const [mail, setMail] = useState("");
const [pass, setPass] = useState("");

Now, let's assign the values to the form and assign a function to handle submit.

<form
          className="px-10 py-8 rounded-sm bg-white shadow flex flex-col gap-4"
          onSubmit={e => e.preventDefault()}
        >
          <input
            type="text"
            placeholder="Enter your email..."
            className="w-64 px-2 py-2 bg-slate-50 rounded outline-none font-medium text-gray-700"
            value={mail}
            onChange={e => setMail(e.target.value)}
          />
          <input
            type="password"
            placeholder="Enter a pasword..."
            className="w-64 px-2 py-2 bg-slate-50 rounded outline-none font-medium text-gray-700"
            value={pass}
            onChange={e => setPass(e.target.value)}
          />

          <button
            className="px-4 py-2 rounded-sm bg-emerald-500 text-white hover:bg-emerald-400 duration-100"
            onClick={signUp}
          >
            Sign Up
          </button>
        </form>

Now, we are going to make the actual function to create a new account with the details.

First, import the supabase client from supabase.config.js

import supabase from "../supabase.config";

Now, make a function named signUp inside the SignUp component.

const signUp = async () => {
  const { user, session, error } = await supabase.auth.signUp({
    email: mail,
    password: pass,
  });

  error ? console.log(error) : console.log(user);
  };

Now, at this point, if you sign up with the details, you should receive an email telling you to confirm your email. The user needs to confirm his/her email in order to verify it.

image.png

Now, let's make the sign in page. Create a new file in the pages directory named sign-in.

First, we are gonna make a form that will collect data.

- pages/sign-in.js

import Header from "../components/Header";
import { useState } from "react";

const SignIn = () => {
  const [mail, setMail] = useState("");
  const [pass, setPass] = useState("");

  return (
    <>
      <Header />

      <div className="min-h-screen min-w-screen bg-gray-700 flex justify-center items-center">
        <form
          className="px-10 py-8 rounded-sm bg-white shadow flex flex-col gap-4"
          onSubmit={e => e.preventDefault()}
        >
          <input
            type="text"
            placeholder="Enter your email..."
            className="w-64 px-2 py-2 bg-slate-50 rounded outline-none font-medium text-gray-700"
            value={mail}
            onChange={e => setMail(e.target.value)}
          />
          <input
            type="password"
            placeholder="Enter a pasword..."
            className="w-64 px-2 py-2 bg-slate-50 rounded outline-none font-medium text-gray-700"
            value={pass}
            onChange={e => setPass(e.target.value)}
          />

          <button
            className="px-4 py-2 rounded-sm bg-emerald-500 text-white hover:bg-emerald-400 duration-100"
            onClick={signIn}
          >
            Sign In
          </button>
        </form>
      </div>
    </>
  );
};

export default SignIn;

Now, we are gonna make the function to sign the user in.

First, import supabase client from the supabase.config.js file:

import supabase from "../supabase.config";

Now, create a function named signIn

const signIn = async () => {
  const { user, session, error } = await supabase.auth.signIn({
    email: mail,
    password: pass,
  });

  error ? console.log(error) : console.log(user);
  };

Now, we will apply some logic.

If the user is signed in, the app should redirect him/her to the home page.

For this, we will use the useRouter hook.

In the sign-in.js page, import the useRouter hook

import { useRouter } from "next/router";

Now, inside the SignIn component, we are going to check if user has logged in or not and will redirect according to it.

- pages/sign-in.js

const router = useRouter();
const user = supabase.auth.user();
user ? router.push("/") : null;

Logout functionality So, as mentioned above, we will make the log-out function in the header section itself

First, import the supabase client in the Header.js file

import supabase from '../supabase.config'

Now, in the LogOut button, we will add an onClick event to handle logout. Here's how we are gonna do it:

<button className="mx-2 text-xl px-4 py-1 rounded-full bg-emerald-500 text-white hover:bg-emerald-400 duration-100"
  onClick={()=>supabase.auth.signOut()}>
    Logout
</button>

Show results based on auth state.

So, we should display a text displaying whether the user is logged in or not. Here's how we are going to deal with this:

Let's import supabase client in index.js file

import supabase from "../supabase.config";

Now, add this code for the Home component:

const Home = () => {

  const user = supabase.auth.user()
  return (
    <>
      <Header />
    <p className="text-center text-2xl">
      {
        user ? "You are logged in!"
        : "You're not logged in :/"
      }
    </p>
    </>
  );
};

Well, that's it! Now you should have a fully-fledged Email/Pass auth built in!

Did you find this article valuable?

Support Anurag by becoming a sponsor. Any amount is appreciated!

Learn more about Hashnode Sponsors
 
Share this