@insforge/nextjs 0.4.0 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,53 +5,32 @@ Pre-built authentication UI components for Next.js applications using Insforge b
5
5
  ## Features
6
6
 
7
7
  - **Drop-in UI Components**: Pre-styled SignIn, SignUp, and UserButton components
8
+ - **Auth Primitives (v0.5.0+)**: 10 low-level components for building custom auth UIs
8
9
  - **React Hooks**: Easy access to auth state with `useAuth()`, `useUser()`, `useSession()`
9
10
  - **Control Components**: `<SignedIn>`, `<SignedOut>`, `<Protect>` for conditional rendering
10
11
  - **Next.js Middleware**: Server-side route protection
11
- - **OAuth Support**: Built-in Google and GitHub authentication
12
+ - **OAuth Support**: 11 providers (Google, GitHub, Discord, Facebook, LinkedIn, Microsoft, Apple, X, Instagram, TikTok, Spotify)
13
+ - **Smart OAuth Layout**: Adaptive grid (1/2/3 columns) based on provider count
12
14
  - **TypeScript**: Full type safety out of the box
13
- - **Customizable**: Override styles with the `appearance` prop
15
+ - **Customizable**: Override styles with the `appearance` prop or build from primitives
14
16
 
15
17
  ## Installation
16
18
 
17
19
  ```bash
18
- npm install @insforge/nextjs lucide-react
20
+ npm install @insforge/nextjs
19
21
  # or
20
- yarn add @insforge/nextjs lucide-react
22
+ yarn add @insforge/nextjs
21
23
  ```
22
24
 
23
- **Required peer dependencies:**
24
- - `lucide-react` - Icon library (used for icons in components)
25
25
 
26
26
  ## Quick Start
27
27
 
28
- ### 1. Check Your Backend OAuth Configuration
29
-
30
- First, query your Insforge backend to see what OAuth providers are configured:
31
-
32
- ```bash
33
- # Using curl (requires admin authentication)
34
- curl -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
35
- https://your-backend.insforge.app/api/metadata/auth
36
- ```
37
-
38
- **Response example:**
39
- ```json
40
- {
41
- "oauths": [
42
- { "provider": "github", "clientId": "...", ... },
43
- { "provider": "google", "clientId": "...", ... }
44
- ]
45
- }
46
- ```
47
-
48
- **For AI Agents:** Use the Insforge MCP tool `get-backend-metadata` to automatically retrieve this configuration.
49
-
50
- ### 2. Wrap your app with AuthProvider
28
+ ### 1. Wrap your app with InsforgeProvider
51
29
 
52
30
  ```tsx
53
31
  // app/layout.tsx
54
- import { AuthProvider } from '@insforge/nextjs';
32
+ import { InsforgeProvider } from '@insforge/nextjs';
33
+ import '@insforge/nextjs/styles.css';
55
34
 
56
35
  export default function RootLayout({ children }: { children: React.ReactNode }) {
57
36
  const baseUrl = process.env.NEXT_PUBLIC_INSFORGE_BASE_URL!;
@@ -59,60 +38,117 @@ export default function RootLayout({ children }: { children: React.ReactNode })
59
38
  return (
60
39
  <html lang="en">
61
40
  <body>
62
- <AuthProvider baseUrl={baseUrl}>
41
+ <InsforgeProvider baseUrl={baseUrl}>
63
42
  {children}
64
- </AuthProvider>
43
+ </InsforgeProvider>
65
44
  </body>
66
45
  </html>
67
46
  );
68
47
  }
69
48
  ```
70
49
 
71
- **Note:** Import the component styles:
50
+ **That's it!** No Tailwind configuration needed. The package uses standalone CSS.
51
+
52
+ ### 2. Set up API route for authentication (Required for SSR)
53
+
54
+ Create an API route to handle authentication cookies. This is **essential** for Next.js server-side rendering and middleware to work properly.
72
55
 
