@insforge/react 1.1.4 → 1.1.6-test.0
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 +718 -718
- package/dist/atoms.cjs +1 -0
- package/dist/atoms.cjs.map +1 -1
- package/dist/atoms.js +1 -0
- package/dist/atoms.js.map +1 -1
- package/dist/components.cjs +125 -5
- package/dist/components.cjs.map +1 -1
- package/dist/components.js +125 -5
- package/dist/components.js.map +1 -1
- package/dist/forms.cjs +1 -0
- package/dist/forms.cjs.map +1 -1
- package/dist/forms.js +1 -0
- package/dist/forms.js.map +1 -1
- package/dist/hooks.cjs +1 -0
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.js +1 -0
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +149 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +148 -7
- package/dist/index.js.map +1 -1
- package/dist/lib.cjs +30 -0
- package/dist/lib.cjs.map +1 -1
- package/dist/lib.d.cts +39 -1
- package/dist/lib.d.ts +39 -1
- package/dist/lib.js +29 -1
- package/dist/lib.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,718 +1,718 @@
|
|
|
1
|
-
# @insforge/react
|
|
2
|
-
|
|
3
|
-
**Framework-agnostic authentication solution for React applications.** Production-ready components with full business logic included.
|
|
4
|
-
|
|
5
|
-
> **✨ CSS-in-JS**: All components now use Emotion CSS-in-JS for zero FOUC in SSR environments. No CSS imports needed!
|
|
6
|
-
|
|
7
|
-
## Why @insforge/react?
|
|
8
|
-
|
|
9
|
-
✅ **Framework Agnostic** - Works with any React setup (Vite, CRA, or no bundler)
|
|
10
|
-
✅ **Zero Router Dependencies** - Built-in navigation abstraction works with any routing solution
|
|
11
|
-
✅ **Route Protection** - Built-in `RouteGuard` for vanilla React apps
|
|
12
|
-
✅ **Production Ready** - Complete auth flows with business logic included
|
|
13
|
-
✅ **Full TypeScript** - Complete type safety out of the box
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## Quick Start
|
|
18
|
-
|
|
19
|
-
Get authentication working in your React app in 5 minutes.
|
|
20
|
-
|
|
21
|
-
### 1. Install
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
npm install @insforge/react
|
|
25
|
-
# or
|
|
26
|
-
yarn add @insforge/react
|
|
27
|
-
# or
|
|
28
|
-
pnpm add @insforge/react
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
#### Environment Variables
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
# .env
|
|
35
|
-
VITE_INSFORGE_BASE_URL=https://your-project.insforge.app/
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
### 2. Setup Provider & Route Guard
|
|
39
|
-
|
|
40
|
-
Wrap your app with `InsforgeProvider`:
|
|
41
|
-
|
|
42
|
-
```tsx
|
|
43
|
-
// src/main.tsx (Vite) or src/index.tsx (CRA)
|
|
44
|
-
import { StrictMode } from 'react';
|
|
45
|
-
import { createRoot } from 'react-dom/client';
|
|
46
|
-
import { InsforgeProvider } from '@insforge/react';
|
|
47
|
-
import App from './App';
|
|
48
|
-
|
|
49
|
-
createRoot(document.getElementById('root')!).render(
|
|
50
|
-
<StrictMode>
|
|
51
|
-
<InsforgeProvider baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL}>
|
|
52
|
-
<App />
|
|
53
|
-
</InsforgeProvider>
|
|
54
|
-
</StrictMode>
|
|
55
|
-
);
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### 3. Use Components & Hooks
|
|
59
|
-
|
|
60
|
-
Now you can use authentication components and hooks anywhere in your app:
|
|
61
|
-
|
|
62
|
-
```tsx
|
|
63
|
-
// src/App.tsx
|
|
64
|
-
import { SignInButton, SignUpButton, SignedIn, SignedOut, UserButton } from '@insforge/react';
|
|
65
|
-
|
|
66
|
-
export default function App() {
|
|
67
|
-
return (
|
|
68
|
-
<div>
|
|
69
|
-
<SignedOut>
|
|
70
|
-
<SignInButton />
|
|
71
|
-
<SignUpButton />
|
|
72
|
-
</SignedOut>
|
|
73
|
-
|
|
74
|
-
<SignedIn>
|
|
75
|
-
<nav>
|
|
76
|
-
<UserButton />
|
|
77
|
-
</nav>
|
|
78
|
-
<h1>Welcome to your dashboard!</h1>
|
|
79
|
-
</SignedIn>
|
|
80
|
-
</div>
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
**That's it!** 🎉 Your app is now protected with authentication.
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
## Usage Patterns
|
|
90
|
-
|
|
91
|
-
### Option 1: Pre-built Components (Fastest)
|
|
92
|
-
|
|
93
|
-
Use complete auth flows with built-in UI and logic:
|
|
94
|
-
|
|
95
|
-
```tsx
|
|
96
|
-
import { SignIn, SignUp, ForgotPassword, ResetPassword } from '@insforge/react';
|
|
97
|
-
|
|
98
|
-
// In your app
|
|
99
|
-
<SignIn /> // Complete sign-in flow
|
|
100
|
-
<SignUp /> // Complete sign-up flow with email verification
|
|
101
|
-
<ForgotPassword /> // Password reset request + verification
|
|
102
|
-
<ResetPassword /> // Reset password with token (from URL params)
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Option 2: Form Components (UI Only)
|
|
106
|
-
|
|
107
|
-
Use UI components and add your own logic:
|
|
108
|
-
|
|
109
|
-
```tsx
|
|
110
|
-
import { SignInForm, useAuth } from '@insforge/react';
|
|
111
|
-
import { useState } from 'react';
|
|
112
|
-
|
|
113
|
-
function CustomSignIn() {
|
|
114
|
-
const { signIn } = useAuth();
|
|
115
|
-
const [email, setEmail] = useState('');
|
|
116
|
-
const [password, setPassword] = useState('');
|
|
117
|
-
const [error, setError] = useState('');
|
|
118
|
-
const [loading, setLoading] = useState(false);
|
|
119
|
-
|
|
120
|
-
const handleSubmit = async (e) => {
|
|
121
|
-
e.preventDefault();
|
|
122
|
-
setLoading(true);
|
|
123
|
-
const result = await signIn(email, password);
|
|
124
|
-
if ('error' in result) {
|
|
125
|
-
setError(result.error);
|
|
126
|
-
}
|
|
127
|
-
setLoading(false);
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
return (
|
|
131
|
-
<SignInForm
|
|
132
|
-
email={email}
|
|
133
|
-
password={password}
|
|
134
|
-
onEmailChange={setEmail}
|
|
135
|
-
onPasswordChange={setPassword}
|
|
136
|
-
onSubmit={handleSubmit}
|
|
137
|
-
error={error}
|
|
138
|
-
loading={loading}
|
|
139
|
-
/>
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### Option 3: Hooks Only (Headless)
|
|
145
|
-
|
|
146
|
-
Build completely custom UI using authentication hooks:
|
|
147
|
-
|
|
148
|
-
```tsx
|
|
149
|
-
import { useAuth } from '@insforge/react';
|
|
150
|
-
|
|
151
|
-
function CustomAuthForm() {
|
|
152
|
-
const { signIn, signUp, isLoaded } = useAuth();
|
|
153
|
-
|
|
154
|
-
const handleLogin = async (email: string, password: string) => {
|
|
155
|
-
const result = await signIn(email, password);
|
|
156
|
-
if ('error' in result) {
|
|
157
|
-
console.error(result.error);
|
|
158
|
-
} else {
|
|
159
|
-
console.log('Signed in!');
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
return <form>...your custom UI...</form>;
|
|
164
|
-
}
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
---
|
|
168
|
-
|
|
169
|
-
## Core Features
|
|
170
|
-
|
|
171
|
-
### Components
|
|
172
|
-
|
|
173
|
-
**Pre-built with Business Logic:**
|
|
174
|
-
|
|
175
|
-
- `<SignIn />` - Complete sign-in with email/password & OAuth
|
|
176
|
-
- `<SignUp />` - Registration with password validation & email verification
|
|
177
|
-
- `<ForgotPassword />` - Request password reset with email validation
|
|
178
|
-
- `<ResetPassword />` - Reset password with token validation
|
|
179
|
-
- `<VerifyEmail />` - Verify email with automatic token handling
|
|
180
|
-
- `<UserButton />` - User dropdown with sign-out
|
|
181
|
-
- `<RouteGuard />` - **NEW:** App-level route protection for vanilla React
|
|
182
|
-
- `<Protect />` - Component-level protection wrapper
|
|
183
|
-
- `<SignedIn>` / `<SignedOut>` - Conditional rendering
|
|
184
|
-
|
|
185
|
-
**Form Components (Pure UI):**
|
|
186
|
-
|
|
187
|
-
- `<SignInForm />` - Sign-in UI without logic
|
|
188
|
-
- `<SignUpForm />` - Sign-up UI without logic
|
|
189
|
-
- `<ForgotPasswordForm />` - Password reset request UI
|
|
190
|
-
- `<ResetPasswordForm />` - Password reset with token UI
|
|
191
|
-
- `<VerifyEmailStatus />` - Email verification status UI
|
|
192
|
-
|
|
193
|
-
**Atomic Components (14 total):**
|
|
194
|
-
|
|
195
|
-
- `<AuthContainer />`, `<AuthHeader />`, `<AuthFormField />`, `<AuthPasswordField />`, `<AuthEmailVerificationStep />`, etc.
|
|
196
|
-
|
|
197
|
-
### Hooks
|
|
198
|
-
|
|
199
|
-
```tsx
|
|
200
|
-
// Authentication state and methods
|
|
201
|
-
const {
|
|
202
|
-
signIn,
|
|
203
|
-
signUp,
|
|
204
|
-
signOut,
|
|
205
|
-
isSignedIn,
|
|
206
|
-
isLoaded,
|
|
207
|
-
baseUrl, // From provider
|
|
208
|
-
afterSignInUrl, // From provider
|
|
209
|
-
} = useAuth();
|
|
210
|
-
|
|
211
|
-
// Or use useInsforge (same as useAuth)
|
|
212
|
-
const context = useInsforge();
|
|
213
|
-
|
|
214
|
-
// User information
|
|
215
|
-
const { user, updateUser, isLoaded } = useUser();
|
|
216
|
-
|
|
217
|
-
// Public auth configuration (OAuth providers, password requirements, etc.)
|
|
218
|
-
const { oauthProviders, authConfig, isLoaded } = usePublicAuthConfig();
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
---
|
|
222
|
-
|
|
223
|
-
## Customization
|
|
224
|
-
|
|
225
|
-
### Text Customization
|
|
226
|
-
|
|
227
|
-
All components support full text customization:
|
|
228
|
-
|
|
229
|
-
```tsx
|
|
230
|
-
<SignIn
|
|
231
|
-
title="Welcome Back!"
|
|
232
|
-
subtitle="We're happy to see you again"
|
|
233
|
-
emailLabel="Your Email Address"
|
|
234
|
-
emailPlaceholder="you@company.com"
|
|
235
|
-
passwordLabel="Your Password"
|
|
236
|
-
submitButtonText="Login Now"
|
|
237
|
-
loadingButtonText="Signing you in..."
|
|
238
|
-
signUpText="New to our platform?"
|
|
239
|
-
signUpLinkText="Create an account"
|
|
240
|
-
dividerText="or continue with"
|
|
241
|
-
/>
|
|
242
|
-
|
|
243
|
-
<ForgotPassword
|
|
244
|
-
title="Reset Your Password"
|
|
245
|
-
subtitle="Enter your email to receive a reset code"
|
|
246
|
-
emailLabel="Email Address"
|
|
247
|
-
submitButtonText="Send Reset Code"
|
|
248
|
-
backToSignInText="Remember your password?"
|
|
249
|
-
successTitle="Check Your Email"
|
|
250
|
-
successMessage="We've sent a reset code to your inbox"
|
|
251
|
-
/>
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
---
|
|
255
|
-
|
|
256
|
-
## Advanced Usage
|
|
257
|
-
|
|
258
|
-
### Conditional Rendering
|
|
259
|
-
|
|
260
|
-
Control what users see based on auth state:
|
|
261
|
-
|
|
262
|
-
```tsx
|
|
263
|
-
import { SignedIn, SignedOut, Protect } from '@insforge/react';
|
|
264
|
-
|
|
265
|
-
function App() {
|
|
266
|
-
return (
|
|
267
|
-
<>
|
|
268
|
-
<SignedOut>
|
|
269
|
-
<SignIn />
|
|
270
|
-
</SignedOut>
|
|
271
|
-
|
|
272
|
-
<SignedIn>
|
|
273
|
-
<Dashboard />
|
|
274
|
-
</SignedIn>
|
|
275
|
-
|
|
276
|
-
{/* Or use Protect for specific sections */}
|
|
277
|
-
<Protect redirectTo="/sign-in">
|
|
278
|
-
<ProtectedContent />
|
|
279
|
-
</Protect>
|
|
280
|
-
</>
|
|
281
|
-
);
|
|
282
|
-
}
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
### Build from Atomic Components
|
|
286
|
-
|
|
287
|
-
```tsx
|
|
288
|
-
import {
|
|
289
|
-
AuthContainer,
|
|
290
|
-
AuthHeader,
|
|
291
|
-
AuthFormField,
|
|
292
|
-
AuthPasswordField,
|
|
293
|
-
AuthSubmitButton,
|
|
294
|
-
AuthErrorBanner,
|
|
295
|
-
AuthDivider,
|
|
296
|
-
AuthOAuthProviders,
|
|
297
|
-
AuthLink,
|
|
298
|
-
} from '@insforge/react';
|
|
299
|
-
|
|
300
|
-
function CompletelyCustomAuth() {
|
|
301
|
-
return (
|
|
302
|
-
<AuthContainer>
|
|
303
|
-
<AuthHeader title="Welcome to MyApp" subtitle="Sign in to continue" />
|
|
304
|
-
|
|
305
|
-
<AuthErrorBanner error={error} />
|
|
306
|
-
|
|
307
|
-
<form onSubmit={handleSubmit}>
|
|
308
|
-
<AuthFormField
|
|
309
|
-
id="email"
|
|
310
|
-
type="email"
|
|
311
|
-
label="Email"
|
|
312
|
-
value={email}
|
|
313
|
-
onChange={(e) => setEmail(e.target.value)}
|
|
314
|
-
/>
|
|
315
|
-
|
|
316
|
-
<AuthPasswordField
|
|
317
|
-
id="password"
|
|
318
|
-
label="Password"
|
|
319
|
-
value={password}
|
|
320
|
-
onChange={(e) => setPassword(e.target.value)}
|
|
321
|
-
authConfig={config}
|
|
322
|
-
showStrengthIndicator
|
|
323
|
-
/>
|
|
324
|
-
|
|
325
|
-
<AuthSubmitButton isLoading={loading}>Sign In</AuthSubmitButton>
|
|
326
|
-
</form>
|
|
327
|
-
|
|
328
|
-
<AuthDivider text="or" />
|
|
329
|
-
|
|
330
|
-
<AuthOAuthProviders
|
|
331
|
-
providers={['google', 'github', 'discord']}
|
|
332
|
-
onClick={handleOAuth}
|
|
333
|
-
loading={oauthLoading}
|
|
334
|
-
/>
|
|
335
|
-
|
|
336
|
-
<AuthLink text="Don't have an account?" linkText="Sign up" href="/sign-up" />
|
|
337
|
-
</AuthContainer>
|
|
338
|
-
);
|
|
339
|
-
}
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
### Content Protection
|
|
343
|
-
|
|
344
|
-
Protect specific content or sections:
|
|
345
|
-
|
|
346
|
-
```tsx
|
|
347
|
-
import { Protect } from '@insforge/react';
|
|
348
|
-
|
|
349
|
-
function Dashboard() {
|
|
350
|
-
return (
|
|
351
|
-
<div>
|
|
352
|
-
<h1>Dashboard</h1>
|
|
353
|
-
|
|
354
|
-
{/* Simple protection - shows nothing if not signed in */}
|
|
355
|
-
<Protect>
|
|
356
|
-
<UserContent />
|
|
357
|
-
</Protect>
|
|
358
|
-
|
|
359
|
-
{/* With redirect */}
|
|
360
|
-
<Protect redirectTo="/sign-in">
|
|
361
|
-
<UserContent />
|
|
362
|
-
</Protect>
|
|
363
|
-
|
|
364
|
-
{/* Custom condition - e.g., role-based */}
|
|
365
|
-
<Protect condition={(user) => user.email.endsWith('@admin.com')} redirectTo="/unauthorized">
|
|
366
|
-
<AdminPanel />
|
|
367
|
-
</Protect>
|
|
368
|
-
</div>
|
|
369
|
-
);
|
|
370
|
-
}
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
> **Note:** `<Protect>` is for component-level conditional rendering. For app-level route protection, use `<RouteGuard>`
|
|
374
|
-
|
|
375
|
-
---
|
|
376
|
-
|
|
377
|
-
## Route Protection (Detailed)
|
|
378
|
-
|
|
379
|
-
### RouteGuard for Vanilla React
|
|
380
|
-
|
|
381
|
-
`RouteGuard` provides app-level authentication protection without requiring any routing library.
|
|
382
|
-
|
|
383
|
-
#### Option 1: External Built-in Auth (Simplest)
|
|
384
|
-
|
|
385
|
-
Redirects to your deployed Insforge Auth pages:
|
|
386
|
-
|
|
387
|
-
```tsx
|
|
388
|
-
import { InsforgeProvider, RouteGuard } from '@insforge/react';
|
|
389
|
-
|
|
390
|
-
createRoot(document.getElementById('root')!).render(
|
|
391
|
-
<InsforgeProvider baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL} afterSignInUrl="/dashboard">
|
|
392
|
-
<RouteGuard
|
|
393
|
-
builtInAuth
|
|
394
|
-
publicRoutes={['/', '/about', '/pricing']}
|
|
395
|
-
loadingFallback={<div>Loading...</div>}
|
|
396
|
-
>
|
|
397
|
-
<App />
|
|
398
|
-
</RouteGuard>
|
|
399
|
-
</InsforgeProvider>
|
|
400
|
-
);
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
**Behavior:**
|
|
404
|
-
|
|
405
|
-
- User visits `/sign-in` → Redirects to `baseUrl/auth/sign-in`
|
|
406
|
-
- User visits `/sign-up` → Redirects to `baseUrl/auth/sign-up`
|
|
407
|
-
- User visits `/dashboard` (protected) → Redirects to `baseUrl/auth/sign-in`
|
|
408
|
-
- User visits `/` (public) → ✅ Renders normally
|
|
409
|
-
|
|
410
|
-
#### Option 2: Custom Auth Pages
|
|
411
|
-
|
|
412
|
-
Use @insforge/react components in your own app:
|
|
413
|
-
|
|
414
|
-
```tsx
|
|
415
|
-
import { InsforgeProvider, RouteGuard, SignIn, SignUp } from '@insforge/react';
|
|
416
|
-
|
|
417
|
-
// Simple hash-based routing
|
|
418
|
-
function App() {
|
|
419
|
-
const path = window.location.hash.slice(1) || '/';
|
|
420
|
-
|
|
421
|
-
return (
|
|
422
|
-
<>
|
|
423
|
-
{path === '/login' && <SignIn />}
|
|
424
|
-
{path === '/register' && <SignUp />}
|
|
425
|
-
{path === '/dashboard' && <Dashboard />}
|
|
426
|
-
{path === '/' && <HomePage />}
|
|
427
|
-
</>
|
|
428
|
-
);
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
createRoot(document.getElementById('root')!).render(
|
|
432
|
-
<InsforgeProvider baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL}>
|
|
433
|
-
<RouteGuard
|
|
434
|
-
builtInAuth={false}
|
|
435
|
-
publicRoutes={['/login', '/register', '/forgot-password', '/']}
|
|
436
|
-
paths={{ signIn: '/login', signUp: '/register' }}
|
|
437
|
-
loadingFallback={<div>Loading...</div>}
|
|
438
|
-
>
|
|
439
|
-
<App />
|
|
440
|
-
</RouteGuard>
|
|
441
|
-
</InsforgeProvider>
|
|
442
|
-
);
|
|
443
|
-
```
|
|
444
|
-
|
|
445
|
-
**Behavior:**
|
|
446
|
-
|
|
447
|
-
- User visits `/login` → ✅ Renders `<SignIn />` (in publicRoutes)
|
|
448
|
-
- User visits `/dashboard` (protected) → Redirects to `/login?redirect=/dashboard`
|
|
449
|
-
- After login → Redirects to `/dashboard`
|
|
450
|
-
|
|
451
|
-
#### RouteGuard Props Reference
|
|
452
|
-
|
|
453
|
-
| Prop | Type | Required | Default | Description |
|
|
454
|
-
| ---------------------- | ----------- | -------- | ----------------------------- | ---------------------------------------------------------- |
|
|
455
|
-
| `builtInAuth` | `boolean` | No | `true` | Use external auth pages (`true`) or custom pages (`false`) |
|
|
456
|
-
| `publicRoutes` | `string[]` | No | `[]` | Routes accessible without authentication |
|
|
457
|
-
| `paths` | `object` | No | `{ signIn: '/sign-in', ... }` | Custom auth page paths (when `builtInAuth=false`) |
|
|
458
|
-
| `paths.signIn` | `string` | No | `'/sign-in'` | Custom sign-in page path |
|
|
459
|
-
| `paths.signUp` | `string` | No | `'/sign-up'` | Custom sign-up page path |
|
|
460
|
-
| `paths.forgotPassword` | `string` | No | `'/forgot-password'` | Custom forgot password page path |
|
|
461
|
-
| `loadingFallback` | `ReactNode` | **Yes** | - | Loading UI displayed while checking authentication |
|
|
462
|
-
|
|
463
|
-
**Public Routes with Wildcards:**
|
|
464
|
-
|
|
465
|
-
```tsx
|
|
466
|
-
<RouteGuard
|
|
467
|
-
publicRoutes={[
|
|
468
|
-
'/', // Home page
|
|
469
|
-
'/about', // About page
|
|
470
|
-
'/blog/*', // All blog routes
|
|
471
|
-
'/docs/*', // All documentation routes
|
|
472
|
-
]}
|
|
473
|
-
>
|
|
474
|
-
<App />
|
|
475
|
-
</RouteGuard>
|
|
476
|
-
```
|
|
477
|
-
|
|
478
|
-
> **Note:** When `builtInAuth=true`, auth paths (`/sign-in`, `/sign-up`, `/forgot-password`) are automatically redirected. Don't include them in `publicRoutes`.
|
|
479
|
-
|
|
480
|
-
### React Router Integration
|
|
481
|
-
|
|
482
|
-
For React Router apps, use the dedicated adapter:
|
|
483
|
-
|
|
484
|
-
```bash
|
|
485
|
-
npm install @insforge/react-router
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
```tsx
|
|
489
|
-
import { InsforgeProvider } from '@insforge/react-router';
|
|
490
|
-
import { getInsforgeRoutes } from '@insforge/react-router/router';
|
|
491
|
-
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
|
492
|
-
|
|
493
|
-
const router = createBrowserRouter([
|
|
494
|
-
{ path: '/', element: <Home /> },
|
|
495
|
-
{ path: '/dashboard', element: <Dashboard /> },
|
|
496
|
-
...getInsforgeRoutes({
|
|
497
|
-
baseUrl: import.meta.env.VITE_INSFORGE_BASE_URL,
|
|
498
|
-
builtInAuth: true,
|
|
499
|
-
}),
|
|
500
|
-
]);
|
|
501
|
-
|
|
502
|
-
function App() {
|
|
503
|
-
return (
|
|
504
|
-
<InsforgeProvider baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL}>
|
|
505
|
-
<RouterProvider router={router} />
|
|
506
|
-
</InsforgeProvider>
|
|
507
|
-
);
|
|
508
|
-
}
|
|
509
|
-
```
|
|
510
|
-
|
|
511
|
-
**Features:**
|
|
512
|
-
|
|
513
|
-
- Pre-configured routes for authentication flows
|
|
514
|
-
- React Router's `Link` and `useSearchParams` integration
|
|
515
|
-
- Optimized navigation with client-side routing
|
|
516
|
-
|
|
517
|
-
**Docs:** [@insforge/react-router](https://github.com/InsForge/InsForge/tree/main/packages/react-router)
|
|
518
|
-
|
|
519
|
-
### Next.js Integration
|
|
520
|
-
|
|
521
|
-
For Next.js App Router with SSR:
|
|
522
|
-
|
|
523
|
-
```bash
|
|
524
|
-
npm install @insforge/nextjs
|
|
525
|
-
```
|
|
526
|
-
|
|
527
|
-
```tsx
|
|
528
|
-
// app/layout.tsx
|
|
529
|
-
import { InsforgeProvider } from '@insforge/nextjs';
|
|
530
|
-
|
|
531
|
-
export default function RootLayout({ children }) {
|
|
532
|
-
return (
|
|
533
|
-
<html>
|
|
534
|
-
<body>
|
|
535
|
-
<InsforgeProvider baseUrl={process.env.NEXT_PUBLIC_INSFORGE_BASE_URL}>
|
|
536
|
-
{children}
|
|
537
|
-
</InsforgeProvider>
|
|
538
|
-
</body>
|
|
539
|
-
</html>
|
|
540
|
-
);
|
|
541
|
-
}
|
|
542
|
-
```
|
|
543
|
-
|
|
544
|
-
**Features:**
|
|
545
|
-
|
|
546
|
-
- Server-side rendering (SSR) support
|
|
547
|
-
- Middleware-based route protection
|
|
548
|
-
- Next.js `Link` and `useSearchParams` integration
|
|
549
|
-
- Cookie-based session management
|
|
550
|
-
- Automatic token refresh
|
|
551
|
-
|
|
552
|
-
**Docs:** [@insforge/nextjs](https://github.com/InsForge/InsForge/tree/main/packages/nextjs)
|
|
553
|
-
|
|
554
|
-
---
|
|
555
|
-
|
|
556
|
-
## OAuth Providers
|
|
557
|
-
|
|
558
|
-
Built-in support for 10+ OAuth providers:
|
|
559
|
-
|
|
560
|
-
- Google
|
|
561
|
-
- GitHub
|
|
562
|
-
- Discord
|
|
563
|
-
- Apple
|
|
564
|
-
- Microsoft
|
|
565
|
-
- Facebook
|
|
566
|
-
- LinkedIn
|
|
567
|
-
- Instagram
|
|
568
|
-
- TikTok
|
|
569
|
-
- Spotify
|
|
570
|
-
- X (Twitter)
|
|
571
|
-
|
|
572
|
-
Providers are auto-detected from your backend configuration.
|
|
573
|
-
|
|
574
|
-
---
|
|
575
|
-
|
|
576
|
-
## Available Atomic Components
|
|
577
|
-
|
|
578
|
-
Low-level building blocks for complete customization:
|
|
579
|
-
|
|
580
|
-
- `<AuthBranding />` - Insforge branding footer
|
|
581
|
-
- `<AuthContainer />` - Main container wrapper
|
|
582
|
-
- `<AuthHeader />` - Title and subtitle display
|
|
583
|
-
- `<AuthErrorBanner />` - Error message display
|
|
584
|
-
- `<AuthFormField />` - Standard input field
|
|
585
|
-
- `<AuthPasswordField />` - Password input with features
|
|
586
|
-
- `<AuthPasswordStrengthIndicator />` - Password checklist
|
|
587
|
-
- `<AuthSubmitButton />` - Submit button with states
|
|
588
|
-
- `<AuthLink />` - Call-to-action link
|
|
589
|
-
- `<AuthDivider />` - Visual separator
|
|
590
|
-
- `<AuthOAuthButton />` - Single OAuth provider button
|
|
591
|
-
- `<AuthOAuthProviders />` - Smart OAuth grid
|
|
592
|
-
- `<AuthVerificationCodeInput />` - 6-digit OTP input
|
|
593
|
-
- `<AuthEmailVerificationStep />` - Email verification step with countdown and resend
|
|
594
|
-
|
|
595
|
-
---
|
|
596
|
-
|
|
597
|
-
## API Reference
|
|
598
|
-
|
|
599
|
-
### InsforgeProvider
|
|
600
|
-
|
|
601
|
-
The root provider component that manages authentication state.
|
|
602
|
-
|
|
603
|
-
**Props:**
|
|
604
|
-
|
|
605
|
-
| Prop | Type | Required | Default | Description |
|
|
606
|
-
| ---------------- | -------------------------------------- | -------- | ------- | --------------------------------------------------- |
|
|
607
|
-
| `baseUrl` | `string` | **Yes** | - | Your Insforge backend URL |
|
|
608
|
-
| `afterSignInUrl` | `string` | No | `'/'` | Redirect URL after successful sign-in |
|
|
609
|
-
| `onAuthChange` | `(user: InsforgeUser \| null) => void` | No | - | Callback when auth state changes |
|
|
610
|
-
| `onSignIn` | `(authToken: string) => Promise<void>` | No | - | Custom handler after sign-in (e.g., cookie sync) |
|
|
611
|
-
| `onSignOut` | `() => Promise<void>` | No | - | Custom handler after sign-out (e.g., clear cookies) |
|
|
612
|
-
|
|
613
|
-
**Example:**
|
|
614
|
-
|
|
615
|
-
```tsx
|
|
616
|
-
<InsforgeProvider
|
|
617
|
-
baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL}
|
|
618
|
-
afterSignInUrl="/dashboard"
|
|
619
|
-
onAuthChange={(user) => {
|
|
620
|
-
console.log('Auth changed:', user);
|
|
621
|
-
}}
|
|
622
|
-
>
|
|
623
|
-
{children}
|
|
624
|
-
</InsforgeProvider>
|
|
625
|
-
```
|
|
626
|
-
|
|
627
|
-
### RouteGuard
|
|
628
|
-
|
|
629
|
-
App-level route protection for vanilla React apps (no router library needed).
|
|
630
|
-
|
|
631
|
-
See [Route Protection (Detailed)](#route-protection-detailed) for full documentation.
|
|
632
|
-
|
|
633
|
-
**Quick Props:**
|
|
634
|
-
|
|
635
|
-
- `builtInAuth` (default: `true`) - Use external auth or custom pages
|
|
636
|
-
- `publicRoutes` - Array of paths accessible without auth
|
|
637
|
-
- `paths` - Custom auth page paths (when `builtInAuth=false`)
|
|
638
|
-
- `loadingFallback` (required) - Loading UI
|
|
639
|
-
|
|
640
|
-
### useAuth() / useInsforge()
|
|
641
|
-
|
|
642
|
-
Primary hook for authentication. Both are aliases for the same hook.
|
|
643
|
-
|
|
644
|
-
**Returns:**
|
|
645
|
-
|
|
646
|
-
```tsx
|
|
647
|
-
{
|
|
648
|
-
// Auth state
|
|
649
|
-
user: InsforgeUser | null;
|
|
650
|
-
isLoaded: boolean;
|
|
651
|
-
isSignedIn: boolean;
|
|
652
|
-
|
|
653
|
-
// Auth methods
|
|
654
|
-
signIn: (email: string, password: string) => Promise<...>;
|
|
655
|
-
signUp: (email: string, password: string) => Promise<...>;
|
|
656
|
-
signOut: () => Promise<void>;
|
|
657
|
-
updateUser: (data: Partial<InsforgeUser>) => Promise<...>;
|
|
658
|
-
reloadAuth: () => Promise<...>;
|
|
659
|
-
|
|
660
|
-
// Email verification
|
|
661
|
-
resendVerificationEmail: (email: string) => Promise<...>;
|
|
662
|
-
verifyEmail: (otp: string, email?: string) => Promise<...>;
|
|
663
|
-
|
|
664
|
-
// Password reset
|
|
665
|
-
sendResetPasswordEmail: (email: string) => Promise<...>;
|
|
666
|
-
resetPassword: (token: string, newPassword: string) => Promise<...>;
|
|
667
|
-
exchangeResetPasswordToken: (email: string, code: string) => Promise<...>;
|
|
668
|
-
|
|
669
|
-
// OAuth
|
|
670
|
-
loginWithOAuth: (provider: OAuthProvider, redirectTo: string) => Promise<void>;
|
|
671
|
-
|
|
672
|
-
// Config (from provider)
|
|
673
|
-
baseUrl: string;
|
|
674
|
-
afterSignInUrl: string;
|
|
675
|
-
|
|
676
|
-
// Public config
|
|
677
|
-
getPublicAuthConfig: () => Promise<...>;
|
|
678
|
-
}
|
|
679
|
-
```
|
|
680
|
-
|
|
681
|
-
### useUser()
|
|
682
|
-
|
|
683
|
-
Simplified hook for user data only.
|
|
684
|
-
|
|
685
|
-
**Returns:**
|
|
686
|
-
|
|
687
|
-
```tsx
|
|
688
|
-
{
|
|
689
|
-
user: InsforgeUser | null;
|
|
690
|
-
isLoaded: boolean;
|
|
691
|
-
}
|
|
692
|
-
```
|
|
693
|
-
|
|
694
|
-
### usePublicAuthConfig()
|
|
695
|
-
|
|
696
|
-
Hook for fetching public auth configuration (OAuth providers, password requirements, etc.).
|
|
697
|
-
|
|
698
|
-
**Returns:**
|
|
699
|
-
|
|
700
|
-
```tsx
|
|
701
|
-
{
|
|
702
|
-
oauthProviders: OAuthProviderConfig[];
|
|
703
|
-
authConfig: AuthConfig;
|
|
704
|
-
isLoaded: boolean;
|
|
705
|
-
}
|
|
706
|
-
```
|
|
707
|
-
|
|
708
|
-
---
|
|
709
|
-
|
|
710
|
-
## Support
|
|
711
|
-
|
|
712
|
-
- **Documentation**: https://docs.insforge.dev
|
|
713
|
-
- **GitHub Issues**: https://github.com/InsForge/InsForge/issues
|
|
714
|
-
- **Discord Community**: https://discord.com/invite/DvBtaEc9Jz
|
|
715
|
-
|
|
716
|
-
## License
|
|
717
|
-
|
|
718
|
-
MIT © Insforge
|
|
1
|
+
# @insforge/react
|
|
2
|
+
|
|
3
|
+
**Framework-agnostic authentication solution for React applications.** Production-ready components with full business logic included.
|
|
4
|
+
|
|
5
|
+
> **✨ CSS-in-JS**: All components now use Emotion CSS-in-JS for zero FOUC in SSR environments. No CSS imports needed!
|
|
6
|
+
|
|
7
|
+
## Why @insforge/react?
|
|
8
|
+
|
|
9
|
+
✅ **Framework Agnostic** - Works with any React setup (Vite, CRA, or no bundler)
|
|
10
|
+
✅ **Zero Router Dependencies** - Built-in navigation abstraction works with any routing solution
|
|
11
|
+
✅ **Route Protection** - Built-in `RouteGuard` for vanilla React apps
|
|
12
|
+
✅ **Production Ready** - Complete auth flows with business logic included
|
|
13
|
+
✅ **Full TypeScript** - Complete type safety out of the box
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
Get authentication working in your React app in 5 minutes.
|
|
20
|
+
|
|
21
|
+
### 1. Install
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @insforge/react
|
|
25
|
+
# or
|
|
26
|
+
yarn add @insforge/react
|
|
27
|
+
# or
|
|
28
|
+
pnpm add @insforge/react
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
#### Environment Variables
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# .env
|
|
35
|
+
VITE_INSFORGE_BASE_URL=https://your-project.insforge.app/
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 2. Setup Provider & Route Guard
|
|
39
|
+
|
|
40
|
+
Wrap your app with `InsforgeProvider`:
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
// src/main.tsx (Vite) or src/index.tsx (CRA)
|
|
44
|
+
import { StrictMode } from 'react';
|
|
45
|
+
import { createRoot } from 'react-dom/client';
|
|
46
|
+
import { InsforgeProvider } from '@insforge/react';
|
|
47
|
+
import App from './App';
|
|
48
|
+
|
|
49
|
+
createRoot(document.getElementById('root')!).render(
|
|
50
|
+
<StrictMode>
|
|
51
|
+
<InsforgeProvider baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL}>
|
|
52
|
+
<App />
|
|
53
|
+
</InsforgeProvider>
|
|
54
|
+
</StrictMode>
|
|
55
|
+
);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 3. Use Components & Hooks
|
|
59
|
+
|
|
60
|
+
Now you can use authentication components and hooks anywhere in your app:
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
// src/App.tsx
|
|
64
|
+
import { SignInButton, SignUpButton, SignedIn, SignedOut, UserButton } from '@insforge/react';
|
|
65
|
+
|
|
66
|
+
export default function App() {
|
|
67
|
+
return (
|
|
68
|
+
<div>
|
|
69
|
+
<SignedOut>
|
|
70
|
+
<SignInButton />
|
|
71
|
+
<SignUpButton />
|
|
72
|
+
</SignedOut>
|
|
73
|
+
|
|
74
|
+
<SignedIn>
|
|
75
|
+
<nav>
|
|
76
|
+
<UserButton />
|
|
77
|
+
</nav>
|
|
78
|
+
<h1>Welcome to your dashboard!</h1>
|
|
79
|
+
</SignedIn>
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**That's it!** 🎉 Your app is now protected with authentication.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Usage Patterns
|
|
90
|
+
|
|
91
|
+
### Option 1: Pre-built Components (Fastest)
|
|
92
|
+
|
|
93
|
+
Use complete auth flows with built-in UI and logic:
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
import { SignIn, SignUp, ForgotPassword, ResetPassword } from '@insforge/react';
|
|
97
|
+
|
|
98
|
+
// In your app
|
|
99
|
+
<SignIn /> // Complete sign-in flow
|
|
100
|
+
<SignUp /> // Complete sign-up flow with email verification
|
|
101
|
+
<ForgotPassword /> // Password reset request + verification
|
|
102
|
+
<ResetPassword /> // Reset password with token (from URL params)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Option 2: Form Components (UI Only)
|
|
106
|
+
|
|
107
|
+
Use UI components and add your own logic:
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
import { SignInForm, useAuth } from '@insforge/react';
|
|
111
|
+
import { useState } from 'react';
|
|
112
|
+
|
|
113
|
+
function CustomSignIn() {
|
|
114
|
+
const { signIn } = useAuth();
|
|
115
|
+
const [email, setEmail] = useState('');
|
|
116
|
+
const [password, setPassword] = useState('');
|
|
117
|
+
const [error, setError] = useState('');
|
|
118
|
+
const [loading, setLoading] = useState(false);
|
|
119
|
+
|
|
120
|
+
const handleSubmit = async (e) => {
|
|
121
|
+
e.preventDefault();
|
|
122
|
+
setLoading(true);
|
|
123
|
+
const result = await signIn(email, password);
|
|
124
|
+
if ('error' in result) {
|
|
125
|
+
setError(result.error);
|
|
126
|
+
}
|
|
127
|
+
setLoading(false);
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<SignInForm
|
|
132
|
+
email={email}
|
|
133
|
+
password={password}
|
|
134
|
+
onEmailChange={setEmail}
|
|
135
|
+
onPasswordChange={setPassword}
|
|
136
|
+
onSubmit={handleSubmit}
|
|
137
|
+
error={error}
|
|
138
|
+
loading={loading}
|
|
139
|
+
/>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Option 3: Hooks Only (Headless)
|
|
145
|
+
|
|
146
|
+
Build completely custom UI using authentication hooks:
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
import { useAuth } from '@insforge/react';
|
|
150
|
+
|
|
151
|
+
function CustomAuthForm() {
|
|
152
|
+
const { signIn, signUp, isLoaded } = useAuth();
|
|
153
|
+
|
|
154
|
+
const handleLogin = async (email: string, password: string) => {
|
|
155
|
+
const result = await signIn(email, password);
|
|
156
|
+
if ('error' in result) {
|
|
157
|
+
console.error(result.error);
|
|
158
|
+
} else {
|
|
159
|
+
console.log('Signed in!');
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
return <form>...your custom UI...</form>;
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Core Features
|
|
170
|
+
|
|
171
|
+
### Components
|
|
172
|
+
|
|
173
|
+
**Pre-built with Business Logic:**
|
|
174
|
+
|
|
175
|
+
- `<SignIn />` - Complete sign-in with email/password & OAuth
|
|
176
|
+
- `<SignUp />` - Registration with password validation & email verification
|
|
177
|
+
- `<ForgotPassword />` - Request password reset with email validation
|
|
178
|
+
- `<ResetPassword />` - Reset password with token validation
|
|
179
|
+
- `<VerifyEmail />` - Verify email with automatic token handling
|
|
180
|
+
- `<UserButton />` - User dropdown with sign-out
|
|
181
|
+
- `<RouteGuard />` - **NEW:** App-level route protection for vanilla React
|
|
182
|
+
- `<Protect />` - Component-level protection wrapper
|
|
183
|
+
- `<SignedIn>` / `<SignedOut>` - Conditional rendering
|
|
184
|
+
|
|
185
|
+
**Form Components (Pure UI):**
|
|
186
|
+
|
|
187
|
+
- `<SignInForm />` - Sign-in UI without logic
|
|
188
|
+
- `<SignUpForm />` - Sign-up UI without logic
|
|
189
|
+
- `<ForgotPasswordForm />` - Password reset request UI
|
|
190
|
+
- `<ResetPasswordForm />` - Password reset with token UI
|
|
191
|
+
- `<VerifyEmailStatus />` - Email verification status UI
|
|
192
|
+
|
|
193
|
+
**Atomic Components (14 total):**
|
|
194
|
+
|
|
195
|
+
- `<AuthContainer />`, `<AuthHeader />`, `<AuthFormField />`, `<AuthPasswordField />`, `<AuthEmailVerificationStep />`, etc.
|
|
196
|
+
|
|
197
|
+
### Hooks
|
|
198
|
+
|
|
199
|
+
```tsx
|
|
200
|
+
// Authentication state and methods
|
|
201
|
+
const {
|
|
202
|
+
signIn,
|
|
203
|
+
signUp,
|
|
204
|
+
signOut,
|
|
205
|
+
isSignedIn,
|
|
206
|
+
isLoaded,
|
|
207
|
+
baseUrl, // From provider
|
|
208
|
+
afterSignInUrl, // From provider
|
|
209
|
+
} = useAuth();
|
|
210
|
+
|
|
211
|
+
// Or use useInsforge (same as useAuth)
|
|
212
|
+
const context = useInsforge();
|
|
213
|
+
|
|
214
|
+
// User information
|
|
215
|
+
const { user, updateUser, isLoaded } = useUser();
|
|
216
|
+
|
|
217
|
+
// Public auth configuration (OAuth providers, password requirements, etc.)
|
|
218
|
+
const { oauthProviders, authConfig, isLoaded } = usePublicAuthConfig();
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Customization
|
|
224
|
+
|
|
225
|
+
### Text Customization
|
|
226
|
+
|
|
227
|
+
All components support full text customization:
|
|
228
|
+
|
|
229
|
+
```tsx
|
|
230
|
+
<SignIn
|
|
231
|
+
title="Welcome Back!"
|
|
232
|
+
subtitle="We're happy to see you again"
|
|
233
|
+
emailLabel="Your Email Address"
|
|
234
|
+
emailPlaceholder="you@company.com"
|
|
235
|
+
passwordLabel="Your Password"
|
|
236
|
+
submitButtonText="Login Now"
|
|
237
|
+
loadingButtonText="Signing you in..."
|
|
238
|
+
signUpText="New to our platform?"
|
|
239
|
+
signUpLinkText="Create an account"
|
|
240
|
+
dividerText="or continue with"
|
|
241
|
+
/>
|
|
242
|
+
|
|
243
|
+
<ForgotPassword
|
|
244
|
+
title="Reset Your Password"
|
|
245
|
+
subtitle="Enter your email to receive a reset code"
|
|
246
|
+
emailLabel="Email Address"
|
|
247
|
+
submitButtonText="Send Reset Code"
|
|
248
|
+
backToSignInText="Remember your password?"
|
|
249
|
+
successTitle="Check Your Email"
|
|
250
|
+
successMessage="We've sent a reset code to your inbox"
|
|
251
|
+
/>
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Advanced Usage
|
|
257
|
+
|
|
258
|
+
### Conditional Rendering
|
|
259
|
+
|
|
260
|
+
Control what users see based on auth state:
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
import { SignedIn, SignedOut, Protect } from '@insforge/react';
|
|
264
|
+
|
|
265
|
+
function App() {
|
|
266
|
+
return (
|
|
267
|
+
<>
|
|
268
|
+
<SignedOut>
|
|
269
|
+
<SignIn />
|
|
270
|
+
</SignedOut>
|
|
271
|
+
|
|
272
|
+
<SignedIn>
|
|
273
|
+
<Dashboard />
|
|
274
|
+
</SignedIn>
|
|
275
|
+
|
|
276
|
+
{/* Or use Protect for specific sections */}
|
|
277
|
+
<Protect redirectTo="/sign-in">
|
|
278
|
+
<ProtectedContent />
|
|
279
|
+
</Protect>
|
|
280
|
+
</>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Build from Atomic Components
|
|
286
|
+
|
|
287
|
+
```tsx
|
|
288
|
+
import {
|
|
289
|
+
AuthContainer,
|
|
290
|
+
AuthHeader,
|
|
291
|
+
AuthFormField,
|
|
292
|
+
AuthPasswordField,
|
|
293
|
+
AuthSubmitButton,
|
|
294
|
+
AuthErrorBanner,
|
|
295
|
+
AuthDivider,
|
|
296
|
+
AuthOAuthProviders,
|
|
297
|
+
AuthLink,
|
|
298
|
+
} from '@insforge/react';
|
|
299
|
+
|
|
300
|
+
function CompletelyCustomAuth() {
|
|
301
|
+
return (
|
|
302
|
+
<AuthContainer>
|
|
303
|
+
<AuthHeader title="Welcome to MyApp" subtitle="Sign in to continue" />
|
|
304
|
+
|
|
305
|
+
<AuthErrorBanner error={error} />
|
|
306
|
+
|
|
307
|
+
<form onSubmit={handleSubmit}>
|
|
308
|
+
<AuthFormField
|
|
309
|
+
id="email"
|
|
310
|
+
type="email"
|
|
311
|
+
label="Email"
|
|
312
|
+
value={email}
|
|
313
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
314
|
+
/>
|
|
315
|
+
|
|
316
|
+
<AuthPasswordField
|
|
317
|
+
id="password"
|
|
318
|
+
label="Password"
|
|
319
|
+
value={password}
|
|
320
|
+
onChange={(e) => setPassword(e.target.value)}
|
|
321
|
+
authConfig={config}
|
|
322
|
+
showStrengthIndicator
|
|
323
|
+
/>
|
|
324
|
+
|
|
325
|
+
<AuthSubmitButton isLoading={loading}>Sign In</AuthSubmitButton>
|
|
326
|
+
</form>
|
|
327
|
+
|
|
328
|
+
<AuthDivider text="or" />
|
|
329
|
+
|
|
330
|
+
<AuthOAuthProviders
|
|
331
|
+
providers={['google', 'github', 'discord']}
|
|
332
|
+
onClick={handleOAuth}
|
|
333
|
+
loading={oauthLoading}
|
|
334
|
+
/>
|
|
335
|
+
|
|
336
|
+
<AuthLink text="Don't have an account?" linkText="Sign up" href="/sign-up" />
|
|
337
|
+
</AuthContainer>
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Content Protection
|
|
343
|
+
|
|
344
|
+
Protect specific content or sections:
|
|
345
|
+
|
|
346
|
+
```tsx
|
|
347
|
+
import { Protect } from '@insforge/react';
|
|
348
|
+
|
|
349
|
+
function Dashboard() {
|
|
350
|
+
return (
|
|
351
|
+
<div>
|
|
352
|
+
<h1>Dashboard</h1>
|
|
353
|
+
|
|
354
|
+
{/* Simple protection - shows nothing if not signed in */}
|
|
355
|
+
<Protect>
|
|
356
|
+
<UserContent />
|
|
357
|
+
</Protect>
|
|
358
|
+
|
|
359
|
+
{/* With redirect */}
|
|
360
|
+
<Protect redirectTo="/sign-in">
|
|
361
|
+
<UserContent />
|
|
362
|
+
</Protect>
|
|
363
|
+
|
|
364
|
+
{/* Custom condition - e.g., role-based */}
|
|
365
|
+
<Protect condition={(user) => user.email.endsWith('@admin.com')} redirectTo="/unauthorized">
|
|
366
|
+
<AdminPanel />
|
|
367
|
+
</Protect>
|
|
368
|
+
</div>
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
> **Note:** `<Protect>` is for component-level conditional rendering. For app-level route protection, use `<RouteGuard>`
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## Route Protection (Detailed)
|
|
378
|
+
|
|
379
|
+
### RouteGuard for Vanilla React
|
|
380
|
+
|
|
381
|
+
`RouteGuard` provides app-level authentication protection without requiring any routing library.
|
|
382
|
+
|
|
383
|
+
#### Option 1: External Built-in Auth (Simplest)
|
|
384
|
+
|
|
385
|
+
Redirects to your deployed Insforge Auth pages:
|
|
386
|
+
|
|
387
|
+
```tsx
|
|
388
|
+
import { InsforgeProvider, RouteGuard } from '@insforge/react';
|
|
389
|
+
|
|
390
|
+
createRoot(document.getElementById('root')!).render(
|
|
391
|
+
<InsforgeProvider baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL} afterSignInUrl="/dashboard">
|
|
392
|
+
<RouteGuard
|
|
393
|
+
builtInAuth
|
|
394
|
+
publicRoutes={['/', '/about', '/pricing']}
|
|
395
|
+
loadingFallback={<div>Loading...</div>}
|
|
396
|
+
>
|
|
397
|
+
<App />
|
|
398
|
+
</RouteGuard>
|
|
399
|
+
</InsforgeProvider>
|
|
400
|
+
);
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**Behavior:**
|
|
404
|
+
|
|
405
|
+
- User visits `/sign-in` → Redirects to `baseUrl/auth/sign-in`
|
|
406
|
+
- User visits `/sign-up` → Redirects to `baseUrl/auth/sign-up`
|
|
407
|
+
- User visits `/dashboard` (protected) → Redirects to `baseUrl/auth/sign-in`
|
|
408
|
+
- User visits `/` (public) → ✅ Renders normally
|
|
409
|
+
|
|
410
|
+
#### Option 2: Custom Auth Pages
|
|
411
|
+
|
|
412
|
+
Use @insforge/react components in your own app:
|
|
413
|
+
|
|
414
|
+
```tsx
|
|
415
|
+
import { InsforgeProvider, RouteGuard, SignIn, SignUp } from '@insforge/react';
|
|
416
|
+
|
|
417
|
+
// Simple hash-based routing
|
|
418
|
+
function App() {
|
|
419
|
+
const path = window.location.hash.slice(1) || '/';
|
|
420
|
+
|
|
421
|
+
return (
|
|
422
|
+
<>
|
|
423
|
+
{path === '/login' && <SignIn />}
|
|
424
|
+
{path === '/register' && <SignUp />}
|
|
425
|
+
{path === '/dashboard' && <Dashboard />}
|
|
426
|
+
{path === '/' && <HomePage />}
|
|
427
|
+
</>
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
createRoot(document.getElementById('root')!).render(
|
|
432
|
+
<InsforgeProvider baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL}>
|
|
433
|
+
<RouteGuard
|
|
434
|
+
builtInAuth={false}
|
|
435
|
+
publicRoutes={['/login', '/register', '/forgot-password', '/']}
|
|
436
|
+
paths={{ signIn: '/login', signUp: '/register' }}
|
|
437
|
+
loadingFallback={<div>Loading...</div>}
|
|
438
|
+
>
|
|
439
|
+
<App />
|
|
440
|
+
</RouteGuard>
|
|
441
|
+
</InsforgeProvider>
|
|
442
|
+
);
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
**Behavior:**
|
|
446
|
+
|
|
447
|
+
- User visits `/login` → ✅ Renders `<SignIn />` (in publicRoutes)
|
|
448
|
+
- User visits `/dashboard` (protected) → Redirects to `/login?redirect=/dashboard`
|
|
449
|
+
- After login → Redirects to `/dashboard`
|
|
450
|
+
|
|
451
|
+
#### RouteGuard Props Reference
|
|
452
|
+
|
|
453
|
+
| Prop | Type | Required | Default | Description |
|
|
454
|
+
| ---------------------- | ----------- | -------- | ----------------------------- | ---------------------------------------------------------- |
|
|
455
|
+
| `builtInAuth` | `boolean` | No | `true` | Use external auth pages (`true`) or custom pages (`false`) |
|
|
456
|
+
| `publicRoutes` | `string[]` | No | `[]` | Routes accessible without authentication |
|
|
457
|
+
| `paths` | `object` | No | `{ signIn: '/sign-in', ... }` | Custom auth page paths (when `builtInAuth=false`) |
|
|
458
|
+
| `paths.signIn` | `string` | No | `'/sign-in'` | Custom sign-in page path |
|
|
459
|
+
| `paths.signUp` | `string` | No | `'/sign-up'` | Custom sign-up page path |
|
|
460
|
+
| `paths.forgotPassword` | `string` | No | `'/forgot-password'` | Custom forgot password page path |
|
|
461
|
+
| `loadingFallback` | `ReactNode` | **Yes** | - | Loading UI displayed while checking authentication |
|
|
462
|
+
|
|
463
|
+
**Public Routes with Wildcards:**
|
|
464
|
+
|
|
465
|
+
```tsx
|
|
466
|
+
<RouteGuard
|
|
467
|
+
publicRoutes={[
|
|
468
|
+
'/', // Home page
|
|
469
|
+
'/about', // About page
|
|
470
|
+
'/blog/*', // All blog routes
|
|
471
|
+
'/docs/*', // All documentation routes
|
|
472
|
+
]}
|
|
473
|
+
>
|
|
474
|
+
<App />
|
|
475
|
+
</RouteGuard>
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
> **Note:** When `builtInAuth=true`, auth paths (`/sign-in`, `/sign-up`, `/forgot-password`) are automatically redirected. Don't include them in `publicRoutes`.
|
|
479
|
+
|
|
480
|
+
### React Router Integration
|
|
481
|
+
|
|
482
|
+
For React Router apps, use the dedicated adapter:
|
|
483
|
+
|
|
484
|
+
```bash
|
|
485
|
+
npm install @insforge/react-router
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
```tsx
|
|
489
|
+
import { InsforgeProvider } from '@insforge/react-router';
|
|
490
|
+
import { getInsforgeRoutes } from '@insforge/react-router/router';
|
|
491
|
+
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
|
492
|
+
|
|
493
|
+
const router = createBrowserRouter([
|
|
494
|
+
{ path: '/', element: <Home /> },
|
|
495
|
+
{ path: '/dashboard', element: <Dashboard /> },
|
|
496
|
+
...getInsforgeRoutes({
|
|
497
|
+
baseUrl: import.meta.env.VITE_INSFORGE_BASE_URL,
|
|
498
|
+
builtInAuth: true,
|
|
499
|
+
}),
|
|
500
|
+
]);
|
|
501
|
+
|
|
502
|
+
function App() {
|
|
503
|
+
return (
|
|
504
|
+
<InsforgeProvider baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL}>
|
|
505
|
+
<RouterProvider router={router} />
|
|
506
|
+
</InsforgeProvider>
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
**Features:**
|
|
512
|
+
|
|
513
|
+
- Pre-configured routes for authentication flows
|
|
514
|
+
- React Router's `Link` and `useSearchParams` integration
|
|
515
|
+
- Optimized navigation with client-side routing
|
|
516
|
+
|
|
517
|
+
**Docs:** [@insforge/react-router](https://github.com/InsForge/InsForge/tree/main/packages/react-router)
|
|
518
|
+
|
|
519
|
+
### Next.js Integration
|
|
520
|
+
|
|
521
|
+
For Next.js App Router with SSR:
|
|
522
|
+
|
|
523
|
+
```bash
|
|
524
|
+
npm install @insforge/nextjs
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
```tsx
|
|
528
|
+
// app/layout.tsx
|
|
529
|
+
import { InsforgeProvider } from '@insforge/nextjs';
|
|
530
|
+
|
|
531
|
+
export default function RootLayout({ children }) {
|
|
532
|
+
return (
|
|
533
|
+
<html>
|
|
534
|
+
<body>
|
|
535
|
+
<InsforgeProvider baseUrl={process.env.NEXT_PUBLIC_INSFORGE_BASE_URL}>
|
|
536
|
+
{children}
|
|
537
|
+
</InsforgeProvider>
|
|
538
|
+
</body>
|
|
539
|
+
</html>
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
**Features:**
|
|
545
|
+
|
|
546
|
+
- Server-side rendering (SSR) support
|
|
547
|
+
- Middleware-based route protection
|
|
548
|
+
- Next.js `Link` and `useSearchParams` integration
|
|
549
|
+
- Cookie-based session management
|
|
550
|
+
- Automatic token refresh
|
|
551
|
+
|
|
552
|
+
**Docs:** [@insforge/nextjs](https://github.com/InsForge/InsForge/tree/main/packages/nextjs)
|
|
553
|
+
|
|
554
|
+
---
|
|
555
|
+
|
|
556
|
+
## OAuth Providers
|
|
557
|
+
|
|
558
|
+
Built-in support for 10+ OAuth providers:
|
|
559
|
+
|
|
560
|
+
- Google
|
|
561
|
+
- GitHub
|
|
562
|
+
- Discord
|
|
563
|
+
- Apple
|
|
564
|
+
- Microsoft
|
|
565
|
+
- Facebook
|
|
566
|
+
- LinkedIn
|
|
567
|
+
- Instagram
|
|
568
|
+
- TikTok
|
|
569
|
+
- Spotify
|
|
570
|
+
- X (Twitter)
|
|
571
|
+
|
|
572
|
+
Providers are auto-detected from your backend configuration.
|
|
573
|
+
|
|
574
|
+
---
|
|
575
|
+
|
|
576
|
+
## Available Atomic Components
|
|
577
|
+
|
|
578
|
+
Low-level building blocks for complete customization:
|
|
579
|
+
|
|
580
|
+
- `<AuthBranding />` - Insforge branding footer
|
|
581
|
+
- `<AuthContainer />` - Main container wrapper
|
|
582
|
+
- `<AuthHeader />` - Title and subtitle display
|
|
583
|
+
- `<AuthErrorBanner />` - Error message display
|
|
584
|
+
- `<AuthFormField />` - Standard input field
|
|
585
|
+
- `<AuthPasswordField />` - Password input with features
|
|
586
|
+
- `<AuthPasswordStrengthIndicator />` - Password checklist
|
|
587
|
+
- `<AuthSubmitButton />` - Submit button with states
|
|
588
|
+
- `<AuthLink />` - Call-to-action link
|
|
589
|
+
- `<AuthDivider />` - Visual separator
|
|
590
|
+
- `<AuthOAuthButton />` - Single OAuth provider button
|
|
591
|
+
- `<AuthOAuthProviders />` - Smart OAuth grid
|
|
592
|
+
- `<AuthVerificationCodeInput />` - 6-digit OTP input
|
|
593
|
+
- `<AuthEmailVerificationStep />` - Email verification step with countdown and resend
|
|
594
|
+
|
|
595
|
+
---
|
|
596
|
+
|
|
597
|
+
## API Reference
|
|
598
|
+
|
|
599
|
+
### InsforgeProvider
|
|
600
|
+
|
|
601
|
+
The root provider component that manages authentication state.
|
|
602
|
+
|
|
603
|
+
**Props:**
|
|
604
|
+
|
|
605
|
+
| Prop | Type | Required | Default | Description |
|
|
606
|
+
| ---------------- | -------------------------------------- | -------- | ------- | --------------------------------------------------- |
|
|
607
|
+
| `baseUrl` | `string` | **Yes** | - | Your Insforge backend URL |
|
|
608
|
+
| `afterSignInUrl` | `string` | No | `'/'` | Redirect URL after successful sign-in |
|
|
609
|
+
| `onAuthChange` | `(user: InsforgeUser \| null) => void` | No | - | Callback when auth state changes |
|
|
610
|
+
| `onSignIn` | `(authToken: string) => Promise<void>` | No | - | Custom handler after sign-in (e.g., cookie sync) |
|
|
611
|
+
| `onSignOut` | `() => Promise<void>` | No | - | Custom handler after sign-out (e.g., clear cookies) |
|
|
612
|
+
|
|
613
|
+
**Example:**
|
|
614
|
+
|
|
615
|
+
```tsx
|
|
616
|
+
<InsforgeProvider
|
|
617
|
+
baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL}
|
|
618
|
+
afterSignInUrl="/dashboard"
|
|
619
|
+
onAuthChange={(user) => {
|
|
620
|
+
console.log('Auth changed:', user);
|
|
621
|
+
}}
|
|
622
|
+
>
|
|
623
|
+
{children}
|
|
624
|
+
</InsforgeProvider>
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
### RouteGuard
|
|
628
|
+
|
|
629
|
+
App-level route protection for vanilla React apps (no router library needed).
|
|
630
|
+
|
|
631
|
+
See [Route Protection (Detailed)](#route-protection-detailed) for full documentation.
|
|
632
|
+
|
|
633
|
+
**Quick Props:**
|
|
634
|
+
|
|
635
|
+
- `builtInAuth` (default: `true`) - Use external auth or custom pages
|
|
636
|
+
- `publicRoutes` - Array of paths accessible without auth
|
|
637
|
+
- `paths` - Custom auth page paths (when `builtInAuth=false`)
|
|
638
|
+
- `loadingFallback` (required) - Loading UI
|
|
639
|
+
|
|
640
|
+
### useAuth() / useInsforge()
|
|
641
|
+
|
|
642
|
+
Primary hook for authentication. Both are aliases for the same hook.
|
|
643
|
+
|
|
644
|
+
**Returns:**
|
|
645
|
+
|
|
646
|
+
```tsx
|
|
647
|
+
{
|
|
648
|
+
// Auth state
|
|
649
|
+
user: InsforgeUser | null;
|
|
650
|
+
isLoaded: boolean;
|
|
651
|
+
isSignedIn: boolean;
|
|
652
|
+
|
|
653
|
+
// Auth methods
|
|
654
|
+
signIn: (email: string, password: string) => Promise<...>;
|
|
655
|
+
signUp: (email: string, password: string) => Promise<...>;
|
|
656
|
+
signOut: () => Promise<void>;
|
|
657
|
+
updateUser: (data: Partial<InsforgeUser>) => Promise<...>;
|
|
658
|
+
reloadAuth: () => Promise<...>;
|
|
659
|
+
|
|
660
|
+
// Email verification
|
|
661
|
+
resendVerificationEmail: (email: string) => Promise<...>;
|
|
662
|
+
verifyEmail: (otp: string, email?: string) => Promise<...>;
|
|
663
|
+
|
|
664
|
+
// Password reset
|
|
665
|
+
sendResetPasswordEmail: (email: string) => Promise<...>;
|
|
666
|
+
resetPassword: (token: string, newPassword: string) => Promise<...>;
|
|
667
|
+
exchangeResetPasswordToken: (email: string, code: string) => Promise<...>;
|
|
668
|
+
|
|
669
|
+
// OAuth
|
|
670
|
+
loginWithOAuth: (provider: OAuthProvider, redirectTo: string) => Promise<void>;
|
|
671
|
+
|
|
672
|
+
// Config (from provider)
|
|
673
|
+
baseUrl: string;
|
|
674
|
+
afterSignInUrl: string;
|
|
675
|
+
|
|
676
|
+
// Public config
|
|
677
|
+
getPublicAuthConfig: () => Promise<...>;
|
|
678
|
+
}
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
### useUser()
|
|
682
|
+
|
|
683
|
+
Simplified hook for user data only.
|
|
684
|
+
|
|
685
|
+
**Returns:**
|
|
686
|
+
|
|
687
|
+
```tsx
|
|
688
|
+
{
|
|
689
|
+
user: InsforgeUser | null;
|
|
690
|
+
isLoaded: boolean;
|
|
691
|
+
}
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
### usePublicAuthConfig()
|
|
695
|
+
|
|
696
|
+
Hook for fetching public auth configuration (OAuth providers, password requirements, etc.).
|
|
697
|
+
|
|
698
|
+
**Returns:**
|
|
699
|
+
|
|
700
|
+
```tsx
|
|
701
|
+
{
|
|
702
|
+
oauthProviders: OAuthProviderConfig[];
|
|
703
|
+
authConfig: AuthConfig;
|
|
704
|
+
isLoaded: boolean;
|
|
705
|
+
}
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
---
|
|
709
|
+
|
|
710
|
+
## Support
|
|
711
|
+
|
|
712
|
+
- **Documentation**: https://docs.insforge.dev
|
|
713
|
+
- **GitHub Issues**: https://github.com/InsForge/InsForge/issues
|
|
714
|
+
- **Discord Community**: https://discord.com/invite/DvBtaEc9Jz
|
|
715
|
+
|
|
716
|
+
## License
|
|
717
|
+
|
|
718
|
+
MIT © Insforge
|