Creating an Email Authentication using Supabase in React

Suraj Vishwakarma - Sep 19 '22 - - Dev Community

Introduction

Welcome to the latest part of the Authentication series. Previously, we have discussed
"How JSON web token works in NodeJS for Authentication with a Project" and "How to use Crypto Wallet for Authentication in ReactJS". In this series, we are discussing different ways and tools to create an authentication system for your web application. You can follow me on Twitter(@surajondev) to get notified of future posts earlier.

Supabase is an open-source alternative to firebase. It provides you Postgres database, Authentication, instant APIs, Edge Functions, Realtime subscriptions, and Storage in one place. You do not need to set up anything locally, access all the features through the web-based dashboard for managing features in your application.

Today, we are going to build an authentication system that has register and login features. These features will be created with Supabase's Authentication.

So let's get started.

Setting Up Supabase

First, we need to create an account on Supabase to access their features. Go to the Supabase homepage via the supabase.com link. From the top-right navigation bar, click on Sign in. This will take you to the app.supabase.com page requesting you to Sign In with GitHub. Click on the button, and you will redirect to the GitHub login page, enter your credential and authorize the Supabase with the necessary permission.

Now, you will be redirected back to app.supabase.com. Here, we will create our project.

Create Project

Click on + New Project to initiate the process. On the next page, you will be asked to fill out the following details:

  • Name: Enter the name of your project. I have gone with 'supabase-authn'.

  • Database Password: Enter a strong password for your project.

  • Region: Select the server region, which is closest to your location.

  • Pricing Plan: Use the free tier for now.

New Project

After filling the details, click on Create new project. This will takes some time(Around 1-2 minutes) to create the project.

Once the project is created, it's time to set up our React project.

Environment Setup

Let's create our project in ReactJS. Install react with the below command.

Enter the below command in the terminal:
command

npx create-react-app supabase-authn
Enter fullscreen mode Exit fullscreen mode

This will create the basic react application. Delete all the unnecessary files and code from the /src directory.

Dependencies

As for the dependencies of our project, we need just supabase-js library to interact with the supabase database. Install the library with the below command.

Change directory to /supabase-authn and run the below command in the terminal:

npm install @supabase/supabase-js
Enter fullscreen mode Exit fullscreen mode

Now, the environment for the development of our project has been set up. Now, it's time to write some code.

Note: To run the above commands, you need nodejs pre-installed on your machine.

App.js

In the /src/App.js, we will implement the feature of Register and Login. First let's look into the working of the project.

Here is the algorithm:

  • Take email, password, and username from the user. username is not mandatory and unique.
  • If any error occurs then display the message. Otherwise, display a successful registration message.
  • Users can log in to their account with a valid email and password.
  • If login fails then displays an error message. Otherwise, display a successful login message.

So, let's implement the feature.

Imports

At the top, we are importing the library and CSS files.

import './App.css';
import { useState } from 'react';
import { createClient } from '@supabase/supabase-js'
Enter fullscreen mode Exit fullscreen mode

Usestate hooks for storing data

We have used the useState hooks to store the data. Here are all the states with comments explaining their purpose.

  const [email, setEmail] = useState(''); // email of the user
  const [password, setPassword] = useState(''); // password of the user
  const [username, setUsername] = useState(''); // username of the user
  const [Rmsg, setRMsg] = useState(''); // Registration message
  const [Lmsg, setLMsg] = useState(''); // Login message
  const [user, setUser] = useState(''); // User object after registration / login
  const [session, setSession] = useState(''); // session object after registration / login
Enter fullscreen mode Exit fullscreen mode

Return statement

As for the return, we are having both the register and login components. Here is the code for it.

return (
    <div className="App">
      <h1>Register User</h1>
      email:<input type="email" onChange={(e) => setEmail(e.target.value)} placeholder="Enter your email" /><br/>
      Password:<input type="password" onChange={(e) => setPassword(e.target.value)} placeholder="Enter your Password" /><br/>
      username:<input type="text" onChange={(e) => setUsername(e.target.value)} placeholder="Enter your username" /><br/>
      <button onClick={Register}>Register</button><br/>
      <p>{Rmsg}</p>
      <h1>Login</h1>
      email:<input type="email" onChange={(e) => setEmail(e.target.value)} placeholder="Enter your email" /><br/>      Password:<input type="password" onChange={(e) => setPassword(e.target.value)} placeholder="Enter your Password" /><br/>
      <button onClick={Login}>Login</button><br/>
      <p>{Lmsg}</p>
    </div>
  );
Enter fullscreen mode Exit fullscreen mode

This will result in the following output:

HomePage

Note: There will be an error as we haven't implemented the Register and Login components

There are two functions Register and Login which will be triggered after clicking the Register and Login buttons simultaneously. Let's write code for both of them.

supabase

Before writing the code for the Register and Login components, we need to establish a connection with the supabase database. For this, we need two things - anon and URL.