73
56
  ```tsx
74
- // In your layout.tsx or _app.tsx
75
- import '@insforge/nextjs/styles.css';
57
+ // app/api/auth/route.ts
58
+ import { createAuthRouteHandlers } from '@insforge/nextjs/api';
59
+
60
+ const handlers = createAuthRouteHandlers({
61
+ baseUrl: process.env.INSFORGE_BASE_URL || process.env.NEXT_PUBLIC_INSFORGE_BASE_URL!,
62
+ cookieName: 'insforge_token',
63
+ });
64
+
65
+ export const POST = handlers.POST;
66
+ export const GET = handlers.GET;
67
+ export const DELETE = handlers.DELETE;
76
68
  ```
77
69
 
78
- **That's it!** No Tailwind configuration needed. The package now uses standalone CSS.
70
+ **Why is this needed?**
71
+
72
+ Next.js middleware runs on the server and cannot access `localStorage` (which is browser-only). This API route:
73
+ - Syncs tokens from `localStorage` to HTTP-only cookies
74
+ - Enables server-side authentication in middleware
75
+ - Provides server-side sign-in/sign-up endpoints
79
76
 
80
- ### 3. Add OAuth callback page (Required for OAuth)
77
+ ### 3. Add authentication callback page (Required for Next.js SSR)
81
78
 
82
- If you're using OAuth providers, you **must** create a callback page:
79
+ Create a callback page to handle post-authentication token synchronization. This is **required for all authentication methods** (email/password and OAuth) when using Next.js middleware:
83
80
 
84
81
  ```tsx
85
82
  // app/auth/callback/page.tsx
86
83
  'use client';
87
84
 
88
- import { useEffect, Suspense } from 'react';
85
+ import { useEffect, useRef, Suspense } from 'react';
89
86
  import { useRouter, useSearchParams } from 'next/navigation';
90
87
 
91
88
  function CallbackContent() {
92
89
  const router = useRouter();
93
90
  const searchParams = useSearchParams();
91
+ const isProcessingRef = useRef(false);
94
92
 
95
93
  useEffect(() => {
96
- const processOAuthCallback = () => {
94
+ const processOAuthCallback = async () => {
95
+ // Prevent double-processing in React Strict Mode
96
+ if (isProcessingRef.current) return;
97
+ isProcessingRef.current = true;
98
+
97
99
  const accessToken = searchParams.get('access_token');
98
100
  const error = searchParams.get('error');
99
101
 
100
102
  if (error) {
103
+ console.error('OAuth error:', error);
101
104
  router.push('/sign-in?error=' + encodeURIComponent(error));
102
105
  return;
103
106
  }
104
107
 
105
108
  if (accessToken) {
106
- // Store token in localStorage (where SDK expects it)
109
+ // 1. Store token in localStorage (for SDK client-side operations)
107
110
  localStorage.setItem('insforge-auth-token', accessToken);
108
111
 
109
- // Get final destination
112
+ console.log('✅ OAuth token stored in localStorage');
113
+
114
+ // 2. Sync token to HTTP-only cookie (for server-side middleware)
115
+ try {
116
+ const syncResponse = await fetch('/api/auth', {
117
+ method: 'POST',
118
+ headers: {
119
+ 'Content-Type': 'application/json',
120
+ },
121
+ body: JSON.stringify({
122
+ action: 'sync-token',
123
+ token: accessToken,
124
+ }),
125
+ });
126
+
127
+ if (syncResponse.ok) {
128
+ console.log('✅ OAuth token synced to cookie');
129
+ } else {
130
+ console.warn('⚠️ Failed to sync token to cookie, but localStorage has it');
131
+ }
132
+ } catch (syncError) {
133
+ console.warn('⚠️ Cookie sync failed:', syncError);
134
+ }
135
+
136
+ // 3. Get the final destination from sessionStorage
110
137
  const finalDestination = sessionStorage.getItem('oauth_final_destination') || '/dashboard';
111
138
  sessionStorage.removeItem('oauth_final_destination');
112
139
 
113
- router.push(finalDestination);
140
+ // 4. Clean up URL to remove OAuth params before redirect
141
+ window.history.replaceState({}, '', '/auth/callback');
142
+
143
+ // 5. Small delay to ensure cookie is set before redirect
144
+ setTimeout(() => {
145
+ router.push(finalDestination);
146
+ }, 100);
114
147
  } else {
115
- router.push('/sign-in?error=no_token');
148
+ if (searchParams.toString()) {
149
+ console.error('No token received from OAuth');
150
+ router.push('/sign-in?error=no_token');
151
+ }
116
152
  }
117
153
  };
118
154
 
@@ -131,14 +167,28 @@ function CallbackContent() {
131
167
 
132
168
  export default function OAuthCallbackPage() {
133
169
  return (
134
- <Suspense fallback={<div>Loading...</div>}>
170
+ <Suspense fallback={
171
+ <div className="flex items-center justify-center min-h-screen">
172
+ <div>Loading...</div>
173
+ </div>
174
+ }>
135
175
  <CallbackContent />
136
176
  </Suspense>
137
177
  );
138
178
  }
139
179
  ```
