npm package: @shyam-148/auth-next
Description: Next.js App Router authentication - simple SSR, RSC, middleware support
Latest version: 1.0.3

# auth-next

Simple, focused authentication for Next.js App Router. Built on top of `auth-client`.

## Features

- ✅ **App Router Only** - Designed for Next.js 14/15+ App Router
- ✅ **Server Components** - Full RSC support with `getSession`, `getUser`
- ✅ **Client Components** - React context with `useAuth`, `useUser`, `useSession`
- ✅ **Middleware** - Edge-compatible route protection
- ✅ **Guards** - Declarative `<AuthGuard>` and `<GuestGuard>` components
- ✅ **TypeScript** - Full type safety
- ✅ **Tree-shakeable** - Import only what you need

## Installation

```bash
pnpm add auth-next auth-client
```

## Quick Start

### 1. Create Provider Wrapper

```tsx
// app/providers.tsx
'use client';

import { AuthProvider } from 'auth-next/client';

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <AuthProvider
      config={{
        baseUrl: process.env.NEXT_PUBLIC_AUTH_API_URL!,
        applicationSlug: 'my-app',
      }}
    >
      {children}
    </AuthProvider>
  );
}
```

### 2. Add to Layout

```tsx
// app/layout.tsx
import { Providers } from './providers';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}
```

### 3. Setup Middleware

```ts
// middleware.ts
import { createAuthMiddleware } from 'auth-next/middleware';

export default createAuthMiddleware({
  publicRoutes: ['/', '/login', '/register', '/api/public/*'],
  authRoutes: ['/login', '/register'],
  loginUrl: '/login',
  defaultRedirect: '/dashboard',
});

export const config = {
  matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};
```

## Usage

### Client Components

```tsx
'use client';

import { useAuth, useUser, AuthGuard, GuestGuard } from 'auth-next/client';

// Basic hook usage
function UserMenu() {
  const { user, logout, isAuthenticated } = useAuth();

  if (!isAuthenticated) return null;

  return (
    <div>
      <span>{user?.email}</span>
      <button onClick={logout}>Logout</button>
    </div>
  );
}

// Simpler user-only hook
function UserAvatar() {
  const { user, isLoading } = useUser();

  if (isLoading) return <Skeleton />;
  if (!user) return null;

  return <Avatar name={user.fullName} />;
}

// Guard component - shows content only when authenticated
function ProtectedPage() {
  return (
    <AuthGuard fallback={<Loading />} redirectTo="/login">
      <Dashboard />
    </AuthGuard>
  );
}

// Guest guard - shows content only when NOT authenticated
function LoginPage() {
  return (
    <GuestGuard redirectTo="/dashboard">
      <LoginForm />
    </GuestGuard>
  );
}
```

### Server Components

```tsx
// app/dashboard/page.tsx
import { getSession, getUser } from 'auth-next/server';
import { redirect } from 'next/navigation';

export default async function DashboardPage() {
  const session = await getSession({
    apiBase: process.env.AUTH_API_URL!,
  });

  if (!session) {
    redirect('/login');
  }

  return (
    <div>
      <h1>Welcome, {session.user.email}</h1>
      <p>Session ID: {session.session.id}</p>
    </div>
  );
}
```

### Server Actions

```ts
// app/actions.ts
'use server';

import { requireAuth } from 'auth-next/server';

export async function updateProfile(formData: FormData) {
  // Throws if not authenticated
  const session = await requireAuth({
    apiBase: process.env.AUTH_API_URL!,
  });

  // session.user is guaranteed to exist
  await db.users.update({
    where: { id: session.user.id },
    data: { name: formData.get('name') as string },
  });
}
```

### Route Handlers

```ts
// app/api/protected/route.ts
import { withAuth } from 'auth-next/middleware';

export const GET = withAuth(async (request, { userId }) => {
  // userId is guaranteed to exist
  const data = await fetchUserData(userId);
  return Response.json(data);
});
```

## API Reference

### Client Exports (`auth-next/client`)

| Export | Description |
|--------|-------------|
| `AuthProvider` | React context provider |
| `useAuth` | Main auth hook - user, session, logout, refresh |
| `useUser` | User-only hook - user, isLoading, isAuthenticated |
| `useSession` | Session hook - session, user, refresh |
| `useAuthStatus` | Status-only hook - status, isLoading, isAuthenticated |
| `useLogout` | Logout hook - logout function with loading state |
| `getAuthManager` | Get the underlying AuthManager for advanced operations |
| `AuthGuard` | Show children only when authenticated |
| `GuestGuard` | Show children only when NOT authenticated |
| `ShowWhenAuthenticated` | Conditional render for authenticated users |
| `ShowWhenGuest` | Conditional render for guests |

### Server Exports (`auth-next/server`)

| Export | Description |
|--------|-------------|
| `getSession` | Get current session (user + session + token) |
| `getUser` | Get current user only |
| `isAuthenticated` | Check if request is authenticated |
| `requireAuth` | Get session or throw error |
| `getAccessToken` | Get access token from cookies |
| `createAuthHeaders` | Create Authorization headers for API calls |
| `AuthenticationError` | Error class for auth failures |

### Middleware Exports (`auth-next/middleware`)

| Export | Description |
|--------|-------------|
| `createAuthMiddleware` | Create Next.js middleware |
| `getAuthFromRequest` | Get auth status from request |
| `withAuth` | Wrap route handler to require auth |
| `createMatcher` | Helper to create middleware matcher config |

## Configuration

### AuthProvider Props

```ts
interface AuthProviderProps {
  config: {
    baseUrl: string;           // Auth API URL
    applicationSlug: string;   // Your app identifier
    // ... other auth-client config
  };
  initialUser?: User | null;      // For SSR hydration
  initialSession?: Session | null;
  loadingComponent?: ReactNode;   // Show during init
  children: ReactNode;
}
```

### Middleware Config

```ts
interface AuthMiddlewareConfig {
  publicRoutes?: string[];     // Routes that don't require auth
  authRoutes?: string[];       // Routes that redirect if authenticated
  loginUrl?: string;           // Where to redirect unauthenticated users
  defaultRedirect?: string;    // Where to redirect authenticated users from auth routes
}
```

## Login Flow

Since authentication strategies vary, login is handled via `auth-client` directly:

```tsx
'use client';

import { getAuthManager } from 'auth-next/client';
import { EmailPasswordStrategy } from 'auth-client';

function LoginForm() {
  const handleSubmit = async (e: FormEvent) => {
    e.preventDefault();
    
    const manager = getAuthManager();
    const strategy = new EmailPasswordStrategy(manager.config.applicationSlug);
    
    await manager.login(strategy, {
      email: 'user@example.com',
      password: 'password',
    });
    
    // Auth state updates automatically via context
    router.push('/dashboard');
  };

  return <form onSubmit={handleSubmit}>...</form>;
}
```

## License

MIT