Anon is a JWT token that acts as an API key while making calls to the supabase database. URL is a RESTful endpoint for querying and managing your database.

You can get both of the things from your supabase project's Home tab available at the top of the left panel after selecting the database from https://app.supabase.com/.

Project API keys

Now, we have both things, now it's time to add them to our React project. We will use the API key and URL as the environment variable. For that create a file .env in the root directory of the project. Add the environment variable in the below format.

REACT_APP_SUPABASE_URL="Your project's URL"
REACT_APP_SUPABASE_ANON_KEY="Your project's Anon"
Enter fullscreen mode Exit fullscreen mode

Prefix the name of the environment variable with REACT_APP_. This will load the variable directly into the browser's environment and we do not need to use the dotenv library.

Now add the below code in App.js for accessing the supabase database.

const supabaseUrl = process.env.REACT_APP_SUPABASE_URL
const supabaseAnonKey = process.env.REACT_APP_SUPABASE_ANON_KEY

const supabase = createClient(supabaseUrl, supabaseAnonKey)
Enter fullscreen mode Exit fullscreen mode

We can use the supabase variable for making requests to the supabase database.

Now, let's look into the Login and Register component that will use the supabase variable.

Register

This function will be triggered when someone clicks the Register button. Let's first look into the code and then I will explain each step one by one.

const Register = async () => {
    const {data, error} = await supabase.auth.signUp({
      email,
      password,
    },
    {
      data: {
        username
      }
    })
    if(error){
      setRMsg(error.message)
    }else{
      setRMsg('User created successfully')
      setUser(data.user)
    }
  }
Enter fullscreen mode Exit fullscreen mode

At the top, we are making a call to the database with the function supabase.auth.signUp(). This function is used to create a new account. It takes two variables one is for email and password, and another one is for the payload. The payload can have data that you want to send to the server along with email and password. As payload, we are sending data objects having property usernames.

The call will result in a response in an object format. We have destructured it to extract errors and data from it. We will move as per the response. If any error occurs, we will set the request message with setRMsg() to display the error message to the user. The error can be a password less than 6 characters, email is not valid, the user already exists, and others.

If there are no errors then we will store the user data and set the register message with "User created successfully". By default, an email confirmation is active and you need to confirm the email before logging into the account. For development purposes, you can also disable this feature by going to your project in app.supabase.com. In project, Go to Authentication -> Setting -> Auth Provider -> Email. In the email provider, disable the Confirm Email.

Confirm Email

Login

Here is the login code of our application. As usual, first, let's look into the code and then the explanation.

  const Login = async () => {
    const { data, error } = await supabase.auth.signInWithPassword({
      email,
      password,
    })
    if(error){
      setLMsg(error.message)
    }else{
      setLMsg('Login successfully')
      setUser(data.user)
      setSession(data.session)
      console.log(data.session)
    }
  }
Enter fullscreen mode Exit fullscreen mode

Using the supabase.auth.signInWithPassword() function, we are calling the database to sign in to the account with email and password. This will give us a response and we have restructured it to extract data and error.

If any error occurs while making calls, we will display the message to the user. The error can be email not confirmed, invalid credentials, etc.

If the login happens, we are extracting user and session information from the data. Users contain information related to the sign of the user such as provider, created at, last sign, and others.

Here is an example of the user object.

{
  "id": "8cb69bb7-d795-4b27-96f5-de9c946d9d4a",
  "aud": "authenticated",
  "role": "authenticated",
  "email": "suraj1@gmail.com",
  "email_confirmed_at": "2022-09-18T16:54:26.17774297Z"
}
Enter fullscreen mode Exit fullscreen mode

The session data contain information related to the created session. It includes data such as JWT token, token bearer, expire_in, and refresh_token. JWT tokens can be used to grant access to protected routes. You can learn more about it through my previous article, How JSON web token works in NodeJS for Authentication with a Project
.

Here is an example of the session object.

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhd…Y5In0.oOnB3Ja-w-tnyEBkvqhsi45XdSGl2vf9F45wklsatw4",
  "token_type": "bearer",
  "expires_in": 3600,
  "refresh_token": "RkKQetdqQB1R-dkbuLyBdA"
}

Enter fullscreen mode Exit fullscreen mode

Demo

After the successful compilation, you will be able to see the below screen on the localhost:3000.

image.png

If you entered the valid details in the register input then an account will be created at the supabase server.

You will be able to see the user in the Authentication tab of your project at app.supabase.com.

image.png

Now, if you try to log in with the same credentials(Email and Password), you will be able to see the "Login successfully" message.

image.png

Connect With Me

Conclusion

You can do a lot of things with the Supabase database such as storage, database, and function. You can also implement a variety of authentication such as Magic Link, Phone, and OAuth.

I hope, you have to understand the authentication using the Supabase database. Thanks for reading the blog post.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .