Embarking on a new web project often means tackling user authentication – a critical yet sometimes complex component. Fortunately, modern Backend-as-a-Service (BaaS) platforms like Supabase simplify this considerably. Supabase offers a robust suite of tools including a PostgreSQL database, real-time subscriptions, file storage, and, crucially for us, a comprehensive authentication system, all ready to go out of the box.

In this inaugural post of our series exploring Supabase integration with React, we’ll strip away the complexities and build a clean, functional authentication flow. We’ll guide you through setting up a React + TypeScript project, seamlessly connecting it to Supabase, and implementing signup, login, and logout functionalities, all beautifully styled with TailwindCSS.

Getting Started with Supabase

Your journey begins on the Supabase platform.

  1. Navigate to supabase.com and create an account if you haven’t already.
  2. Once logged in, create a new project. After the project is provisioned, make sure to save your unique Project URL and anon API key from your project dashboard – you’ll need these soon.
  3. For our authentication purposes, head over to the ‘Authentication’ section in your project settings and enable Email/Password login.

Setting Up Your React + TypeScript Project with Vite

We’ll kick off our frontend with Vite, a blazing-fast build tool, paired with React and TypeScript for a robust development experience. Open your terminal and run the following commands:

npx create-vite@latest supabase-auth-demo --template react-ts
cd supabase-auth-demo
npm install
npm install @supabase/supabase-js tailwindcss postcss autoprefixer
npx tailwindcss init -p

Next, configure TailwindCSS. Open tailwind.config.js and update the content array:

content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
theme: {
  extend: {},
},
plugins: [],

Finally, import Tailwind’s base styles into your src/index.css file:

@tailwind base;
@tailwind components;
@tailwind utilities;

Initializing Supabase in Your React App

Now, let’s connect your React application to your Supabase project. Create a new file named src/supabaseClient.ts:

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

const supabaseUrl = import.meta.env.VITE_SUPABASE_URL as string;
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY as string;

export const supabase = createClient(supabaseUrl, supabaseAnonKey);

To keep your API keys secure and manageable, add your Supabase credentials to a .env file in the root of your project. Remember to replace the placeholders with your actual project details:

VITE_SUPABASE_URL=https://your-project.supabase.co
VITE_SUPABASE_ANON_KEY=your-anon-key

Crafting the Authentication UI

With Supabase initialized, we can now build the user interface for our authentication flow. This Auth component will handle user input for email and password, and trigger the appropriate Supabase authentication methods.

import { useState, useEffect } from "react";
import { supabase } from "./supabaseClient";

export default function Auth() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [user, setUser] = useState(null); // State to hold authenticated user
  const [error, setError] = useState(""); // State for displaying errors

  // Check for existing session on component mount and listen for auth state changes
  useEffect(() => {
    supabase.auth.getSession().then(({ data: { session } }) => {
      setUser(session?.user || null);
    });

    const { data: authListener } = supabase.auth.onAuthStateChange(
      (event, session) => {
        setUser(session?.user || null);
      }
    );

    return () => {
      authListener?.subscription.unsubscribe();
    };
  }, []); // Empty dependency array means this runs once on mount

  const handleSignup = async () => {
    setError(""); // Clear previous errors
    const { data, error } = await supabase.auth.signUp({ email, password });
    if (error) setError(error.message);
    else if (data.user) alert("Check your email for the confirmation link!"); // Inform user about email verification
  };

  const handleLogin = async () => {
    setError(""); // Clear previous errors
    const { data, error } = await supabase.auth.signInWithPassword({
      email,
      password,
    });
    if (error) setError(error.message);
    else setUser(data.user);
  };

  const handleLogout = async () => {
    setError(""); // Clear previous errors
    const { error } = await supabase.auth.signOut();
    if (error) setError(error.message);
    else setUser(null); // Clear user state on logout
  };

  return (
    

Supabase Auth

{error &&

{error}

} {!user ? ( <> setEmail(e.target.value)} className="w-full mb-3 px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" /> setPassword(e.target.value)} className="w-full mb-3 px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" />
) : (

Logged in as {user.email}

)}
); }

Persisting the User Session

To ensure your application remembers logged-in users, you need to manage the user session. The useEffect hook, combined with Supabase’s getSession and onAuthStateChange methods, allows you to fetch the current session when the component mounts and react to any changes in the authentication state.

The updated Auth component above already incorporates this. The useEffect hook runs once on component mount to check for an existing session. It also subscribes to onAuthStateChange events, which automatically updates the user state whenever a user signs in, signs out, or their session refreshes. This ensures your UI always reflects the current authentication status.

Wrapping Up

Congratulations! You’ve successfully built a fully functional authentication system in React using TypeScript and Supabase, complete with signup, login, and logout capabilities, all beautifully styled with TailwindCSS. This provides a robust foundation for user management in any web application.

Stay tuned for the next installment in this series, where we’ll delve into Supabase Edge Functions and learn how to create custom backend APIs to extend your application’s functionality. Don’t forget to share this guide with anyone who could benefit from learning about Supabase!

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.
You need to agree with the terms to proceed