@insforge/nextjs 0.5.6 → 0.6.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 +152 -785
- package/dist/api.d.mts +12 -1
- package/dist/api.d.ts +12 -1
- package/dist/api.js +58 -2
- package/dist/api.js.map +1 -1
- package/dist/api.mjs +56 -1
- package/dist/api.mjs.map +1 -1
- package/dist/index.d.mts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +45 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +45 -5
- package/dist/index.mjs.map +1 -1
- package/dist/middleware.d.mts +7 -1
- package/dist/middleware.d.ts +7 -1
- package/dist/middleware.js +52 -9
- package/dist/middleware.js.map +1 -1
- package/dist/middleware.mjs +48 -8
- package/dist/middleware.mjs.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,44 +1,45 @@
|
|
|
1
1
|
# @insforge/nextjs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Zero-configuration authentication for Next.js** using Insforge backend. Authentication pages are hosted on your backend by default—no UI code needed.
|
|
4
|
+
|
|
5
|
+
## Why Built-in Auth?
|
|
6
|
+
|
|
7
|
+
✅ **Zero UI Code** - No SignIn/SignUp pages to create
|
|
8
|
+
✅ **5-Minute Setup** - Provider + API route + callback page = done
|
|
9
|
+
✅ **Production Ready** - Battle-tested auth UI maintained by Insforge
|
|
10
|
+
✅ **Auto OAuth** - 11 providers configured automatically from backend
|
|
11
|
+
✅ **AI-Friendly** - Minimal code generation = fewer tokens
|
|
12
|
+
|
|
13
|
+
**Use custom components only if you need highly customized branding or custom fields.**
|
|
4
14
|
|
|
5
15
|
## Features
|
|
6
16
|
|
|
7
|
-
- **
|
|
8
|
-
- **
|
|
9
|
-
- **React Hooks**:
|
|
10
|
-
- **Control Components**: `<SignedIn>`, `<SignedOut>`, `<Protect>`
|
|
17
|
+
- **Built-in Authentication**: Backend-hosted sign-in/sign-up pages (default)
|
|
18
|
+
- **OAuth Support**: Google, GitHub, Discord, Facebook, LinkedIn, Microsoft, Apple, X, Instagram, TikTok, Spotify
|
|
19
|
+
- **React Hooks**: `useAuth()`, `useUser()`, `useSession()`
|
|
20
|
+
- **Control Components**: `<SignedIn>`, `<SignedOut>`, `<Protect>`
|
|
11
21
|
- **Next.js Middleware**: Server-side route protection
|
|
12
|
-
- **
|
|
13
|
-
- **Smart OAuth Layout**: Adaptive grid (1/2/3 columns) based on provider count
|
|
14
|
-
- **TypeScript**: Full type safety out of the box
|
|
15
|
-
- **Customizable**: Override styles with the `appearance` prop or build from primitives
|
|
22
|
+
- **TypeScript**: Full type safety
|
|
16
23
|
|
|
17
24
|
## Installation
|
|
18
25
|
|
|
19
26
|
```bash
|
|
20
27
|
npm install @insforge/nextjs
|
|
21
|
-
# or
|
|
22
|
-
yarn add @insforge/nextjs
|
|
23
28
|
```
|
|
24
29
|
|
|
25
|
-
|
|
26
30
|
## Quick Start
|
|
27
31
|
|
|
28
|
-
### 1.
|
|
32
|
+
### 1. Add InsforgeProvider
|
|
29
33
|
|
|
30
34
|
```tsx
|
|
31
35
|
// app/layout.tsx
|
|
32
36
|
import { InsforgeProvider } from '@insforge/nextjs';
|
|
33
|
-
import '@insforge/nextjs/styles.css';
|
|
34
37
|
|
|
35
38
|
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
36
|
-
const baseUrl = process.env.NEXT_PUBLIC_INSFORGE_BASE_URL!;
|
|
37
|
-
|
|
38
39
|
return (
|
|
39
40
|
<html lang="en">
|
|
40
41
|
<body>
|
|
41
|
-
<InsforgeProvider baseUrl={
|
|
42
|
+
<InsforgeProvider baseUrl={process.env.NEXT_PUBLIC_INSFORGE_BASE_URL!}>
|
|
42
43
|
{children}
|
|
43
44
|
</InsforgeProvider>
|
|
44
45
|
</body>
|
|
@@ -47,11 +48,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|
|
47
48
|
}
|
|
48
49
|
```
|
|
49
50
|
|
|
50
|
-
|
|
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.
|
|
51
|
+
### 2. Create API route (enables SSR)
|
|
55
52
|
|
|
56
53
|
```tsx
|
|
57
54
|
// app/api/auth/route.ts
|
|
@@ -67,16 +64,9 @@ export const GET = handlers.GET;
|
|
|
67
64
|
export const DELETE = handlers.DELETE;
|
|
68
65
|
```
|
|
69
66
|
|
|
70
|
-
**Why
|
|
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
|
|
67
|
+
> **Why?** Syncs auth tokens to HTTP-only cookies for server-side middleware.
|
|
76
68
|
|
|
77
|
-
### 3.
|
|
78
|
-
|
|
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:
|
|
69
|
+
### 3. Create callback page
|
|
80
70
|
|
|
81
71
|
```tsx
|
|
82
72
|
// app/auth/callback/page.tsx
|
|
@@ -91,8 +81,7 @@ function CallbackContent() {
|
|
|
91
81
|
const isProcessingRef = useRef(false);
|
|
92
82
|
|
|
93
83
|
useEffect(() => {
|
|
94
|
-
const
|
|
95
|
-
// Prevent double-processing in React Strict Mode
|
|
84
|
+
const processCallback = async () => {
|
|
96
85
|
if (isProcessingRef.current) return;
|
|
97
86
|
isProcessingRef.current = true;
|
|
98
87
|
|
|
@@ -100,59 +89,27 @@ function CallbackContent() {
|
|
|
100
89
|
const error = searchParams.get('error');
|
|
101
90
|
|
|
102
91
|
if (error) {
|
|
103
|
-
|
|
104
|
-
router.push('/sign-in?error=' + encodeURIComponent(error));
|
|
92
|
+
router.push('/?error=' + encodeURIComponent(error));
|
|
105
93
|
return;
|
|
106
94
|
}
|
|
107
95
|
|
|
108
96
|
if (accessToken) {
|
|
109
|
-
// 1. Store token in localStorage (for SDK client-side operations)
|
|
110
97
|
localStorage.setItem('insforge-auth-token', accessToken);
|
|
111
98
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
|
137
|
-
const finalDestination = sessionStorage.getItem('oauth_final_destination') || '/dashboard';
|
|
138
|
-
sessionStorage.removeItem('oauth_final_destination');
|
|
99
|
+
await fetch('/api/auth', {
|
|
100
|
+
method: 'POST',
|
|
101
|
+
headers: { 'Content-Type': 'application/json' },
|
|
102
|
+
body: JSON.stringify({ action: 'sync-token', token: accessToken }),
|
|
103
|
+
});
|
|
139
104
|
|
|
140
|
-
|
|
141
|
-
|
|
105
|
+
const destination = sessionStorage.getItem('auth_destination') || '/dashboard';
|
|
106
|
+
sessionStorage.removeItem('auth_destination');
|
|
142
107
|
|
|
143
|
-
|
|
144
|
-
setTimeout(() => {
|
|
145
|
-
router.push(finalDestination);
|
|
146
|
-
}, 100);
|
|
147
|
-
} else {
|
|
148
|
-
if (searchParams.toString()) {
|
|
149
|
-
console.error('No token received from OAuth');
|
|
150
|
-
router.push('/sign-in?error=no_token');
|
|
151
|
-
}
|
|
108
|
+
setTimeout(() => router.push(destination), 100);
|
|
152
109
|
}
|
|
153
110
|
};
|
|
154
111
|
|
|
155
|
-
|
|
112
|
+
processCallback();
|
|
156
113
|
}, [searchParams, router]);
|
|
157
114
|
|
|
158
115
|
return (
|
|
@@ -165,64 +122,35 @@ function CallbackContent() {
|
|
|
165
122
|
);
|
|
166
123
|
}
|
|
167
124
|
|
|
168
|
-
export default function
|
|
125
|
+
export default function CallbackPage() {
|
|
169
126
|
return (
|
|
170
|
-
<Suspense fallback={
|
|
171
|
-
<div className="flex items-center justify-center min-h-screen">
|
|
172
|
-
<div>Loading...</div>
|
|
173
|
-
</div>
|
|
174
|
-
}>
|
|
127
|
+
<Suspense fallback={<div>Loading...</div>}>
|
|
175
128
|
<CallbackContent />
|
|
176
129
|
</Suspense>
|
|
177
130
|
);
|
|
178
131
|
}
|
|
179
132
|
```
|
|
180
133
|
|
|
181
|
-
**
|
|
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
|
|
134
|
+
> **Why?** Receives token from backend auth pages and syncs to localStorage + cookie.
|
|
190
135
|
|
|
191
|
-
### 4. Add
|
|
192
|
-
|
|
193
|
-
```tsx
|
|
194
|
-
// app/sign-in/page.tsx
|
|
195
|
-
import { SignIn } from '@insforge/nextjs';
|
|
136
|
+
### 4. Add middleware (protects routes)
|
|
196
137
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
afterSignInUrl="/dashboard"
|
|
201
|
-
title="Welcome to MyApp"
|
|
202
|
-
subtitle="Sign in to continue"
|
|
203
|
-
/>
|
|
204
|
-
);
|
|
205
|
-
}
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
**OAuth Providers:** The package automatically detects which OAuth providers are configured on your backend. You don't need to specify them manually!
|
|
209
|
-
|
|
210
|
-
### 5. Add sign-up page
|
|
138
|
+
```ts
|
|
139
|
+
// middleware.ts
|
|
140
|
+
import { InsforgeMiddleware } from '@insforge/nextjs/middleware';
|
|
211
141
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
142
|
+
export default InsforgeMiddleware({
|
|
143
|
+
baseUrl: process.env.INSFORGE_BASE_URL!,
|
|
144
|
+
publicRoutes: ['/auth/callback', '/'],
|
|
145
|
+
cookieName: 'insforge_token',
|
|
146
|
+
});
|
|
215
147
|
|
|
216
|
-
export
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
afterSignUpUrl="/dashboard"
|
|
220
|
-
/>
|
|
221
|
-
);
|
|
222
|
-
}
|
|
148
|
+
export const config = {
|
|
149
|
+
matcher: ['/((?!api|_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)'],
|
|
150
|
+
};
|
|
223
151
|
```
|
|
224
152
|
|
|
225
|
-
###
|
|
153
|
+
### 5. Use in components
|
|
226
154
|
|
|
227
155
|
```tsx
|
|
228
156
|
// app/page.tsx
|
|
@@ -231,816 +159,255 @@ import { SignedIn, SignedOut, UserButton } from '@insforge/nextjs';
|
|
|
231
159
|
export default function Home() {
|
|
232
160
|
return (
|
|
233
161
|
<div>
|
|
234
|
-
<
|
|
235
|
-
<
|
|
236
|
-
|
|
237
|
-
</SignedOut>
|
|
238
|
-
|
|
239
|
-
<SignedIn>
|
|
240
|
-
<UserButton afterSignOutUrl="/" />
|
|
241
|
-
</SignedIn>
|
|
242
|
-
</nav>
|
|
162
|
+
<SignedOut>
|
|
163
|
+
<a href="/sign-in">Sign In</a>
|
|
164
|
+
</SignedOut>
|
|
243
165
|
|
|
244
166
|
<SignedIn>
|
|
167
|
+
<UserButton afterSignOutUrl="/" />
|
|
245
168
|
<h1>Welcome back!</h1>
|
|
246
169
|
</SignedIn>
|
|
247
|
-
|
|
248
|
-
<SignedOut>
|
|
249
|
-
<h1>Please sign in</h1>
|
|
250
|
-
</SignedOut>
|
|
251
170
|
</div>
|
|
252
171
|
);
|
|
253
172
|
}
|
|
254
173
|
```
|
|
255
174
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
```ts
|
|
259
|
-
// middleware.ts
|
|
260
|
-
import { InsforgeMiddleware } from '@insforge/nextjs/middleware';
|
|
261
|
-
|
|
262
|
-
export default InsforgeMiddleware({
|
|
263
|
-
baseUrl: process.env.INSFORGE_BASE_URL!,
|
|
264
|
-
publicRoutes: ['/sign-in', '/sign-up', '/', '/auth/callback'], // Include callback!
|
|
265
|
-
signInUrl: '/sign-in',
|
|
266
|
-
cookieName: 'insforge_token', // Must match API route cookie name
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
export const config = {
|
|
270
|
-
matcher: ['/((?!api|_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)'],
|
|
271
|
-
};
|
|
272
|
-
```
|
|
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
|
|
175
|
+
**That's it!** When users click "Sign In", they'll be redirected to your backend's auth page automatically.
|
|
283
176
|
|
|
284
177
|
---
|
|
285
178
|
|
|
286
|
-
##
|
|
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:**
|
|
179
|
+
## How It Works
|
|
301
180
|
|
|
302
181
|
```
|
|
303
|
-
|
|
304
|
-
│ Authentication Flow (Email/Password & OAuth) │
|
|
305
|
-
└─────────────────────────────────────────────────────────────┘
|
|
306
|
-
|
|
307
|
-
1. User signs in (email/password OR OAuth)
|
|
182
|
+
1. User clicks "Sign In" → Middleware detects no auth
|
|
308
183
|
↓
|
|
309
|
-
2.
|
|
184
|
+
2. Redirects to: https://backend.insforge.app/auth/signin?redirect=yourapp.com/auth/callback
|
|
310
185
|
↓
|
|
311
|
-
3.
|
|
312
|
-
├─ Stores token in localStorage (for SDK)
|
|
313
|
-
└─ Calls /api/auth with "sync-token" action
|
|
186
|
+
3. User signs in on backend's hosted page
|
|
314
187
|
↓
|
|
315
|
-
4.
|
|
316
|
-
├─ Validates token with backend
|
|
317
|
-
└─ Sets HTTP-only cookie
|
|
188
|
+
4. Backend redirects: yourapp.com/auth/callback?access_token=xxx
|
|
318
189
|
↓
|
|
319
|
-
5.
|
|
320
|
-
└─ Reads cookie to protect routes
|
|
190
|
+
5. Callback stores token (localStorage + cookie) → User sees /dashboard
|
|
321
191
|
```
|
|
322
192
|
|
|
323
|
-
**Why
|
|
324
|
-
- **
|
|
325
|
-
- **
|
|
326
|
-
- Both storages stay synchronized through the `/api/auth` endpoint
|
|
327
|
-
|
|
328
|
-
### What Each Component Does
|
|
193
|
+
**Why API route + callback?**
|
|
194
|
+
- **API route**: Syncs tokens to HTTP-only cookies (enables server-side middleware)
|
|
195
|
+
- **Callback page**: Receives tokens from backend auth pages (OAuth + email/password)
|
|
329
196
|
|
|
330
|
-
|
|
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
|
-
|
|
341
|
-
## API Reference
|
|
342
|
-
|
|
343
|
-
### Components
|
|
197
|
+
---
|
|
344
198
|
|
|
345
|
-
|
|
199
|
+
## Local Development
|
|
346
200
|
|
|
347
|
-
|
|
201
|
+
Backend typically runs on different port during local dev:
|
|
348
202
|
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
{children}
|
|
355
|
-
</InsforgeProvider>
|
|
203
|
+
```bash
|
|
204
|
+
# .env.local
|
|
205
|
+
NEXT_PUBLIC_INSFORGE_BASE_URL=http://localhost:7130 # Backend API
|
|
206
|
+
NEXT_PUBLIC_INSFORGE_FRONTEND_URL=http://localhost:7131 # Backend Frontend (auth pages)
|
|
207
|
+
INSFORGE_BASE_URL=http://localhost:7130 # For middleware
|
|
356
208
|
```
|
|
357
209
|
|
|
358
|
-
|
|
359
|
-
- `baseUrl` (required): Your Insforge backend URL
|
|
360
|
-
- `onAuthChange`: Optional callback when auth state changes
|
|
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.
|
|
210
|
+
Provider automatically uses `NEXT_PUBLIC_INSFORGE_FRONTEND_URL` for auth redirects if set.
|
|
363
211
|
|
|
364
212
|
---
|
|
365
213
|
|
|
366
|
-
|
|
214
|
+
## Advanced: Custom Components
|
|
367
215
|
|
|
368
|
-
|
|
216
|
+
Need custom branding? Disable built-in auth:
|
|
369
217
|
|
|
370
218
|
```tsx
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
container: { background: '#f5f5f5' },
|
|
375
|
-
button: { background: 'blue' }
|
|
376
|
-
}}
|
|
377
|
-
onSuccess={(user) => console.log('Signed in:', user)}
|
|
378
|
-
onError={(error) => console.error('Error:', error)}
|
|
379
|
-
/>
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
**Props:**
|
|
383
|
-
- `afterSignInUrl`: Redirect URL after successful sign-in (default: `/`)
|
|
384
|
-
- `appearance`: Custom styles for container, form, and button
|
|
385
|
-
- `onSuccess`: Callback on successful sign-in
|
|
386
|
-
- `onError`: Callback on error
|
|
387
|
-
|
|
388
|
-
**Note:** OAuth providers are automatically detected from your backend configuration via `InsforgeProvider`. No need to manually specify them!
|
|
389
|
-
|
|
390
|
-
---
|
|
219
|
+
// app/layout.tsx
|
|
220
|
+
import { InsforgeProvider } from '@insforge/nextjs';
|
|
221
|
+
import '@insforge/nextjs/styles.css'; // Required for custom components
|
|
391
222
|
|
|
392
|
-
|
|
223
|
+
export default function RootLayout({ children }) {
|
|
224
|
+
return (
|
|
225
|
+
<InsforgeProvider
|
|
226
|
+
baseUrl={process.env.NEXT_PUBLIC_INSFORGE_BASE_URL!}
|
|
227
|
+
useBuiltInAuth={false}
|
|
228
|
+
>
|
|
229
|
+
{children}
|
|
230
|
+
</InsforgeProvider>
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
```
|
|
393
234
|
|
|
394
|
-
Pre-built
|
|
235
|
+
### Pre-built Components
|
|
395
236
|
|
|
396
237
|
```tsx
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
appearance={{
|
|
400
|
-
container: { background: '#f5f5f5' }
|
|
401
|
-
}}
|
|
402
|
-
/>
|
|
403
|
-
```
|
|
404
|
-
|
|
405
|
-
**Props:**
|
|
406
|
-
- `afterSignUpUrl`: Redirect URL after successful sign-up (default: `/`)
|
|
407
|
-
- `appearance`: Custom styles for container, form, and button
|
|
408
|
-
- `onSuccess`: Callback on successful sign-up
|
|
409
|
-
- `onError`: Callback on error
|
|
238
|
+
// app/sign-in/page.tsx
|
|
239
|
+
import { SignIn } from '@insforge/nextjs';
|
|
410
240
|
|
|
411
|
-
|
|
241
|
+
export default function SignInPage() {
|
|
242
|
+
return <SignIn afterSignInUrl="/dashboard" />;
|
|
243
|
+
}
|
|
244
|
+
```
|
|
412
245
|
|
|
413
|
-
|
|
246
|
+
OAuth providers are auto-detected from your backend config.
|
|
414
247
|
|
|
415
|
-
###
|
|
248
|
+
### Build from Primitives
|
|
416
249
|
|
|
417
|
-
For
|
|
250
|
+
For complete control:
|
|
418
251
|
|
|
419
252
|
```tsx
|
|
420
253
|
import {
|
|
421
254
|
AuthContainer,
|
|
422
255
|
AuthHeader,
|
|
423
|
-
AuthErrorBanner,
|
|
424
256
|
AuthFormField,
|
|
425
257
|
AuthPasswordField,
|
|
426
258
|
AuthSubmitButton,
|
|
427
|
-
AuthDivider,
|
|
428
|
-
AuthLink,
|
|
429
259
|
AuthOAuthProviders,
|
|
430
|
-
AuthBranding,
|
|
431
260
|
} from '@insforge/nextjs';
|
|
432
|
-
import '@insforge/nextjs/styles.css';
|
|
433
261
|
|
|
434
262
|
function CustomSignIn() {
|
|
435
|
-
|
|
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
|
-
);
|
|
263
|
+
// Build your own auth UI with full control
|
|
496
264
|
}
|
|
497
265
|
```
|
|
498
266
|
|
|
499
|
-
|
|
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
|
-
|
|
535
|
-
---
|
|
536
|
-
|
|
537
|
-
#### `<UserButton>`
|
|
538
|
-
|
|
539
|
-
User profile dropdown with sign-out functionality.
|
|
540
|
-
|
|
541
|
-
```tsx
|
|
542
|
-
<UserButton
|
|
543
|
-
afterSignOutUrl="/"
|
|
544
|
-
showEmail={true}
|
|
545
|
-
appearance={{
|
|
546
|
-
button: { borderRadius: '50%' },
|
|
547
|
-
dropdown: { minWidth: '250px' }
|
|
548
|
-
}}
|
|
549
|
-
/>
|
|
550
|
-
```
|
|
551
|
-
|
|
552
|
-
**Props:**
|
|
553
|
-
- `afterSignOutUrl`: Redirect URL after sign-out (default: `/`)
|
|
554
|
-
- `showEmail`: Show user email in dropdown (default: `true`)
|
|
555
|
-
- `appearance`: Custom styles for button and dropdown
|
|
556
|
-
|
|
557
|
-
---
|
|
558
|
-
|
|
559
|
-
#### `<SignedIn>`
|
|
560
|
-
|
|
561
|
-
Renders children only when user is authenticated.
|
|
562
|
-
|
|
563
|
-
```tsx
|
|
564
|
-
<SignedIn>
|
|
565
|
-
<Dashboard />
|
|
566
|
-
</SignedIn>
|
|
567
|
-
```
|
|
568
|
-
|
|
569
|
-
---
|
|
267
|
+
**Available primitives**: `AuthContainer`, `AuthHeader`, `AuthErrorBanner`, `AuthFormField`, `AuthPasswordField`, `AuthSubmitButton`, `AuthDivider`, `AuthLink`, `AuthOAuthProviders`, `AuthBranding`.
|
|
570
268
|
|
|
571
|
-
|
|
269
|
+
### Update Middleware
|
|
572
270
|
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
271
|
+
```ts
|
|
272
|
+
// middleware.ts
|
|
273
|
+
export default InsforgeMiddleware({
|
|
274
|
+
baseUrl: process.env.INSFORGE_BASE_URL!,
|
|
275
|
+
publicRoutes: ['/sign-in', '/sign-up', '/auth/callback', '/'],
|
|
276
|
+
signInUrl: '/sign-in',
|
|
277
|
+
useBuiltInAuth: false, // Important!
|
|
278
|
+
});
|
|
579
279
|
```
|
|
580
280
|
|
|
581
281
|
---
|
|
582
282
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
Protects content and optionally redirects unauthenticated users.
|
|
586
|
-
|
|
587
|
-
```tsx
|
|
588
|
-
<Protect
|
|
589
|
-
fallback={<Loading />}
|
|
590
|
-
redirectTo="/sign-in"
|
|
591
|
-
condition={(user) => user.role === 'admin'}
|
|
592
|
-
>
|
|
593
|
-
<AdminPanel />
|
|
594
|
-
</Protect>
|
|
595
|
-
```
|
|
596
|
-
|
|
597
|
-
**Props:**
|
|
598
|
-
- `fallback`: Component to show while loading or if unauthorized
|
|
599
|
-
- `redirectTo`: URL to redirect to if not authorized (default: `/sign-in`)
|
|
600
|
-
- `condition`: Optional function for custom authorization logic (e.g., role-based access)
|
|
601
|
-
|
|
602
|
-
---
|
|
283
|
+
## API Reference
|
|
603
284
|
|
|
604
285
|
### Hooks
|
|
605
286
|
|
|
606
287
|
#### `useAuth()`
|
|
607
288
|
|
|
608
|
-
Access complete auth state and methods.
|
|
609
|
-
|
|
610
289
|
```tsx
|
|
611
290
|
import { useAuth } from '@insforge/nextjs';
|
|
612
291
|
|
|
613
292
|
function Component() {
|
|
614
|
-
const {
|
|
615
|
-
|
|
616
|
-
session,
|
|
617
|
-
isLoaded,
|
|
618
|
-
isSignedIn,
|
|
619
|
-
signIn,
|
|
620
|
-
signUp,
|
|
621
|
-
signOut,
|
|
622
|
-
updateUser
|
|
623
|
-
} = useAuth();
|
|
624
|
-
|
|
625
|
-
if (!isLoaded) return <div>Loading...</div>;
|
|
626
|
-
if (!isSignedIn) return <div>Please sign in</div>;
|
|
627
|
-
|
|
628
|
-
return <div>Hello {user.email}</div>;
|
|
293
|
+
const { user, isSignedIn, signOut } = useAuth();
|
|
294
|
+
return <div>{user?.email}</div>;
|
|
629
295
|
}
|
|
630
296
|
```
|
|
631
297
|
|
|
632
|
-
**Returns
|
|
633
|
-
- `user`: Current user object or `null`
|
|
634
|
-
- `session`: Current session object or `null`
|
|
635
|
-
- `isLoaded`: Whether auth state has loaded
|
|
636
|
-
- `isSignedIn`: Whether user is authenticated
|
|
637
|
-
- `signIn(email, password)`: Sign in method
|
|
638
|
-
- `signUp(email, password)`: Sign up method
|
|
639
|
-
- `signOut()`: Sign out method
|
|
640
|
-
- `updateUser(data)`: Update user data
|
|
641
|
-
|
|
642
|
-
---
|
|
298
|
+
**Returns**: `user`, `session`, `isLoaded`, `isSignedIn`, `signIn()`, `signUp()`, `signOut()`, `updateUser()`
|
|
643
299
|
|
|
644
300
|
#### `useUser()`
|
|
645
301
|
|
|
646
|
-
Access current user data.
|
|
647
|
-
|
|
648
302
|
```tsx
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
function Component() {
|
|
652
|
-
const { user, isLoaded } = useUser();
|
|
653
|
-
|
|
654
|
-
if (!isLoaded) return <div>Loading...</div>;
|
|
655
|
-
if (!user) return <div>Not signed in</div>;
|
|
656
|
-
|
|
657
|
-
return <div>{user.email}</div>;
|
|
658
|
-
}
|
|
303
|
+
const { user, isLoaded } = useUser();
|
|
659
304
|
```
|
|
660
305
|
|
|
661
|
-
---
|
|
662
|
-
|
|
663
306
|
#### `useSession()`
|
|
664
307
|
|
|
665
|
-
Access current session data.
|
|
666
|
-
|
|
667
308
|
```tsx
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
function Component() {
|
|
671
|
-
const { session, isLoaded, isSignedIn } = useSession();
|
|
672
|
-
|
|
673
|
-
return <div>Signed in: {isSignedIn ? 'Yes' : 'No'}</div>;
|
|
674
|
-
}
|
|
309
|
+
const { session, isSignedIn } = useSession();
|
|
675
310
|
```
|
|
676
311
|
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
### API Route Handlers
|
|
312
|
+
### Components
|
|
680
313
|
|
|
681
|
-
####
|
|
314
|
+
#### `<SignIn>` / `<SignUp>`
|
|
682
315
|
|
|
683
|
-
|
|
316
|
+
Pre-built auth forms (only with `useBuiltInAuth={false}`):
|
|
684
317
|
|
|
685
318
|
```tsx
|
|
686
|
-
|
|
687
|
-
|
|
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
|
-
});
|
|
319
|
+
<SignIn afterSignInUrl="/dashboard" />
|
|
320
|
+
<SignUp afterSignUpUrl="/onboarding" />
|
|
722
321
|
```
|
|
723
322
|
|
|
724
|
-
**
|
|
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
|
-
---
|
|
323
|
+
**Props**: `afterSignInUrl`/`afterSignUpUrl`, `appearance`, `onSuccess`, `onError`
|
|
730
324
|
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
#### `InsforgeMiddleware(config)`
|
|
734
|
-
|
|
735
|
-
Create Next.js middleware for route protection.
|
|
736
|
-
|
|
737
|
-
```ts
|
|
738
|
-
import { InsforgeMiddleware } from '@insforge/nextjs/middleware';
|
|
325
|
+
#### `<UserButton>`
|
|
739
326
|
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
publicRoutes: ['/sign-in', '/sign-up', '/', '/about'],
|
|
743
|
-
signInUrl: '/sign-in',
|
|
744
|
-
cookieName: 'insforge_token',
|
|
745
|
-
});
|
|
327
|
+
```tsx
|
|
328
|
+
<UserButton afterSignOutUrl="/" showEmail={true} />
|
|
746
329
|
```
|
|
747
330
|
|
|
748
|
-
|
|
749
|
-
- `baseUrl` (required): Your Insforge backend URL
|
|
750
|
-
- `publicRoutes`: Array of routes that don't require auth (supports wildcards: `/blog/*`)
|
|
751
|
-
- `signInUrl`: URL to redirect to when not authenticated (default: `/sign-in`)
|
|
752
|
-
- `cookieName`: Cookie name for auth token (default: `insforge_token`)
|
|
331
|
+
#### `<SignedIn>` / `<SignedOut>` / `<Protect>`
|
|
753
332
|
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
#### `getAuthUserId(headers)` and `getAuthToken(headers)`
|
|
333
|
+
```tsx
|
|
334
|
+
<SignedIn><Dashboard /></SignedIn>
|
|
335
|
+
<SignedOut><LandingPage /></SignedOut>
|
|
336
|
+
<Protect condition={(user) => user.role === 'admin'}><AdminPanel /></Protect>
|
|
337
|
+
```
|
|
761
338
|
|
|
762
|
-
|
|
339
|
+
### Server-Side Helpers
|
|
763
340
|
|
|
764
341
|
```tsx
|
|
342
|
+
// app/dashboard/page.tsx (Server Component)
|
|
765
343
|
import { headers } from 'next/headers';
|
|
766
344
|
import { getAuthUserId, getAuthToken } from '@insforge/nextjs/middleware';
|
|
767
345
|
|
|
768
|
-
export default async function
|
|
346
|
+
export default async function Dashboard() {
|
|
769
347
|
const userId = getAuthUserId(headers());
|
|
770
348
|
const token = getAuthToken(headers());
|
|
771
|
-
|
|
772
|
-
// Fetch user
|
|
773
|
-
const data = await fetchUserData(userId, token);
|
|
774
|
-
|
|
349
|
+
|
|
350
|
+
// Fetch user data server-side
|
|
775
351
|
return <div>User ID: {userId}</div>;
|
|
776
352
|
}
|
|
777
|
-
```
|
|
778
353
|
|
|
779
|
-
|
|
780
|
-
- `getAuthUser` - Deprecated alias for `getAuthUserId` (backward compatibility)
|
|
354
|
+
```
|
|
781
355
|
|
|
782
356
|
---
|
|
783
357
|
|
|
784
|
-
##
|
|
785
|
-
|
|
786
|
-
This package uses **standalone CSS** for styling - no Tailwind CSS dependency required! All components come pre-styled and ready to use.
|
|
358
|
+
## Customization
|
|
787
359
|
|
|
788
|
-
###
|
|
360
|
+
### Styling (Custom Components Only)
|
|
789
361
|
|
|
790
|
-
|
|
362
|
+
When using `useBuiltInAuth={false}`, import styles:
|
|
791
363
|
|
|
792
364
|
```tsx
|
|
793
|
-
// app/layout.tsx
|
|
794
365
|
import '@insforge/nextjs/styles.css';
|
|
795
366
|
```
|
|
796
367
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
### Typography
|
|
800
|
-
|
|
801
|
-
The package includes the **Manrope variable font** for a modern, professional look. The font is automatically loaded and available as a CSS variable:
|
|
802
|
-
|
|
803
|
-
```css
|
|
804
|
-
/* Use the font in your own CSS */
|
|
805
|
-
.my-component {
|
|
806
|
-
font-family: var(--font-manrope);
|
|
807
|
-
}
|
|
808
|
-
```
|
|
809
|
-
|
|
810
|
-
The font family includes fallbacks to system fonts for optimal loading:
|
|
811
|
-
- `--font-manrope`: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif
|
|
812
|
-
|
|
813
|
-
### Customization
|
|
814
|
-
|
|
815
|
-
**Option 1: Text Customization** (Easiest)
|
|
816
|
-
|
|
817
|
-
All text elements in the components can be customized via props:
|
|
818
|
-
|
|
819
|
-
```tsx
|
|
820
|
-
<SignIn
|
|
821
|
-
baseUrl="..."
|
|
822
|
-
// Customize all text
|
|
823
|
-
title="Welcome Back to MyApp"
|
|
824
|
-
subtitle="We're happy to see you again"
|
|
825
|
-
emailLabel="Your Email"
|
|
826
|
-
emailPlaceholder="you@company.com"
|
|
827
|
-
passwordLabel="Your Password"
|
|
828
|
-
forgotPasswordText="Forgot it?"
|
|
829
|
-
submitButtonText="Log In"
|
|
830
|
-
loadingButtonText="Logging in..."
|
|
831
|
-
signUpText="New user?"
|
|
832
|
-
signUpLinkText="Create an account"
|
|
833
|
-
signUpUrl="/register"
|
|
834
|
-
dividerText="or continue with"
|
|
835
|
-
/>
|
|
836
|
-
|
|
837
|
-
<SignUp
|
|
838
|
-
baseUrl="..."
|
|
839
|
-
// Customize signup text
|
|
840
|
-
title="Join MyApp Today"
|
|
841
|
-
subtitle="Create your account in seconds"
|
|
842
|
-
submitButtonText="Create Account"
|
|
843
|
-
signInText="Existing user?"
|
|
844
|
-
signInLinkText="Log in here"
|
|
845
|
-
/>
|
|
846
|
-
```
|
|
847
|
-
|
|
848
|
-
**Option 2: Style Customization**
|
|
849
|
-
|
|
850
|
-
Override inline styles for specific components:
|
|
368
|
+
Override with `appearance` prop or CSS classes:
|
|
851
369
|
|
|
852
370
|
```tsx
|
|
853
|
-
<SignIn
|
|
854
|
-
appearance={{
|
|
855
|
-
container: {
|
|
856
|
-
background: 'linear-gradient(to right, #4f46e5, #7c3aed)'
|
|
857
|
-
},
|
|
858
|
-
form: {
|
|
859
|
-
padding: '3rem',
|
|
860
|
-
borderRadius: '16px'
|
|
861
|
-
},
|
|
862
|
-
button: {
|
|
863
|
-
background: '#4f46e5',
|
|
864
|
-
color: 'white'
|
|
865
|
-
}
|
|
866
|
-
}}
|
|
867
|
-
/>
|
|
371
|
+
<SignIn appearance={{ container: { background: '#f5f5f5' } }} />
|
|
868
372
|
```
|
|
869
373
|
|
|
870
|
-
**Option 3: Override CSS Classes**
|
|
871
|
-
|
|
872
|
-
All components use semantic CSS class names prefixed with `insforge-`:
|
|
873
|
-
|
|
874
374
|
```css
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
/* Customize the primary button */
|
|
878
|
-
.insforge-btn-primary {
|
|
879
|
-
background: #8b5cf6;
|
|
880
|
-
border-radius: 12px;
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
/* Customize form inputs */
|
|
884
|
-
.insforge-input {
|
|
885
|
-
border-color: #e0e0e0;
|
|
886
|
-
border-radius: 8px;
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
/* Customize the auth card */
|
|
890
|
-
.insforge-auth-card {
|
|
891
|
-
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.15);
|
|
892
|
-
}
|
|
375
|
+
.insforge-btn-primary { background: #8b5cf6; }
|
|
893
376
|
```
|
|
894
377
|
|
|
895
|
-
|
|
896
|
-
- `.insforge-auth-container` - Main container
|
|
897
|
-
- `.insforge-auth-card` - Form card
|
|
898
|
-
- `.insforge-input` - Input fields
|
|
899
|
-
- `.insforge-btn-primary` - Primary buttons
|
|
900
|
-
- `.insforge-oauth-btn` - OAuth buttons
|
|
901
|
-
- `.insforge-user-button` - User menu button
|
|
902
|
-
- `.insforge-error-banner` - Error messages
|
|
903
|
-
|
|
904
|
-
---
|
|
905
|
-
|
|
906
|
-
## Advanced Usage
|
|
907
|
-
|
|
908
|
-
### Role-Based Access Control
|
|
378
|
+
### Auth Callbacks
|
|
909
379
|
|
|
910
380
|
```tsx
|
|
911
|
-
<
|
|
912
|
-
<AdminDashboard />
|
|
913
|
-
</Protect>
|
|
914
|
-
```
|
|
915
|
-
|
|
916
|
-
### Custom Auth Callbacks
|
|
917
|
-
|
|
918
|
-
```tsx
|
|
919
|
-
<InsforgeProvider
|
|
381
|
+
<InsforgeProvider
|
|
920
382
|
baseUrl={baseUrl}
|
|
921
|
-
onAuthChange={(user) =>
|
|
922
|
-
|
|
923
|
-
analytics.identify(user.id);
|
|
924
|
-
} else {
|
|
925
|
-
analytics.reset();
|
|
926
|
-
}
|
|
927
|
-
}}
|
|
928
|
-
>
|
|
929
|
-
{children}
|
|
930
|
-
</InsforgeProvider>
|
|
931
|
-
```
|
|
932
|
-
|
|
933
|
-
### Server-Side User Data
|
|
934
|
-
|
|
935
|
-
```tsx
|
|
936
|
-
// app/dashboard/page.tsx
|
|
937
|
-
import { headers } from 'next/headers';
|
|
938
|
-
import { getAuthUserId } from '@insforge/nextjs/middleware';
|
|
939
|
-
import { createClient } from '@insforge/sdk';
|
|
940
|
-
|
|
941
|
-
export default async function Dashboard() {
|
|
942
|
-
const userId = getAuthUserId(headers());
|
|
943
|
-
|
|
944
|
-
const insforge = createClient({
|
|
945
|
-
baseUrl: process.env.INSFORGE_BASE_URL!
|
|
946
|
-
});
|
|
947
|
-
|
|
948
|
-
const user = await insforge.auth.getUserById(userId);
|
|
949
|
-
|
|
950
|
-
return <div>Welcome {user.email}</div>;
|
|
951
|
-
}
|
|
952
|
-
```
|
|
953
|
-
|
|
954
|
-
---
|
|
955
|
-
|
|
956
|
-
## Environment Variables
|
|
957
|
-
|
|
958
|
-
Create a `.env.local` file:
|
|
959
|
-
|
|
960
|
-
```env
|
|
961
|
-
# Public (accessible in browser)
|
|
962
|
-
NEXT_PUBLIC_INSFORGE_BASE_URL=https://your-backend.insforge.app
|
|
963
|
-
|
|
964
|
-
# Server-only (middleware)
|
|
965
|
-
INSFORGE_BASE_URL=https://your-backend.insforge.app
|
|
383
|
+
onAuthChange={(user) => user && analytics.identify(user.id)}
|
|
384
|
+
/>
|
|
966
385
|
```
|
|
967
386
|
|
|
968
387
|
---
|
|
969
388
|
|
|
970
389
|
## Why @insforge/nextjs?
|
|
971
390
|
|
|
972
|
-
|
|
973
|
-
- **Faster Development**: Drop-in components save hours of auth implementation
|
|
974
|
-
- **Best Practices**: Built-in security, session management, and error handling
|
|
975
|
-
- **Flexible**: Fully customizable while providing sensible defaults
|
|
976
|
-
- **Explicit Configuration**: OAuth providers passed as props - no hidden API calls or magic
|
|
977
|
-
|
|
978
|
-
### For AI Agents
|
|
979
|
-
- **Reduced Token Usage**: Pre-built components mean agents don't rebuild UI each time
|
|
980
|
-
- **Consistent UX**: Standard patterns across projects
|
|
981
|
-
- **Less Context**: Import and use instead of implementing from scratch
|
|
982
|
-
- **Discoverable**: Query `/api/metadata/auth` via MCP to get OAuth config, then generate code with correct `providers` prop
|
|
983
|
-
|
|
984
|
-
### AI Agent Workflow with Insforge MCP
|
|
391
|
+
**For Developers**: 5-minute auth setup instead of hours. Production-ready security and session management included.
|
|
985
392
|
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
1. **Connect to Insforge MCP** - Access the user's Insforge backend
|
|
989
|
-
2. **Generate code** - Use `<SignIn>` and `<SignUp>` components
|
|
990
|
-
3. **Automatic configuration** - OAuth providers are detected automatically from backend
|
|
991
|
-
|
|
992
|
-
**Agent generates:**
|
|
993
|
-
```tsx
|
|
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" />
|
|
1001
|
-
```
|
|
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
|
|
393
|
+
**For AI Agents**: Minimal code generation (5 files vs 20+ for custom auth). Reduced token usage. Consistent patterns across projects.
|
|
1007
394
|
|
|
1008
395
|
---
|
|
1009
396
|
|
|
1010
397
|
## TypeScript
|
|
1011
398
|
|
|
1012
|
-
Full TypeScript support with exported types:
|
|
1013
|
-
|
|
1014
399
|
```tsx
|
|
1015
|
-
import type {
|
|
1016
|
-
InsforgeUser,
|
|
1017
|
-
InsforgeSession,
|
|
1018
|
-
AuthContextValue,
|
|
1019
|
-
SignInProps,
|
|
1020
|
-
ProtectProps
|
|
1021
|
-
} from '@insforge/nextjs';
|
|
400
|
+
import type { InsforgeUser, InsforgeSession, AuthContextValue } from '@insforge/nextjs';
|
|
1022
401
|
```
|
|
1023
402
|
|
|
1024
403
|
---
|
|
1025
404
|
|
|
1026
|
-
##
|
|
1027
|
-
|
|
1028
|
-
Check out the `/examples` directory for:
|
|
1029
|
-
- Basic Next.js App Router setup
|
|
1030
|
-
- Role-based access control
|
|
1031
|
-
- Custom styling
|
|
1032
|
-
- Server-side data fetching
|
|
405
|
+
## Support
|
|
1033
406
|
|
|
1034
|
-
|
|
407
|
+
- **Docs**: https://docs.insforge.dev/introduction
|
|
408
|
+
- **Issues**: https://github.com/InsForge/InsForge/issues
|
|
409
|
+
- **Discord**: https://discord.com/invite/DvBtaEc9Jz
|
|
1035
410
|
|
|
1036
411
|
## License
|
|
1037
412
|
|
|
1038
413
|
MIT
|
|
1039
|
-
|
|
1040
|
-
---
|
|
1041
|
-
|
|
1042
|
-
## Support
|
|
1043
|
-
|
|
1044
|
-
- Documentation: https://docs.insforge.dev/introduction
|
|
1045
|
-
- Issues: https://github.com/InsForge/InsForge/issues
|
|
1046
|
-
- Discord: https://discord.com/invite/DvBtaEc9Jz
|