140
180
 
141
- ### 4. Add sign-in page with OAuth providers
181
+ **What this does:**
182
+ 1. Receives authentication callback with `access_token` from backend (works for both OAuth and email/password)
183
+ 2. Stores token in `localStorage` for SDK client-side operations
184
+ 3. Syncs token to HTTP-only cookie via `/api/auth` for server-side middleware
185
+ 4. Redirects user to their intended destination
186
+
187
+ **Note:** This callback page handles returns from:
188
+ - OAuth providers (Google, GitHub, etc.)
189
+ - Email/password sign-in/sign-up when using the pre-built components
190
+
191
+ ### 4. Add sign-in page
142
192
 
143
193
  ```tsx
144
194
  // app/sign-in/page.tsx
@@ -147,8 +197,6 @@ import { SignIn } from '@insforge/nextjs';
147
197
  export default function SignInPage() {
148
198
  return (
149
199
  <SignIn
150
- baseUrl={process.env.NEXT_PUBLIC_INSFORGE_BASE_URL!}
151
- providers={['github', 'google']} // Based on your backend config
152
200
  afterSignInUrl="/dashboard"
153
201
  title="Welcome to MyApp"
154
202
  subtitle="Sign in to continue"
@@ -157,7 +205,7 @@ export default function SignInPage() {
157
205
  }
158
206
  ```
159
207
 
160
- **Note:** The `providers` prop should match what you've configured in your Insforge backend. OAuth buttons will only render for providers specified in this array.
208
+ **OAuth Providers:** The package automatically detects which OAuth providers are configured on your backend. You don't need to specify them manually!
161
209
 
162
210
  ### 5. Add sign-up page
163
211
 
