
### Next.js JWT Authentication Library Documentation

Table of Contents
-----------------

1.  [Introduction](#introduction)
2.  [Installation](#installation)
3.  [Core Concepts](#core-concepts)
4.  [Configuration](#configuration)
5.  [API Reference](#api-reference)
    
    *   [Client-Side API](#client-side-api)
    *   [Server-Side API](#server-side-api)
    *   [Middleware](#middleware)
    *   [HTTP Utilities](#http-utilities)

Introduction
------------

This authentication library provides a complete solution for JWT-based authentication in Next.js applications. It supports both client and server components, handles token refresh automatically, and provides utilities for making authenticated API requests.

### Key Features

*   **JWT Authentication**: Secure authentication using JSON Web Tokens
*   **Automatic Token Refresh**: Seamless refresh of expired tokens
*   **App Router Support**: Full compatibility with Next.js App Router
*   **TypeScript Support**: Complete type definitions for all components
*   **Server Components**: Authentication utilities for React Server Components
*   **Middleware Integration**: Route protection at the middleware level
*   **HTTP Utilities**: Simplified authenticated API requests

Installation
------------

1.  Configure environment variables in your `.env.local` file:

```env
# Auth API Configuration

NEXT_PUBLIC_API_BASE_URL= # default is: http://localhost:3001
NEXT_PUBLIC_AUTH_GLOBAL_PREFIX= # default is: ""
NEXT_PUBLIC_LOGIN_ENDPOINT= # default is: /sign-in
NEXT_PUBLIC_LOGOUT_ENDPOINT= # default is: /sign-out
NEXT_PUBLIC_REFRESH_TOKEN_PREFIX= # default is: /refresh
NEXT_PUBLIC_USER_ENDPOINT= # default is: /user
NEXT_PUBLIC_ACCESS_TOKEN_PREFIX= # default is:auth.access-token
NEXT_PUBLIC_REFRESH_TOKEN_PREFIX= # default is:auth.refresh-token
NEXT_PUBLIC_AUTH_TOKEN_TYPE= # default is:Bearer
```

2.  Initialize the authentication system in your root layout:

```ts
// app/layout.tsx

import { AuthProvider } from "@duongtrungnguyen/next-helper";
import "./globals.css";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        <AuthProvider>{children}</AuthProvider>
      </body>
    </html>
  );
}
```

Core Concepts
-------------

### Authentication Flow

1.  **Login**: User provides credentials → Server validates and returns JWT tokens → Client stores tokens in cookies
2.  **API Requests**: Client retrieves token from cookies → Sends in Authorization header → Server validates token
3.  **Token Refresh**: When access token expires → Client sends refresh token → Server issues new tokens → Client updates cookies
4.  **Logout**: Client clears tokens from cookies

### Token Storage

Tokens are stored in HTTP-only cookies for security, but are sent in the Authorization header for API requests. This approach:

*   Protects tokens from XSS attacks (HTTP-only cookies)
*   Follows standard API authentication practices (Authorization header)
*   Maintains compatibility with backend services expecting tokens in headers

### Authentication Context

The library provides a React context that exposes:

*   Current authentication state (user, loading, error)
*   Authentication methods (login, logout, refreshTokens)
*   Token management utilities

Configuration
-------------

The library can be configured through environment variables or by passing a configuration object to the `initAuth` function.


API Reference
-------------

### Client-Side API

#### `useAuth()`

React hook that provides access to the authentication context.

**Returns:**

```ts
{
  state: {
    user: User | null;        // Current user or null if not authenticated
    isLoading: boolean;       // True when authentication state is loading
    isAuthenticated: boolean; // True when user is authenticated
    error: string | null;     // Error message or null
  };
  login: (credentials: LoginCredentials) => Promise<void>;  // Login function
  logout: () => Promise<void>;                             // Logout function
  refreshTokens: () => Promise<boolean>;                   // Refresh tokens function
}
```

**Example:**

```ts
"use client";

import { useAuth } from "@duongtrungnguyen/next-helper";

export default function LoginForm() {
  const { login, state } = useAuth();
  
  const handleSubmit = async (e) => {
    e.preventDefault();
    await login({
      email: "user@example.com",
      password: "password"
    });
  };
  
  return (
    <form onSubmit={handleSubmit}>
      {/* Form fields */}
      <button type="submit" disabled={state.isLoading}>
        {state.isLoading ? "Logging in..." : "Login"}
      </button>
      {state.error && <p>{state.error}</p>}
    </form>
  );
}
```

#### `useProtectedRoute()`

React hook that redirects to the login page if the user is not authenticated.

**Returns:**

```ts
{
  isLoading: boolean;       // True when authentication state is loading
  isAuthenticated: boolean; // True when user is authenticated
}
```

**Example:**

```ts
"use client";

import { useProtectedRoute } from "@duongtrungnguyen/next-prepare";

export default function ProfilePage() {
  const { isLoading } = useProtectedRoute();
  
  if (isLoading) {
    return <div>Loading...</div>;
  }
  
  return <div>Profile content (only visible to authenticated users)</div>;
}
```

#### `AuthProvider`

React context provider that must wrap your application.

**Props:**

```ts
{ children: ReactNode; // Child components }
```

### Server-Side API

#### `getCurrentUser()`

Server action that retrieves the current user based on the access token in cookies.

**Returns:**

```ts
Promise<User | null> // User object or null if not authenticated
```

**Example:**

```ts
// app/profile/page.tsx
import { getCurrentUser } from "@duongtrungnguyen/next-prepare";

export default async function ProfilePage() {
  const user = await getCurrentUser();
  
  if (!user) {
    return <div>Please log in to view your profile</div>;
  }
  
  return (
    <div>
      <h1>Welcome, {user.name}</h1>
      <p>Email: {user.email}</p>
    </div>
  );
}
```

#### `setAuthCookies(tokens: AuthTokens)`

Server action that sets authentication cookies for access and refresh tokens.

**Parameters:**

*   `tokens`: Object containing `accessToken` and `refreshToken`

**Example:**

```ts
import { setAuthCookies } from "@duongtrungnguyen/next-prepare";

// Example usage in a custom login API route
export async function POST(request: Request) {
  const { email, password } = await request.json();
  
  // Authenticate user (implementation depends on your backend)
  const tokens = await authenticateUser(email, password);
  
  if (tokens) {
    await setAuthCookies(tokens);
    return Response.json({ success: true });
  }
  
  return Response.json({ success: false }, { status: 401 });
}
```

#### `clearAuthCookies()`

Server action that clears authentication cookies.

**Example:**

```ts
import { clearAuthCookies } from "@duongtrungnguyen/next-prepare";

// Example usage in a custom logout API route
export async function POST() {
  await clearAuthCookies();
  return Response.json({ success: true });
}
```

#### `refreshAccessToken()`

Server action that refreshes the access token using the refresh token in cookies.

**Returns:**

```ts
Promise<boolean> // True if token was successfully refreshed
```

### Middleware

#### `authMiddleware(request: NextRequest)`

Middleware function that checks if the access token is about to expire and refreshes it if necessary.

**Parameters:**

*   `request`: Next.js request object

**Returns:**

`Promise<NextResponse> // Next.js response object`

**Example:**

```ts
// middleware.ts
import { NextRequest, NextResponse } from "next/server";
import { authMiddleware } from "@duongtrungnguyen/next-prepare";

export async function middleware(request: NextRequest) {
  return await authMiddleware(request);
}

export const config = {
  matcher: [
    "/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
  ],
};
```

### HTTP Utilities

#### `HttpClient`

Universal fetch utility class that works in both client and server components.

**Methods:**

*   `get<T>(url: string, config?: RequestConfigs): Promise<T>`
*   `post<T>(url: string, data?: any, config?: RequestConfigs): Promise<T>`
*   `put<T>(url: string, data?: any, config?: RequestConfigs): Promise<T>`
*   `delete<T>(url: string, config?: RequestConfigs): Promise<T>`

**Example:**

```ts
import { httpClient } from "@duongtrungnguyen/next-prepare";

// In any component (client or server)
const fetchData = async () => {
  try {
    const data = await httpClient.get("/api/protected-resource");
    return data;
  } catch (error) {
    console.error("Error fetching data:", error);
  }
};
```

