# @insforge/nextjs

**Zero-configuration authentication for Next.js** using Insforge backend. Get production-ready auth in 5 minutes.

## Why @insforge/nextjs?

✅ **Built-in Auth Pages** - Backend-hosted UI, no React code needed  
✅ **5-Minute Setup** - Provider + API route + callback + middleware = done  
✅ **Full SSR Support** - Works with Next.js App Router and Server Components  
✅ **Auto OAuth** - 11 providers configured from backend automatically  
✅ **TypeScript First** - Complete type safety out of the box

**Need custom UI?** Scroll to [Customization](#customization) for custom components and styling.

## Installation

```bash
npm install @insforge/nextjs
```

---

## Quick Start

### 1. Setup Provider

Wrap your app with `InsforgeProvider` in the root layout:

```tsx
// app/layout.tsx
import { InsforgeProvider } from '@insforge/nextjs';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <InsforgeProvider
          baseUrl={process.env.NEXT_PUBLIC_INSFORGE_BASE_URL!}
          afterSignInUrl="/dashboard"
        >
          {children}
        </InsforgeProvider>
      </body>
    </html>
  );
}
```

> **Zero Configuration**: Styles are automatically injected via Emotion CSS-in-JS. No CSS imports needed!

### 2. Create API Route

Create an API route to sync tokens to HTTP-only cookies (enables SSR):

```tsx
// app/api/auth/route.ts
import { createAuthRouteHandlers } from '@insforge/nextjs/api';

const handlers = createAuthRouteHandlers({
  baseUrl: process.env.INSFORGE_BASE_URL || process.env.NEXT_PUBLIC_INSFORGE_BASE_URL!,
  cookieName: 'insforge_token',
});

export const POST = handlers.POST;
export const GET = handlers.GET;
export const DELETE = handlers.DELETE;
```

**What it does:**

- `POST /api/auth` - Syncs localStorage token to HTTP-only cookie
- `GET /api/auth` - Retrieves user data server-side
- `DELETE /api/auth` - Clears auth cookie on sign out

### 3. Setup Middleware

Protect routes with middleware:

```ts
// middleware.ts
import { InsforgeMiddleware } from '@insforge/nextjs/middleware';

export default InsforgeMiddleware({
  baseUrl: process.env.INSFORGE_BASE_URL!,
  publicRoutes: ['/auth/callback', '/'],
  cookieName: 'insforge_token',
});

export const config = {
  matcher: [
    '/((?!api|_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
  ],
};
```

**What it does:**

- Redirects unauthenticated users to backend auth pages
- Verifies tokens server-side
- Allows public routes without auth

### 4. Use Hooks & Components

```tsx
// app/page.tsx
import { SignedIn, SignedOut, UserButton } from '@insforge/nextjs';

export default function Home() {
  return (
    <div>
      <SignedOut>
        <a href="/sign-in">Sign In</a>
      </SignedOut>

      <SignedIn>
        <UserButton afterSignOutUrl="/" />
        <h1>Welcome back!</h1>
      </SignedIn>
    </div>
  );
}
```

**Available Hooks:**

```tsx
import { useAuth, useUser } from '@insforge/nextjs';

function Component() {
  const { signIn, signUp, signOut, isSignedIn, isLoaded } = useAuth();
  const { user, updateUser } = useUser();

  return <div>Email: {user?.email}</div>;
}
```

**That's it!** 🎉 Your app now has production-ready authentication.

---

## How It Works

```
1. User clicks "Sign In" → Middleware redirects to backend auth page
   ↓
2. User signs in on backend (https://your-project.insforge.app/auth/sign-in)
   ↓
3. Backend redirects: yourapp.com?access_token=xxx&user_id=xxx...
   ↓
4. SDK auto-detects URL parameters:
   - Stores token in localStorage
   - Provider automatically reloads auth state
   - Token syncs to HTTP-only cookie (via API route)
   ↓
5. User sees dashboard with authenticated state
```

**Two-Storage Architecture:**

- **localStorage**: Client-side token access (hooks, components, SDK)
- **HTTP-only cookie**: Server-side token access (middleware, SSR)

---

## Customization

### Custom Auth Pages

Want custom branding? Create custom auth pages instead of using built-in pages:

```tsx
// app/sign-in/page.tsx
'use client';

import { SignIn } from '@insforge/nextjs';
import { useRouter } from 'next/navigation';

export default function SignInPage() {
  const router = useRouter();

  return (
    <div className="min-h-screen flex items-center justify-center bg-gray-50">
      <SignIn
        afterSignInUrl="/dashboard"
        onSuccess={(user) => {
          console.log('Signed in:', user);
          router.push('/dashboard');
        }}
      />
    </div>
  );
}
```

**Additional Auth Components:**

```tsx
// Password reset flow
import { ForgotPassword, ResetPassword, VerifyEmail } from '@insforge/nextjs';

// app/forgot-password/page.tsx
<ForgotPassword backToSignInUrl="/sign-in" />

// app/reset-password/page.tsx (with token from URL)
<ResetPassword token={token} backToSignInUrl="/sign-in" />

// app/verify-email/page.tsx (with token from URL)
<VerifyEmail token={token} />
```

**Available Atomic Components:**

- `AuthContainer` - Main form container
- `AuthHeader` - Title and subtitle
- `AuthFormField` - Standard input field
- `AuthPasswordField` - Password field with visibility toggle
- `AuthPasswordStrengthIndicator` - Password requirement checklist
- `AuthSubmitButton` - Submit button with loading states
- `AuthErrorBanner` - Error message display
- `AuthDivider` - Visual separator
- `AuthOAuthProviders` - OAuth provider buttons grid
- `AuthOAuthButton` - Individual OAuth button
- `AuthVerificationCodeInput` - OTP/2FA code input
- `AuthLink` - Navigation link
- `AuthBranding` - Insforge branding footer

### Server-Side Usage

Access auth data in Server Components, API Routes, and Server Actions using the `auth()` helper:

#### Using in Server Components

```tsx
// app/dashboard/page.tsx (Server Component)
import { auth } from '@insforge/nextjs/server';

export default async function Dashboard() {
  const { userId, user } = await auth();

  if (!userId) {
    return <div>Not authenticated</div>;
  }

  return <div>Welcome, {user?.email}!</div>;
}
```

#### Using in API Routes

```tsx
// app/api/posts/route.ts
import { auth, createServerClient } from '@insforge/nextjs/server';
import { NextResponse } from 'next/server';

export async function GET() {
  const { userId, token } = await auth();

  if (!userId || !token) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }

  // Option 1: Use auth info directly
  return NextResponse.json({ userId, message: 'Authenticated!' });

  // Option 2: Use createServerClient for database operations
  const insforge = await createServerClient({
    baseUrl: process.env.INSFORGE_BASE_URL!,
  });

  if (!insforge) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }

  const result = await insforge.database.from('posts').select();
  return NextResponse.json(result.data);
}
```

#### Using in Server Actions

```tsx
'use server';

import { auth } from '@insforge/nextjs/server';
import { revalidatePath } from 'next/cache';

export async function createPost(formData: FormData) {
  const { userId } = await auth();

  if (!userId) {
    throw new Error('Not authenticated');
  }

  // Create post with userId
  const title = formData.get('title');
  // ... insert into database

  revalidatePath('/posts');
}
```

### Conditional Rendering

```tsx
import { Protect } from '@insforge/nextjs';

// Role-based access
<Protect condition={(user) => user.role === 'admin'}>
  <AdminPanel />
</Protect>

// Custom logic
<Protect condition={(user) => user.emailVerified}>
  <VerifiedUserFeature />
</Protect>
```

### Auth Change Callback

Track authentication events:

```tsx
<InsforgeProvider
  baseUrl={baseUrl}
  onAuthChange={(user) => {
    if (user) {
      analytics.identify(user.id);
    } else {
      analytics.reset();
    }
  }}
/>
```

---

## Local Development

During local development, backend typically runs on a different port:

```bash
# .env.local
NEXT_PUBLIC_INSFORGE_BASE_URL=http://localhost:7130
INSFORGE_BASE_URL=http://localhost:7130
```

---

## TypeScript

Full TypeScript support with exported types:

```tsx
import type {
  InsforgeUser,
  InsforgeCallbackProps,
  SignInProps,
  SignUpProps,
  ForgotPasswordProps,
  ResetPasswordProps,
  VerifyEmailProps,
  SignInAppearance,
  SignUpAppearance,
  UserButtonProps,
  ProtectProps,
  OAuthProvider,
} from '@insforge/nextjs';
```

---

## Support

- **Documentation**: https://docs.insforge.dev
- **GitHub Issues**: https://github.com/InsForge/InsForge/issues
- **Discord Community**: https://discord.com/invite/DvBtaEc9Jz

## License

MIT
