Authentication

ZeroDrag uses NextAuth.js v4 with two authentication methods: Google OAuth and passwordless magic links.

What This System Does

The authentication system handles:

  • User sign-in with Google OAuth (one-click authentication)
  • Passwordless email authentication via magic links
  • Automatic account linking based on email address
  • Session management with JWT tokens
  • Protected route enforcement
  • Server and client-side session access

Why It Exists

Authentication is the foundation for all user-specific features. It ensures users can securely access their accounts, subscriptions, and entitlements. The dual-provider approach (OAuth + magic links) balances convenience with accessibility.

When You Need to Care About It

You'll interact with authentication when:

  • Protecting pages or API routes that require user authentication
  • Checking user entitlements for feature gating
  • Customizing the sign-in UI or flow
  • Adding additional OAuth providers (beyond Google)
  • Modifying session duration or token settings

Key Concepts

Sessions

Sessions are JWT-based tokens stored in HTTP-only cookies. They last 30 days and automatically refresh every 24 hours when the user is active.

Account Linking

If a user signs up with a magic link and later uses Google OAuth (or vice versa) with the same email, the accounts are automatically linked. This prevents duplicate accounts.

Protected Routes

Pages inside /app/(protected)/ automatically require authentication. The layout calls requireAuth() and redirects unauthenticated users to /auth.

Server vs Client Sessions

Server-side code uses getServerSession() or helper functions like requireAuth(). Client-side code uses the useSession() hook from NextAuth.

Important Files

/lib/auth.ts

NextAuth.js configuration. Defines providers, session strategy, and callbacks.

/lib/auth-utils.ts

Server-side authentication helpers: requireAuth(), requireEntitlement(), hasEntitlement().

/components/AuthForm.tsx

Sign-in form UI component. Handles OAuth and magic link flows.

/app/auth/page.tsx

Authentication page that renders the AuthForm component.

/app/api/auth/[...nextauth]/route.ts

NextAuth API route handler. Handles OAuth callbacks and session management.

/app/api/auth/magic-link/route.ts

Magic link email sender. Generates verification tokens and sends emails.

/app/api/auth/magic-link/verify/route.ts

Magic link verification handler. Validates tokens and creates sessions.

Providers

Google OAuth

One-click sign-in using Google accounts. Requires GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET environment variables.

Flow: User clicks "Continue with Google" → Redirected to Google → Returns to /api/auth/callback/google → Session created → Redirected to dashboard.

Magic Links

Passwordless email authentication. User enters email → Receives verification link → Clicks link → Session created.

Requires RESEND_API_KEY for email delivery. Tokens expire after 24 hours.

Server-Side Usage

Use these functions in Server Components and API routes:

requireAuth()

Returns the authenticated user or redirects to /auth.

typescript
import { requireAuth } from "@/lib/auth-utils";

export default async function ProtectedPage() {
  const user = await requireAuth();
  return <div>Hello, {user.email}</div>;
}

requireEntitlement()

Requires authentication and a specific entitlement. Redirects to /pricing if missing.

typescript
import { requireEntitlement } from "@/lib/auth-utils";

export default async function ProPage() {
  const user = await requireEntitlement("pro_features");
  return <ProContent />;
}

hasEntitlement()

Checks entitlement without redirecting. Returns boolean.

typescript
import { hasEntitlement } from "@/lib/auth-utils";

export default async function Dashboard() {
  const hasPro = await hasEntitlement("pro_features");
  return hasPro ? <ProDashboard /> : <FreeDashboard />;
}

Client-Side Usage

Use the useSession hook from NextAuth in Client Components:

typescript
"use client";
import { useSession } from "next-auth/react";

function MyComponent() {
  const { data: session, status } = useSession();
  
  if (status === "loading") return <Loading />;
  if (!session) return <LoginPrompt />;
  
  return <div>Hello, {session.user.name}</div>;
}

For entitlements, use the useEntitlements hook:

typescript
"use client";
import { useEntitlements } from "@/hooks/use-entitlements";

function MyComponent() {
  const { hasEntitlement, loading } = useEntitlements();
  
  if (loading) return <Spinner />;
  if (!hasEntitlement("pro_features")) return <UpgradePrompt />;
  
  return <ProFeature />;
}

What You Can Customize

AuthForm Component

Located at /components/AuthForm.tsx. You can customize:

  • Styling and layout
  • Copy and messaging
  • Additional form fields (if needed)

Keep the core authentication logic (OAuth, magic links) intact.

Session Duration

Modify in /lib/auth.ts:

typescript
session: {
  maxAge: 30 * 24 * 60 * 60, // 30 days
  updateAge: 24 * 60 * 60,   // 24 hours
}

Additional OAuth Providers

Add providers in /lib/auth.ts following the Google provider pattern. NextAuth supports GitHub, Discord, Apple, and many others.

What NOT to Touch

/lib/auth.ts

Core NextAuth configuration. Marked with 🔒 CORE SYSTEM. Only modify session duration or add providers if you understand the implications.

/lib/auth-utils.ts

Authentication helper functions. These ensure consistent behavior across protected routes. Don't modify the core logic.

/app/api/auth/ routes

NextAuth API routes and magic link handlers. These are critical for authentication flow.

Related Sections