@@ -168,8 +216,6 @@ import { SignUp } from '@insforge/nextjs';
168
216
  export default function SignUpPage() {
169
217
  return (
170
218
  <SignUp
171
- baseUrl={process.env.NEXT_PUBLIC_INSFORGE_BASE_URL!}
172
- providers={['github', 'google']} // Based on your backend config
173
219
  afterSignUpUrl="/dashboard"
174
220
  />
175
221
  );
@@ -211,40 +257,110 @@ export default function Home() {
211
257
 
212
258
  ```ts
213
259
  // middleware.ts
214
- import { withAuth } from '@insforge/nextjs/middleware';
260
+ import { InsforgeMiddleware } from '@insforge/nextjs/middleware';
215
261
 
216
- export default withAuth({
262
+ export default InsforgeMiddleware({
217
263
  baseUrl: process.env.INSFORGE_BASE_URL!,
218
- publicRoutes: ['/sign-in', '/sign-up', '/'],
264
+ publicRoutes: ['/sign-in', '/sign-up', '/', '/auth/callback'], // Include callback!
219
265
  signInUrl: '/sign-in',
266
+ cookieName: 'insforge_token', // Must match API route cookie name
220
267
  });
221
268
 
222
269
  export const config = {
223
- matcher: ['/((?!_next|api|.*\\..*).*)'],
270
+ matcher: ['/((?!api|_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)'],
224
271
  };
225
272
  ```
226
273
 
274
+ **Important:**
275
+ - **Must include** `/auth/callback` in `publicRoutes` to allow authentication returns
276
+ - Use the same `cookieName` in both middleware and API route
277
+ - The `cookieName` must match between middleware and API route configuration
278
+
279
+ **Alternative imports:**
280
+ - `InsforgeMiddleware` - Recommended, most descriptive
281
+ - `withInsforgeAuth` - Alternative with Insforge branding
282
+ - `withAuth` - Deprecated but still supported for backward compatibility
283
+
284
+ ---
285
+
286
+ ## Architecture: Why Callback + API Route?
287
+
288
+ This package is specifically designed for **Next.js App Router with Server-Side Rendering (SSR)**. Here's why both the callback page and API route are essential:
289
+
290
+ ### The Challenge
291
+
292
+ Next.js has two execution environments:
293
+ - **Client-side**: Browser, can access `localStorage`
294
+ - **Server-side**: Middleware, Server Components, cannot access `localStorage`
295
+
296
+ The Insforge SDK stores authentication tokens in `localStorage` (client-side only), but Next.js middleware needs to verify authentication on the server.
297
+
298
+ ### The Solution
299
+
300
+ **Two-Storage Architecture:**
301
+
302
+ ```
303
+ ┌─────────────────────────────────────────────────────────────┐
304
+ │ Authentication Flow (Email/Password & OAuth) │
305
+ └─────────────────────────────────────────────────────────────┘
306
+
307
+ 1. User signs in (email/password OR OAuth)
308
+
309
+ 2. Backend redirects to: /auth/callback?access_token=xxx
310
+
311
+ 3. Callback Page (Client-side)
312
+ ├─ Stores token in localStorage (for SDK)
313
+ └─ Calls /api/auth with "sync-token" action
314
+
315
+ 4. API Route (Server-side)
316
+ ├─ Validates token with backend
317
+ └─ Sets HTTP-only cookie
318
+
319
+ 5. Middleware (Server-side)
320
+ └─ Reads cookie to protect routes
321
+ ```
322
+
323
+ **Why this matters:**
324
+ - **Client-side operations** (SDK calls) use `localStorage`
325
+ - **Server-side operations** (middleware, SSR) use HTTP-only cookies
326
+ - Both storages stay synchronized through the `/api/auth` endpoint
327
+
328
+ ### What Each Component Does
329
+
330
+ | Component | Purpose | Runs On |
331
+ |-----------|---------|---------|
332
+ | **Callback Page** | Receives auth token (any method), stores in localStorage, syncs to cookie | Client |
333
+ | **API Route** | Validates tokens, manages cookies, provides server-side auth | Server |
334
+ | **Middleware** | Protects routes, reads cookies, validates sessions | Server |
335
+ | **SDK** | Makes API calls, reads from localStorage | Client |
336
+
337
+ This architecture enables full-stack authentication in Next.js while maintaining security with HTTP-only cookies.
338
+
339
+ **Note:** All authentication methods (email/password, OAuth) use this same flow for consistency and SSR support.
340
+
227
341
  ## API Reference
228
342
 
229
343
  ### Components
230
344
 
231
- #### `<AuthProvider>`
345
+ #### `<InsforgeProvider>`
232
346
 
233
- Wraps your application and provides auth context.
347
+ Wraps your application and provides auth context. Automatically fetches OAuth provider configuration from your backend.
234
348
 
235
349
  ```tsx
236
- <AuthProvider
350
+ <InsforgeProvider
237
351
  baseUrl="https://your-backend.insforge.app"
238
352
  onAuthChange={(user) => console.log('Auth changed:', user)}
239
353
  >
240
354
  {children}
241
- </AuthProvider>
355
+ </InsforgeProvider>
242
356
  ```
243
357
 
244
358
  **Props:**
245
359
  - `baseUrl` (required): Your Insforge backend URL
246
360
  - `onAuthChange`: Optional callback when auth state changes
247
361
 
362
+ **Note:** The provider automatically queries your backend's OAuth configuration, so components like `<SignIn>` and `<SignUp>` will display the correct OAuth buttons without manual configuration.
363
+
248
364
  ---
249
365
 
250
366
  #### `<SignIn>`
@@ -253,8 +369,6 @@ Pre-built sign-in form with email/password and OAuth.
253
369
 
254
370
  ```tsx
255
371
  <SignIn
256
- baseUrl="https://your-backend.insforge.app"
257
- providers={['github', 'google']}
258
372
  afterSignInUrl="/dashboard"
259
373
  appearance={{
260
374
  container: { background: '#f5f5f5' },
@@ -266,13 +380,13 @@ Pre-built sign-in form with email/password and OAuth.
266
380
  ```
267
381
 
268
382
  **Props:**
269
- - `baseUrl` (required): Your Insforge backend URL
270
- - `providers`: Array of OAuth providers to display (e.g., `['github', 'google']`). Omit or pass empty array for email/password only
271
383
  - `afterSignInUrl`: Redirect URL after successful sign-in (default: `/`)
272
384
  - `appearance`: Custom styles for container, form, and button
273
385
  - `onSuccess`: Callback on successful sign-in
274
386
  - `onError`: Callback on error
275
387
 
388
+ **Note:** OAuth providers are automatically detected from your backend configuration via `InsforgeProvider`. No need to manually specify them!
389
+
276
390
  ---
277
391
 
278
392
  #### `<SignUp>`
@@ -281,8 +395,6 @@ Pre-built sign-up form with email/password and OAuth.
281
395
 
282
396
  ```tsx
283
397
  <SignUp
284
- baseUrl="https://your-backend.insforge.app"
285
- providers={['github', 'google']}
286
398
  afterSignUpUrl="/onboarding"
287
399
  appearance={{
288
400
  container: { background: '#f5f5f5' }
@@ -291,13 +403,135 @@ Pre-built sign-up form with email/password and OAuth.
291
403
  ```
292
404
 
293
405
  **Props:**
294
- - `baseUrl` (required): Your Insforge backend URL
295
- - `providers`: Array of OAuth providers to display (e.g., `['github', 'google']`). Omit or pass empty array for email/password only
296
406
  - `afterSignUpUrl`: Redirect URL after successful sign-up (default: `/`)
297
407
  - `appearance`: Custom styles for container, form, and button
298
408
  - `onSuccess`: Callback on successful sign-up
299
409
  - `onError`: Callback on error
300
410
 
411
+ **Note:** OAuth providers are automatically detected from your backend configuration via `InsforgeProvider`. No need to manually specify them!
412
+
413
+ ---
414
+
415
+ ### Auth Component Primitives (v0.5.0+)
416
+
417
+ For advanced customization, use the low-level Auth primitives to build your own authentication UI:
418
+
419
+ ```tsx
420
+ import {
421
+ AuthContainer,
422
+ AuthHeader,
423
+ AuthErrorBanner,
424
+ AuthFormField,
425
+ AuthPasswordField,
426
+ AuthSubmitButton,
427
+ AuthDivider,
428
+ AuthLink,
429
+ AuthOAuthProviders,
430
+ AuthBranding,
431
+ } from '@insforge/nextjs';
432
+ import '@insforge/nextjs/styles.css';
433
+
434
+ function CustomSignIn() {
435
+ const [email, setEmail] = useState('');
436
+ const [password, setPassword] = useState('');
437
+ const [error, setError] = useState('');
438
+ const [loading, setLoading] = useState(false);
439
+
440
+ async function handleSubmit(e) {
441
+ e.preventDefault();
442
+ // Your custom auth logic
443
+ }
444
+
445
+ return (
446
+ <AuthContainer>
447
+ <AuthHeader title="Welcome Back" subtitle="Sign in to continue" />
448
+
449
+ <AuthErrorBanner error={error} />
450
+
451
+ <form onSubmit={handleSubmit} className="insforge-form">
452
+ <AuthFormField
453
+ id="email"
454
+ type="email"
455
+ label="Email"
456
+ placeholder="you@example.com"
457
+ value={email}
458
+ onChange={(e) => setEmail(e.target.value)}
459
+ required
460
+ />
461
+
462
+ <AuthPasswordField
463
+ id="password"
464
+ label="Password"
465
+ value={password}
466
+ onChange={(e) => setPassword(e.target.value)}
467
+ required
468
+ forgotPasswordLink={{
469
+ href: '/forgot-password',
470
+ text: 'Forgot Password?'
471
+ }}
472
+ />
473
+
474
+ <AuthSubmitButton isLoading={loading}>
475
+ Sign In
476
+ </AuthSubmitButton>
477
+ </form>
478
+
479
+ <AuthLink
480
+ text="Don't have an account?"
481
+ linkText="Sign up"
482
+ href="/sign-up"
483
+ />
484
+
485
+ <AuthDivider text="or" />
486
+
487
+ <AuthOAuthProviders
488
+ providers={['google', 'github', 'discord']}
489
+ onClick={(provider) => handleOAuth(provider)}
490
+ loading={null}
491
+ />
492
+
493
+ <AuthBranding />
494
+ </AuthContainer>
495
+ );
496
+ }
497
+ ```
498
+
499
+ #### Available Primitives
500
+
501
+ | Component | Description |
502
+ |-----------|-------------|
503
+ | `<AuthContainer>` | Main wrapper with card styling. Accepts `style` prop for customization |
504
+ | `<AuthHeader>` | Displays `title` and optional `subtitle` |
505
+ | `<AuthErrorBanner>` | Shows error messages. Pass `error` string prop |
506
+ | `<AuthFormField>` | Standard input field. Supports all HTML input props + `label` |
507
+ | `<AuthPasswordField>` | Password input with visibility toggle, optional strength indicator, and forgot password link |
508
+ | `<AuthSubmitButton>` | Submit button with loading state. Pass `isLoading` and optional `loadingText` |
509
+ | `<AuthDivider>` | Visual separator with customizable `text` (default: "or") |
510
+ | `<AuthLink>` | Call-to-action link. Props: `text`, `linkText`, `href` |
511
+ | `<AuthOAuthProviders>` | Smart grid of OAuth buttons. Props: `providers`, `onClick`, `loading` |
512
+ | `<AuthBranding>` | "Powered by InsForge" branding. Optional `text` and `href` props |
513
+
514
+ **`AuthPasswordField` Props:**
515
+ - All standard input props (`value`, `onChange`, `required`, etc.)
516
+ - `label`: Field label text
517
+ - `id`: Input element ID
518
+ - `showStrengthIndicator`: Show password strength indicator (default: `false`)
519
+ - `forgotPasswordLink`: Object with `{ href: string, text?: string }`
520
+
521
+ **`AuthOAuthProviders` Smart Layout:**
522
+ - 1 provider: Full-width button with "Continue with Google"
523
+ - 2 providers: Two columns with short text "Google", "GitHub"
524
+ - 3+ providers: Three columns with icons only
525
+ - Auto-centers incomplete last rows (e.g., 5, 8, 11 providers)
526
+
527
+ **When to use primitives vs pre-built components:**
528
+ - Use `<SignIn>` / `<SignUp>` for quick setup with minimal customization
529
+ - Use Auth primitives when you need:
530
+ - Custom form layouts
531
+ - Additional fields (username, terms checkbox, etc.)
532
+ - Integration with your own state management
533
+ - Unique branding and styling
534
+
301
535
  ---
302
536
 
303
537
  #### `<UserButton>`
@@ -442,16 +676,68 @@ function Component() {
442
676
 
443
677
  ---
444
678
 
679
+ ### API Route Handlers
680
+
681
+ #### `createAuthRouteHandlers(config)`
682
+
683
+ Creates Next.js App Router API handlers for authentication with HTTP-only cookie management.
684
+
685
+ ```tsx
686
+ // app/api/auth/route.ts
687
+ import { createAuthRouteHandlers } from '@insforge/nextjs/api';
688
+
689
+ const handlers = createAuthRouteHandlers({
690
+ baseUrl: process.env.INSFORGE_BASE_URL!,
691
+ cookieName: 'insforge_token',
692
+ cookieMaxAge: 7 * 24 * 60 * 60, // 7 days
693
+ });
694
+
695
+ export const POST = handlers.POST;
696
+ export const GET = handlers.GET;
697
+ export const DELETE = handlers.DELETE;
698
+ ```
699
+
700
+ **Config:**
701
+ - `baseUrl` (required): Your Insforge backend URL
702
+ - `cookieName`: Cookie name for auth token (default: `insforge_token`)
703
+ - `cookieMaxAge`: Cookie expiration in seconds (default: 7 days)
704
+ - `secure`: Use secure cookies (auto-detected, `true` in production)
705
+
706
+ **Supported Actions (POST):**
707
+ - `sign-in`: Email/password sign-in with cookie creation
708
+ - `sign-up`: Email/password sign-up with cookie creation
709
+ - `sync-token`: Sync token from localStorage to cookie (for OAuth)
710
+
711
+ **Example: Sync token after OAuth**
712
+ ```typescript
713
+ // In your OAuth callback page
714
+ const response = await fetch('/api/auth', {
715
+ method: 'POST',
716
+ headers: { 'Content-Type': 'application/json' },
717
+ body: JSON.stringify({
718
+ action: 'sync-token',
719
+ token: accessToken,
720
+ }),
721
+ });
722
+ ```
723
+
724
+ **Endpoints:**
725
+ - `POST /api/auth` - Sign in, sign up, or sync token
726
+ - `GET /api/auth` - Check current session
727
+ - `DELETE /api/auth` - Sign out and clear cookies
728
+
729
+ ---
730
+
445
731
  ### Middleware
446
732
 
447
- #### `withAuth(config)`
733
+ #### `InsforgeMiddleware(config)`
448
734
 
449
735
  Create Next.js middleware for route protection.
450
736
 
451
737
  ```ts
452
- import { withAuth } from '@insforge/nextjs/middleware';
738
+ import { InsforgeMiddleware } from '@insforge/nextjs/middleware';
453
739
 
454
- export default withAuth({
740
+ export default InsforgeMiddleware({
455
741
  baseUrl: process.env.INSFORGE_BASE_URL!,
456
742
  publicRoutes: ['/sign-in', '/sign-up', '/', '/about'],
457
743
  signInUrl: '/sign-in',
@@ -465,18 +751,22 @@ export default withAuth({
465
751
  - `signInUrl`: URL to redirect to when not authenticated (default: `/sign-in`)
466
752
  - `cookieName`: Cookie name for auth token (default: `insforge_token`)
467
753
 
754
+ **Alternative exports:**
755
+ - `withInsforgeAuth` - Same as `InsforgeMiddleware` with Insforge branding
756
+ - `withAuth` - Deprecated alias for backward compatibility
757
+
468
758
  ---
469
759
 
470
- #### `getAuthUser(headers)` and `getAuthToken(headers)`
760
+ #### `getAuthUserId(headers)` and `getAuthToken(headers)`
471
761
 
472
762
  Get authenticated user ID or token in server components.
473
763
 
474
764
  ```tsx
475
765
  import { headers } from 'next/headers';
476
- import { getAuthUser, getAuthToken } from '@insforge/nextjs/middleware';
766
+ import { getAuthUserId, getAuthToken } from '@insforge/nextjs/middleware';
477
767
 
478
768
  export default async function ServerComponent() {
479
- const userId = getAuthUser(headers());
769
+ const userId = getAuthUserId(headers());
480
770
  const token = getAuthToken(headers());
481
771
 
482
772
  // Fetch user-specific data
@@ -486,6 +776,9 @@ export default async function ServerComponent() {
486
776
  }
487
777
  ```
488
778
 
779
+ **Alternative exports:**
780
+ - `getAuthUser` - Deprecated alias for `getAuthUserId` (backward compatibility)
781
+
489
782
  ---
490
783
 
491
784
  ## Styling
@@ -623,7 +916,7 @@ All components use semantic CSS class names prefixed with `insforge-`:
623
916
  ### Custom Auth Callbacks
624
917
 
625
918
  ```tsx
626
- <AuthProvider
919
+ <InsforgeProvider
627
920
  baseUrl={baseUrl}
628
921
  onAuthChange={(user) => {
629
922
  if (user) {
@@ -634,7 +927,7 @@ All components use semantic CSS class names prefixed with `insforge-`:
634
927
  }}
635
928
  >
636
929
  {children}
637
- </AuthProvider>
930
+ </InsforgeProvider>
638
931
  ```
639
932
 
640
933
  ### Server-Side User Data
@@ -642,11 +935,11 @@ All components use semantic CSS class names prefixed with `insforge-`:
642
935
  ```tsx
643
936
  // app/dashboard/page.tsx
644
937
  import { headers } from 'next/headers';
645
- import { getAuthUser } from '@insforge/nextjs/middleware';
938
+ import { getAuthUserId } from '@insforge/nextjs/middleware';
646
939
  import { createClient } from '@insforge/sdk';
647
940
 
648
941
  export default async function Dashboard() {
649
- const userId = getAuthUser(headers());
942
+ const userId = getAuthUserId(headers());
650
943
 
651
944
  const insforge = createClient({
652
945
  baseUrl: process.env.INSFORGE_BASE_URL!
@@ -693,31 +986,25 @@ INSFORGE_BASE_URL=https://your-backend.insforge.app
693
986
  When building Next.js apps with authentication:
694
987
 
695
988
  1. **Connect to Insforge MCP** - Access the user's Insforge backend
696
- 2. **Query metadata** - Call `get-backend-metadata` to get OAuth configuration
697
- 3. **Generate code** - Write auth pages with explicit `providers={['github', 'google']}` based on backend config
698
- 4. **User sees OAuth buttons** - Components render buttons for configured providers
699
-
700
- **Example MCP Response:**
701
- ```json
702
- {
703
- "auth": {
704
- "oauths": [
705
- { "provider": "github", "clientId": "..." },
706
- { "provider": "google", "clientId": "..." }
707
- ]
708
- }
709
- }
710
- ```
989
+ 2. **Generate code** - Use `<SignIn>` and `<SignUp>` components
990
+ 3. **Automatic configuration** - OAuth providers are detected automatically from backend
711
991
 
712
992
  **Agent generates:**
713
993
  ```tsx
714
- <SignIn
715
- baseUrl={process.env.NEXT_PUBLIC_INSFORGE_BASE_URL!}
716
- providers={['github', 'google']} // From metadata
717
- afterSignInUrl="/dashboard"
718
- />
994
+ // Step 1: Wrap app with InsforgeProvider
995
+ <InsforgeProvider baseUrl={process.env.NEXT_PUBLIC_INSFORGE_BASE_URL!}>
996
+ {children}
997
+ </InsforgeProvider>
998
+
999
+ // Step 2: Add sign-in page (OAuth auto-detected)
1000
+ <SignIn afterSignInUrl="/dashboard" />
719
1001
  ```
720
1002
 
1003
+ **Benefits:**
1004
+ - No need to query OAuth configuration manually
1005
+ - Components automatically render correct OAuth buttons
1006
+ - Backend configuration is the single source of truth
1007
+
721
1008
  ---
722
1009
 
723
1010
  ## TypeScript
@@ -754,6 +1041,6 @@ MIT
754
1041
 
755
1042
  ## Support
756
1043
 
757
- - Documentation: https://docs.insforge.app
758
- - Issues: https://github.com/insforge/nextjs/issues
759
- - Discord: https://discord.gg/insforge
1044
+ - Documentation: https://docs.insforge.dev/introduction
1045
+ - Issues: https://github.com/InsForge/InsForge/issues
1046
+ - Discord: https://discord.com/invite/DvBtaEc9Jz