Skip to main content

Authentication

Set up Supabase email and password sign-in plus optional Google OAuth in DirectoryLaunch, grant admin rights, and use the built-in auth helpers.

DirectoryLaunch uses Supabase Auth for user accounts — no external service to sign up for, no OAuth apps to wire up (except Google, if you want it).

What works out of the box

  • Email + password signup & login
  • "Forgot my password" email flow
  • Session cookies, auto-refreshed by middleware
  • Protected pages (redirect to /auth/signin when logged out)

The signin page

Users sign up or sign in from /auth/signin. OAuth flows come back through /auth/callback.

Enabling Google OAuth (optional)

If you want the "Continue with Google" button to work:

1. In Supabase

Authentication → Providers → Google → toggle on.

2. In Google Cloud Console

  1. Go to console.cloud.google.com → create a project (or pick one)
  2. APIs & Services → Credentials → Create Credentials → OAuth client ID
  3. Application type: Web application
  4. Authorized redirect URIs: copy the callback URL from Supabase (shown on the Google provider page — looks like https://xxx.supabase.co/auth/v1/callback)
  5. Save → copy Client ID and Client Secret

3. Back in Supabase

Paste the Client ID and Client Secret into the Google provider form → Save.

4. Restart your dev server

Done. "Continue with Google" now works.

User dashboard

Once logged in, users get a dashboard for their submissions, profile, and settings:

Making a user an admin

Two fields, both need to be set:

  1. In Supabase → Table Editorusers → find the user
  2. Set is_admin to true
  3. Set role to admin

Why two fields?

isAdmin() helper (server code) checks is_admin. RLS policies (database security) use role. They must match — set both.

Auth helpers in code

Server components / API routes

import {
  getServerSession,
  getCurrentUser,
  isAdmin,
  isAuthenticated,
  requireAuth,
} from '@/lib/supabase/auth-helpers';
 
await getServerSession();   // { user } or null
await getCurrentUser();     // user object or null
await isAuthenticated();    // boolean
await isAdmin();            // boolean
await requireAuth();        // returns redirect() if not logged in

Client components

import { useUser } from '@/hooks/use-user';
 
function Dashboard() {
  const { user, loading } = useUser();
 
  if (loading) return <Spinner />;
  if (!user) return <SignInPrompt />;
 
  return <div>Hello {user.email}</div>;
}

Security: getUser() vs getSession()

Use getUser() server-side

supabase.auth.getUser() verifies the token against Supabase. getSession() just reads the cookie — a malicious user can spoof that. In API routes and server components, always use getUser().

Middleware

middleware.ts runs on every request (except static files and /api/webhooks). It:

  • Refreshes the session token so users stay logged in
  • Handles locale detection when i18n is on

It does not redirect or protect routes — that's each page's job.

See also