TrueSpec

Supabase Email/Password Auth

Sign up, sign in, password reset, and protected routes with Supabase Auth

What You’ll Build

After following this guide, you will have a working implementation of supabase email/password auth in your project. Implement full email/password authentication using Supabase Auth. Includes sign up with email verification, sign in, password reset flow, and protecting routes based on auth state. Supabase handles all the heavy lifting — no need to manage password hashing or token rotation yourself.

Use Cases & Problems Solved

  • Protect routes so only authenticated users can access sensitive pages
  • Allow users to sign up, log in, and manage their accounts securely
  • Avoid storing raw passwords or building session management from scratch

Prerequisites

  • Supabase project (free tier works)
  • React or Next.js app
  • Node.js 18+

Step-by-Step Implementation

Install Supabase client

The following snippet shows how to install supabase client. Copy this into your project and adjust the values for your environment.

npm install @supabase/supabase-js

Initialize the Supabase client

The following snippet shows how to initialize the supabase client. Copy this into your project and adjust the values for your environment.

// lib/supabase.js
import { createClient } from '@supabase/supabase-js';

export const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
);

Sign up, sign in, and sign out

The following snippet shows how to sign up, sign in, and sign out. Copy this into your project and adjust the values for your environment.

import { supabase } from '../lib/supabase';

// Sign up
const { data, error } = await supabase.auth.signUp({
  email: 'user@example.com',
  password: 'securepassword123',
});

// Sign in
const { data, error } = await supabase.auth.signInWithPassword({
  email: 'user@example.com',
  password: 'securepassword123',
});

// Sign out
await supabase.auth.signOut();

// Get current user
const { data: { user } } = await supabase.auth.getUser();

Password reset flow

The following snippet shows how to password reset flow. Copy this into your project and adjust the values for your environment.

// Send reset email
await supabase.auth.resetPasswordForEmail('user@example.com', {
  redirectTo: 'https://yourapp.com/reset-password',
});

// Update password (on the reset page)
await supabase.auth.updateUser({ password: 'newSecurePassword' });

⚠️ Don’t Do This

❌ Using the service_role key in frontend code

// NEVER use service_role key in the browser!
const supabase = createClient(url, 
  'eyJhbGciOiJIUzI1NiIs...service_role_key'
);

✅ Always use the anon key in frontend, service_role only on server

// Frontend: anon key (safe to expose)
const supabase = createClient(url, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY);

// Server only: service_role key
const adminClient = createClient(url, process.env.SUPABASE_SERVICE_ROLE_KEY);

Testing

Add these tests to verify your supabase email/password auth implementation works correctly:

// __tests__/supabase.test.ts
import { describe, it, expect } from 'vitest';

describe('Supabase Email/Password Auth', () => {
  it('should handle successful authentication', async () => {
    // Test the happy path
    const result = await authenticate({ email: 'test@example.com', password: 'valid' });
    expect(result.user).toBeDefined();
    expect(result.error).toBeNull();
  });

  it('should reject invalid credentials', async () => {
    const result = await authenticate({ email: 'test@example.com', password: 'wrong' });
    expect(result.user).toBeNull();
    expect(result.error).toBeDefined();
  });

  it('should handle missing fields', async () => {
    const result = await authenticate({ email: '', password: '' });
    expect(result.error).toBeDefined();
  });
});

Verification

# Start your app
npm run dev
# Test sign up with a real email
# Check Supabase dashboard > Authentication > Users
# Verify the user appears and email is confirmed

Related Specs

Beginner

Clerk Auth in Next.js App Router

Drop-in auth with Clerk, middleware protection, and user metadata

Auth & Identity
Beginner

Firebase Auth with React

Google/GitHub sign-in, onAuthStateChanged listener, and route protection

Auth & Identity
Intermediate

Passwordless Magic Link Auth

Email magic link flow with Resend and custom token verification

Auth & Identity