Technical Documentation

Authentication Flow

No passwords to remember. Just your email. A magic link. And you're home.

Last Updated: March 15, 2026Supabase AuthMagic Links

Overview

We use Supabase Auth with magic link emails. No passwords to remember—perfect for neurodivergent users who struggle with password fatigue.

The Journey

Sign Up
Enter email
Send Magic Link
Supabase Auth
Click Link
Verify email
Logged In
Redirect to dashboard

Step-by-Step Process

1

User Signs Up

User visits /signup, enters email address, clicks 'Send Magic Link'

📍 Code location: app/(auth)/signup/page.tsx

2

Supabase Creates User

Auth record created in auth.users. Trigger handle_new_user() runs automatically and creates matching row in public.profiles

3

User Receives Email

Magic link sent to inbox. Link expires in 24 hours. Clicking link verifies email.

4

User is Logged In

Redirected to /dashboard. Session cookie set. Now authenticated for all requests.

Client-Side Auth

Browser client for user-facing components. Use this in your client components.

lib/supabase/client.ts
import { createBrowserClient } from '@supabase/ssr'

export const createClient = () => 
  createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
  )

Server-Side Auth

Server client for route handlers and server components. Use this in your API routes and server components.

lib/supabase/server.ts
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'

export const createClient = async () => {
  const cookieStore = await cookies()
  return createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    { cookies: { get: (name) => cookieStore.get(name)?.value } }
  )
}

Middleware Protection

Next.js middleware that protects routes and refreshes sessions.

middleware.ts
import { createMiddlewareClient } from '@supabase/ssr'
import { NextResponse } from 'next/server'

export async function middleware(req) {
  const res = NextResponse.next()
  const supabase = createMiddlewareClient({ req, res })
  await supabase.auth.getSession()
  return res
}

export const config = {
  matcher: ['/dashboard/:path*', '/profile/:path*', '/checkout/:path*']
}

Protected Routes

Routes in app/(dashboard)/ require authentication.

Protected Routes
/dashboard/*

Main dashboard and user overview

/profile/*

Profile viewing and editing

/checkout/*

Payment and checkout flows

/creator/*

Creator dashboard and tools

/vendor/*

Vendor dashboard and tools

/admin/*

Admin panel (requires admin role)

✨ Why Magic Links?

  • No passwords to remember or reset
  • One less cognitive load for neurodivergent users
  • No password storage risk
  • Email-based recovery built-in