Auth Module

What auth-basic installs

$ asa install auth-basic

Not a marketing mock. Every component below is from the actual module output.

This is real output from our architecture service — not a downloadable template.

Register

domains/auth/register/ui/AuthRegister.tsx

Validation State

Invalid email address

Password must be at least 8 characters

Display name is required

Success State

Account created

Redirecting to dashboard...

Zod validation: All fields validated server-side before Supabase call. Generic error on duplicate email — no account enumeration. Profile created in profiles table with RLS.

Login

domains/auth/login/ui/AuthLogin.tsx

Default State

Forgot password?

No account? Create one

Error State

Invalid credentials

No hint whether email or password is wrong.

Server-verified: Uses getUser() — not getSession() — for JWT verification. HttpOnly cookie session. Generic error message prevents credential enumeration. Lint rule SEC-002 blocks getSession() misuse.

Reset Password

domains/auth/reset-password/ui/AuthResetPassword.tsx

Enter your email and we'll send you a reset link.

Security: Generic response for all emails (no enumeration). Reset token sent via Supabase Auth email flow.

What the Handler Looks Like

domains/auth/login/handler.ts — generated code

import { NextRequest, NextResponse } from 'next/server';
import { createBrowserClient } from '@/shared/db/supabase-client';
import { loginSchema } from './schemas';

export async function POST(request: NextRequest) {
  const body = await request.json();
  const parsed = loginSchema.safeParse(body);
  if (!parsed.success) {
    return NextResponse.json(
      { error: parsed.error.issues[0]?.message },
      { status: 400 }
    );
  }

  const supabase = createBrowserClient();
  const { data, error } = await supabase.auth.signInWithPassword({
    email: parsed.data.email,
    password: parsed.data.password,
  });

  if (error) {
    return NextResponse.json(
      { error: 'Invalid credentials' }, // No enumeration
      { status: 401 }
    );
  }

  return NextResponse.json({ user: data.user });
}

Real generated code. Zod validation. Server-side auth. Generic error messages.

Server-Side Guards

shared/auth/guards.ts — always verify server-side

// Every protected handler uses this:
const { user, response } = await requireAuth(request);
if (response) return response; // 401 if not authenticated

// For role-based access:
const { user, response } = await requireRole(request, 'admin');
if (response) return response; // 403 if wrong role

Protected Route Redirect

shared/auth/middleware.ts — unauthenticated users never see protected content

Without Auth → /dashboard
1User visits /dashboard
2Middleware checks getUser()
3No valid session found
Redirect to /login?next=/dashboard
After Login → /dashboard
1User logs in successfully
2HttpOnly cookie set server-side
3Reads ?next= parameter
Redirect to /dashboard

Defense in depth: Middleware redirects unauthenticated users. Route handlers re-verify with requireAuth(). Even if middleware is bypassed, the handler rejects the request.

Complete Auth Flow

Register → Login → Protected Page — end to end

1

Register

Zod validated → Supabase Auth → Profile created → Redirect

2

Login

Server-verified → HttpOnly cookie → getUser() check

3

Middleware

Every request → getUser() → Redirect if unauthenticated

4

Dashboard

requireAuth() server-side → User data from verified JWT

Real auth output. Not a marketing mock.

Install auth-basic and get server-verified sessions, validation, and protected routes in your project.