CoreMVP

Authentication

Supabase Auth integration with server-side session management.

Overview

Authentication is handled by Supabase Auth with server-side session management through the Next.js proxy.

Supported Methods

  • Email/Password with verification
  • Magic links (OTP)
  • OAuth (Google, GitHub, Apple, and other Supabase-supported providers)

Architecture

service.ts
types.ts
app.ts
proxy.ts

How It Works

The user submits a form to the existing same-origin /api/auth/* URL. The Next.js catch-all passes the request to Hono, the auth handler calls the auth service, and the service uses the cookie-backed Supabase server client. The existing Next.js proxy continues refreshing browser sessions through the Supabase session helper. Password forms keep provider and validation failures on the current form. After a successful sign-in, sign-up, password setup, or sign-out, the shared auth transition helper clears cached session and user-status results before the next route renders.

Auth Service

The server-only auth service (src/services/auth/service.ts) owns Supabase Auth calls and their redirect results. Password routes preserve the supplied password; only email addresses are trimmed at the Hono boundary.

Password resultDestination
Sign-up creates a session immediately/pricing with success status
Sign-up requires email confirmation/ with confirmation status
Password sign-in succeeds/dashboard with success status
Provider or validation failsCurrent auth form with error detail

The API reference lists the exact response shapes. Keep the service's validation, existing-account, and provider-error branches when customizing it.

API Routes

The Hono auth module trims the email, preserves the password, calls the auth service, and returns its JSON result with a success or failure status.

Client-side password transitions

Use the shipped mutation hooks rather than calling Supabase from browser components. After a successful password transition, clear session-dependent query results before navigating:

const queryClient = useQueryClient();
const signUpMutation = useSignUpMutation();
const result = await signUpMutation.mutateAsync({ email, password });

if (result.ok) {
  reconcileAuthTransition(queryClient);
  router.push(result.redirectPath);
}

Session Management

Proxy session refresh

The Next.js entrypoint is src/proxy.ts. It calls the session helper in src/lib/supabase/middleware.ts for matched requests and preserves refreshed cookies when the existing Markdown negotiation path rewrites a response.

Getting the Current User

In server components or API routes:

import { createSupabaseServerClient } from "@/lib/supabase/server";

const supabase = await createSupabaseServerClient();
const {
  data: { user },
} = await supabase.auth.getUser();

In client components, use the session hook:

import { useSession } from "@/hooks/auth";

const session = useSession();
const user = session?.user ?? null;

Protected Routes

Protect the dashboard route tree in its server layout. getUser() validates the request cookies with Supabase before any dashboard shell or nested route can render:

src/app/dashboard/layout.tsx
import { redirect } from "next/navigation";
import { createSupabaseServerClient } from "@/lib/supabase/server";

export default async function DashboardLayout({ children }) {
  const supabase = await createSupabaseServerClient();
  const {
    data: { user },
    error,
  } = await supabase.auth.getUser();

  if (error || !user) {
    redirect("/signin");
  }

  return children;
}

Keep client status queries for account and billing data, not for route admission. An unauthenticated request redirects before protected HTML is sent.

OAuth Setup

Enable Provider in Supabase

Go to Supabase Dashboard → Authentication → Providers

Configure OAuth App

Create an OAuth app in the Google, GitHub, or Apple developer console and get credentials

Add Credentials to Supabase

Enter Client ID and Secret in Supabase provider settings

Set Redirect URLs

Add https://<project-ref>.supabase.co/auth/v1/callback to the OAuth provider's allowed redirects. This is the provider callback, not your app's hosted URL.

Configure the Hosted App URL

After your hosted domain is assigned, open Supabase URL Configuration. Set Site URL to https://<your-domain>, add https://<your-domain>/** to Redirect URLs, and save both fields before testing OAuth.

Database Trigger

New users are automatically added to the users table via a database trigger:

supabase/migrations/handle_new_user.sql
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS trigger AS $$
BEGIN
  INSERT INTO public.users (id, email)
  VALUES (new.id, new.email);
  RETURN new;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

CREATE TRIGGER on_auth_user_created
  AFTER INSERT ON auth.users
  FOR EACH ROW EXECUTE PROCEDURE public.handle_new_user();

Was this page helpful?

On this page