@rqdhw3n/react-auth-flow 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,569 +1,261 @@
1
- # @rqdhw3n/react-auth-flow
2
-
3
- A production-ready, TypeScript-first authentication flow package for React applications. Provides a complete solution for handling user authentication with minimal configuration while maintaining flexibility.
4
-
5
- ## Features
6
-
7
- - 🔐 **Secure by default**: HttpOnly cookie JWT support
8
- - ⚡ **Zero dependencies**: Uses native fetch API
9
- - 🎣 **Custom hooks**: `useAuth()` hook for accessing auth state
10
- - 🔄 **Auto-refresh**: Automatic session refresh capability
11
- - 🎨 **Unstyled components**: Ready-to-use forms with full customization
12
- - 🛣️ **Protected routes**: React Router v6 compatible route protection
13
- - 📦 **TypeScript support**: Full type safety throughout
14
- - 🔌 **Customizable**: Custom headers, endpoints, and request adapters
15
- - 🚀 **SSR-friendly**: Works with server-side rendering when configured properly
16
-
17
- ## Installation
18
-
19
- ```bash
20
- npm install @rqdhw3n/react-auth-flow react react-dom react-router-dom
21
- ```
22
-
23
- or with yarn:
24
-
25
- ```bash
26
- yarn add @rqdhw3n/react-auth-flow react react-dom react-router-dom
27
- ```
28
-
29
- ## Quick Setup
30
-
31
- ### 1. Wrap your app with AuthProvider
32
-
33
- ```tsx
34
- import { AuthProvider } from '@rqdhw3n/react-auth-flow';
35
-
36
- function App() {
37
- return (
38
- <AuthProvider
39
- baseURL="https://api.example.com"
40
- autoRefresh={true}
41
- refreshInterval={5 * 60 * 1000} // 5 minutes
42
- >
43
- {/* Your app components */}
44
- </AuthProvider>
45
- );
46
- }
47
- ```
48
-
49
- ### 2. Use the useAuth hook
50
-
51
- ```tsx
52
- import { useAuth } from '@rqdhw3n/react-auth-flow';
53
-
54
- function Header() {
55
- const { user, isAuthenticated, logout } = useAuth();
56
-
57
- if (!isAuthenticated) {
58
- return <span>Please log in</span>;
59
- }
60
-
61
- return (
62
- <div>
63
- <p>Welcome, {user?.name}</p>
64
- <button onClick={logout}>Logout</button>
65
- </div>
66
- );
67
- }
68
- ```
69
-
70
- ## Usage Examples
71
-
72
- ### LoginForm Component
73
-
74
- ```tsx
75
- import { LoginForm } from '@rqdhw3n/react-auth-flow';
76
- import { useNavigate } from 'react-router-dom';
77
-
78
- function LoginPage() {
79
- const navigate = useNavigate();
80
-
81
- return (
82
- <LoginForm
83
- className="my-login-form"
84
- labels={{
85
- email: 'Email Address',
86
- password: 'Password',
87
- rememberMe: 'Keep me signed in',
88
- }}
89
- placeholders={{
90
- email: 'name@example.com',
91
- password: 'Enter your password',
92
- }}
93
- submitButtonText="Sign In"
94
- onSuccess={(user) => {
95
- console.log('Logged in:', user);
96
- navigate('/dashboard');
97
- }}
98
- onError={(error) => {
99
- console.error('Login failed:', error);
100
- }}
101
- />
102
- );
103
- }
104
- ```
105
-
106
- ### RegisterForm Component
107
-
108
- ```tsx
109
- import { RegisterForm } from '@rqdhw3n/react-auth-flow';
110
-
111
- function SignUpPage() {
112
- return (
113
- <RegisterForm
114
- submitButtonText="Create Account"
115
- labels={{
116
- name: 'Full Name',
117
- email: 'Email Address',
118
- password: 'Password',
119
- confirmPassword: 'Confirm Password',
120
- }}
121
- onSuccess={() => {
122
- // Navigate to email verification or login
123
- }}
124
- onError={(error) => {
125
- alert(error.message);
126
- }}
127
- />
128
- );
129
- }
130
- ```
131
-
132
- ### ForgotPasswordForm Component
133
-
134
- ```tsx
135
- import { ForgotPasswordForm } from '@rqdhw3n/react-auth-flow';
136
-
137
- function ForgotPasswordPage() {
138
- return (
139
- <ForgotPasswordForm
140
- submitButtonText="Send Recovery Email"
141
- labels={{
142
- email: 'Enter your email address',
143
- }}
144
- onSuccess={() => {
145
- alert('Recovery email sent! Check your inbox.');
146
- }}
147
- />
148
- );
149
- }
150
- ```
151
-
152
- ### ResetPasswordForm Component
153
-
154
- ```tsx
155
- import { ResetPasswordForm } from '@rqdhw3n/react-auth-flow';
156
- import { useSearchParams } from 'react-router-dom';
157
-
158
- function ResetPasswordPage() {
159
- const [searchParams] = useSearchParams();
160
- const token = searchParams.get('token') || '';
161
-
162
- return (
163
- <ResetPasswordForm
164
- token={token}
165
- submitButtonText="Update Password"
166
- onSuccess={() => {
167
- alert('Password updated successfully!');
168
- // Navigate to login
169
- }}
170
- />
171
- );
172
- }
173
- ```
174
-
175
- ### VerifyEmailForm Component
176
-
177
- ```tsx
178
- import { VerifyEmailForm } from '@rqdhw3n/react-auth-flow';
179
- import { useSearchParams } from 'react-router-dom';
180
-
181
- function VerifyEmailPage() {
182
- const [searchParams] = useSearchParams();
183
- const token = searchParams.get('token') || '';
184
- const email = searchParams.get('email') || '';
185
-
186
- return (
187
- <VerifyEmailForm
188
- token={token}
189
- email={email}
190
- onSuccess={() => {
191
- alert('Email verified!');
192
- }}
193
- />
194
- );
195
- }
196
- ```
197
-
198
- ### ProtectedRoute Component
199
-
200
- ```tsx
201
- import { ProtectedRoute } from '@rqdhw3n/react-auth-flow';
202
- import { Routes, Route } from 'react-router-dom';
203
-
204
- function App() {
205
- return (
206
- <Routes>
207
- <Route path="/login" element={<LoginPage />} />
208
- <Route
209
- path="/dashboard"
210
- element={
211
- <ProtectedRoute redirectTo="/login">
212
- <Dashboard />
213
- </ProtectedRoute>
214
- }
215
- />
216
- <Route
217
- path="/admin"
218
- element={
219
- <ProtectedRoute
220
- roles={['admin']}
221
- redirectTo="/unauthorized"
222
- >
223
- <AdminPanel />
224
- </ProtectedRoute>
225
- }
226
- />
227
- <Route
228
- path="/manage-users"
229
- element={
230
- <ProtectedRoute
231
- permissions={['users.manage', 'users.delete']}
232
- redirectTo="/unauthorized"
233
- >
234
- <UserManagement />
235
- </ProtectedRoute>
236
- }
237
- />
238
- </Routes>
239
- );
240
- }
241
- ```
242
-
243
- ### useAuth Hook
244
-
245
- ```tsx
246
- import { useAuth } from '@rqdhw3n/react-auth-flow';
247
-
248
- function UserProfile() {
249
- const {
250
- user,
251
- isAuthenticated,
252
- isLoading,
253
- error,
254
- login,
255
- logout,
256
- refreshSession,
257
- setUser,
258
- } = useAuth();
259
-
260
- const handleLogin = async () => {
261
- try {
262
- const user = await login({
263
- email: 'user@example.com',
264
- password: 'password',
265
- rememberMe: true,
266
- });
267
- console.log('Logged in as:', user);
268
- } catch (err) {
269
- console.error('Login failed:', err);
270
- }
271
- };
272
-
273
- const handleLogout = async () => {
274
- await logout();
275
- console.log('Logged out');
276
- };
277
-
278
- if (isLoading) {
279
- return <div>Loading...</div>;
280
- }
281
-
282
- if (error) {
283
- return <div>Error: {error.message}</div>;
284
- }
285
-
286
- if (!isAuthenticated) {
287
- return <button onClick={handleLogin}>Login</button>;
288
- }
289
-
290
- return (
291
- <div>
292
- <h1>Hello, {user?.name}</h1>
293
- <p>Email: {user?.email}</p>
294
- <p>Roles: {user?.roles?.join(', ')}</p>
295
- <button onClick={handleLogout}>Logout</button>
296
- <button onClick={refreshSession}>Refresh Session</button>
297
- </div>
298
- );
299
- }
300
- ```
301
-
302
- ## API Endpoints Configuration
303
-
304
- The package expects your backend to provide the following endpoints by default:
305
-
306
- ### Default Endpoints
307
-
308
- - `POST /auth/login` - Login with email and password
309
- - `POST /auth/register` - Register a new account
310
- - `POST /auth/logout` - Logout the user
311
- - `GET /auth/me` - Get current user information
312
- - `POST /auth/refresh` - Refresh authentication token
313
- - `POST /auth/forgot-password` - Request password reset
314
- - `POST /auth/reset-password` - Reset password with token
315
- - `POST /auth/verify-email` - Verify email with token
316
-
317
- ### Customizing Endpoints
318
-
319
- ```tsx
320
- import { AuthProvider } from '@rqdhw3n/react-auth-flow';
321
-
322
- <AuthProvider
323
- baseURL="https://api.example.com"
324
- endpoints={{
325
- login: '/auth/signin',
326
- register: '/auth/signup',
327
- me: '/user/profile',
328
- // ... other endpoints
329
- }}
330
- >
331
- {/* Your app */}
332
- </AuthProvider>
333
- ```
334
-
335
- ## Expected API Response Formats
336
-
337
- ### Login Response
338
-
339
- ```json
340
- {
341
- "user": {
342
- "id": 1,
343
- "name": "John Doe",
344
- "email": "john@example.com",
345
- "roles": ["admin"],
346
- "permissions": ["users.manage", "users.delete"]
347
- }
348
- }
349
- ```
350
-
351
- ### Current User (Me) Response
352
-
353
- ```json
354
- {
355
- "user": {
356
- "id": 1,
357
- "name": "John Doe",
358
- "email": "john@example.com",
359
- "roles": ["admin"],
360
- "permissions": ["users.manage", "users.delete"]
361
- }
362
- }
363
- ```
364
-
365
- ### Error Response
366
-
367
- ```json
368
- {
369
- "error": {
370
- "code": "INVALID_CREDENTIALS",
371
- "message": "Invalid email or password",
372
- "statusCode": 401
373
- }
374
- }
375
- ```
376
-
377
- ## HttpOnly Cookie JWT Authentication
378
-
379
- For enhanced security, configure your backend to use HttpOnly cookies:
380
-
381
- ```tsx
382
- // Backend should set a cookie like:
383
- // Set-Cookie: jwt=token; HttpOnly; Secure; SameSite=Strict; Max-Age=3600
384
-
385
- // The package will automatically include cookies with requests
386
- // because credentials: "include" is set by default
387
- ```
388
-
389
- ## Custom Headers and Request Adapter
390
-
391
- ```tsx
392
- import { createAuthClient } from '@rqdhw3n/react-auth-flow';
393
-
394
- // Create a custom client
395
- const authClient = createAuthClient({
396
- baseURL: 'https://api.example.com',
397
- headers: {
398
- 'X-API-Key': 'your-api-key',
399
- 'X-Client-Version': '1.0.0',
400
- },
401
- credentials: 'include', // for HttpOnly cookies
402
- adapter: async (url, options) => {
403
- // Custom request logic
404
- console.log('Making request to:', url);
405
- return fetch(url, options);
406
- },
407
- });
408
-
409
- // Use in AuthProvider
410
- <AuthProvider
411
- baseURL="https://api.example.com"
412
- // ... other config
413
- >
414
- {/* Your app */}
415
- </AuthProvider>
416
- ```
417
-
418
- ## TypeScript Customization
419
-
420
- Extend types for your application:
421
-
422
- ```tsx
423
- import { AuthUser, AuthContextValue } from '@rqdhw3n/react-auth-flow';
424
-
425
- // Extend the AuthUser type
426
- interface AppUser extends AuthUser {
427
- id: number;
428
- name: string;
429
- email: string;
430
- roles: string[];
431
- permissions: string[];
432
- company?: string;
433
- department?: string;
434
- }
435
-
436
- // Use in your components
437
- import { useAuth } from '@rqdhw3n/react-auth-flow';
438
-
439
- function MyComponent() {
440
- const { user } = useAuth();
441
- const appUser = user as AppUser;
442
-
443
- return <div>Working in {appUser.department}</div>;
444
- }
445
- ```
446
-
447
- ## Styling Components
448
-
449
- All form components use semantic class names for styling:
450
-
451
- ```css
452
- .auth-form-group {
453
- margin-bottom: 1rem;
454
- }
455
-
456
- .auth-form-label {
457
- display: block;
458
- margin-bottom: 0.5rem;
459
- font-weight: 500;
460
- }
461
-
462
- .auth-form-input {
463
- width: 100%;
464
- padding: 0.5rem;
465
- border: 1px solid #ccc;
466
- border-radius: 4px;
467
- font-size: 1rem;
468
- }
469
-
470
- .auth-form-input:disabled {
471
- background-color: #f5f5f5;
472
- cursor: not-allowed;
473
- }
474
-
475
- .auth-form-error {
476
- color: #dc3545;
477
- margin-top: 0.5rem;
478
- font-size: 0.875rem;
479
- }
480
-
481
- .auth-form-button {
482
- padding: 0.5rem 1rem;
483
- border: none;
484
- border-radius: 4px;
485
- font-size: 1rem;
486
- cursor: pointer;
487
- width: 100%;
488
- }
489
-
490
- .auth-form-button-primary {
491
- background-color: #007bff;
492
- color: white;
493
- }
494
-
495
- .auth-form-button-primary:hover {
496
- background-color: #0056b3;
497
- }
498
-
499
- .auth-form-button:disabled {
500
- opacity: 0.5;
501
- cursor: not-allowed;
502
- }
503
-
504
- .auth-form-checkbox {
505
- display: flex;
506
- align-items: center;
507
- gap: 0.5rem;
508
- }
509
-
510
- .auth-form-checkbox .auth-form-label {
511
- margin-bottom: 0;
512
- }
513
-
514
- .auth-form-success {
515
- padding: 1rem;
516
- background-color: #d4edda;
517
- border: 1px solid #c3e6cb;
518
- border-radius: 4px;
519
- color: #155724;
520
- }
521
-
522
- .auth-form-success-message {
523
- margin: 0;
524
- }
525
-
526
- .auth-loading {
527
- text-align: center;
528
- padding: 2rem;
529
- font-size: 1rem;
530
- }
531
-
532
- .auth-forbidden {
533
- padding: 2rem;
534
- text-align: center;
535
- color: #dc3545;
536
- }
537
- ```
538
-
539
- ## Error Handling
540
-
541
- The package normalizes all errors to a consistent format:
542
-
543
- ```tsx
544
- import { useAuth, AuthError } from '@rqdhw3n/react-auth-flow';
545
-
546
- function MyComponent() {
547
- const { error } = useAuth();
548
-
549
- if (error) {
550
- const authError: AuthError = error;
551
- console.log({
552
- code: authError.code, // e.g., "INVALID_CREDENTIALS"
553
- message: authError.message,
554
- statusCode: authError.statusCode, // e.g., 401
555
- details: authError.details, // additional error info
556
- });
557
- }
558
-
559
- return <div>Status: {error?.message}</div>;
560
- }
561
- ```
562
-
563
- ## License
564
-
565
- MIT
566
-
567
- ## Support
568
-
569
- For issues and feature requests, please visit the [GitHub repository](https://github.com/rqdhw3n/react-auth-flow).
1
+ # @rqdhw3n/react-auth-flow
2
+
3
+ A TypeScript-first authentication flow package for React applications with built-in, production-ready auth form styling.
4
+
5
+ ## Features
6
+
7
+ - Secure by default with cookie-based auth support
8
+ - Zero UI framework dependency
9
+ - Built-in stylesheet loaded automatically from the package entry
10
+ - Ready-to-use `LoginForm`, `RegisterForm`, `ForgotPasswordForm`, `ResetPasswordForm`, and `VerifyEmailForm`
11
+ - `AuthProvider` and `useAuth()` for auth state management
12
+ - `ProtectedRoute` support for React Router
13
+ - Customizable endpoints, headers, and request adapters
14
+ - Override-friendly class name props for consumer styling
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @rqdhw3n/react-auth-flow react react-dom react-router-dom
20
+ ```
21
+
22
+ No Tailwind, PostCSS, `tailwind.config.js`, or manual CSS import is required. Importing the package automatically loads the packaged auth stylesheet.
23
+
24
+ ## Quick Setup
25
+
26
+ ### Wrap your app with `AuthProvider`
27
+
28
+ ```tsx
29
+ import { AuthProvider } from "@rqdhw3n/react-auth-flow";
30
+
31
+ function App() {
32
+ return (
33
+ <AuthProvider
34
+ baseURL="https://api.example.com"
35
+ autoRefresh={true}
36
+ refreshInterval={5 * 60 * 1000}
37
+ >
38
+ {/* your app */}
39
+ </AuthProvider>
40
+ );
41
+ }
42
+ ```
43
+
44
+ ### Use `useAuth()`
45
+
46
+ ```tsx
47
+ import { useAuth } from "@rqdhw3n/react-auth-flow";
48
+
49
+ function Header() {
50
+ const { user, isAuthenticated, logout } = useAuth();
51
+
52
+ if (!isAuthenticated) {
53
+ return <span>Please log in</span>;
54
+ }
55
+
56
+ return (
57
+ <div>
58
+ <p>Welcome, {user?.name}</p>
59
+ <button onClick={logout}>Logout</button>
60
+ </div>
61
+ );
62
+ }
63
+ ```
64
+
65
+ ## Forms
66
+
67
+ ### Styled out of the box
68
+
69
+ ```tsx
70
+ import { LoginForm } from "@rqdhw3n/react-auth-flow";
71
+
72
+ function App() {
73
+ return <LoginForm />;
74
+ }
75
+ ```
76
+
77
+ ### Login form
78
+
79
+ ```tsx
80
+ import { LoginForm } from "@rqdhw3n/react-auth-flow";
81
+ import { useNavigate } from "react-router-dom";
82
+
83
+ function LoginPage() {
84
+ const navigate = useNavigate();
85
+
86
+ return (
87
+ <div
88
+ style={{
89
+ minHeight: "100vh",
90
+ display: "grid",
91
+ placeItems: "center",
92
+ padding: 24,
93
+ background: "#f4f7fb",
94
+ }}
95
+ >
96
+ <LoginForm
97
+ title="Welcome back"
98
+ subtitle="Sign in to continue"
99
+ submitButtonText="Sign In"
100
+ loadingText="Signing in..."
101
+ labels={{
102
+ email: "Email Address",
103
+ password: "Password",
104
+ rememberMe: "Keep me signed in",
105
+ }}
106
+ onSuccess={() => navigate("/dashboard")}
107
+ />
108
+ </div>
109
+ );
110
+ }
111
+ ```
112
+
113
+ ### Register form
114
+
115
+ ```tsx
116
+ import { RegisterForm } from "@rqdhw3n/react-auth-flow";
117
+
118
+ function SignUpPage() {
119
+ return (
120
+ <RegisterForm
121
+ title="Create your account"
122
+ subtitle="Get started in seconds"
123
+ submitButtonText="Create Account"
124
+ loadingText="Creating account..."
125
+ />
126
+ );
127
+ }
128
+ ```
129
+
130
+ ### Forgot password form
131
+
132
+ ```tsx
133
+ import { ForgotPasswordForm } from "@rqdhw3n/react-auth-flow";
134
+
135
+ function ForgotPasswordPage() {
136
+ return (
137
+ <ForgotPasswordForm
138
+ title="Reset your password"
139
+ subtitle="Enter your email to receive a reset link"
140
+ />
141
+ );
142
+ }
143
+ ```
144
+
145
+ ### Reset password form
146
+
147
+ ```tsx
148
+ import { ResetPasswordForm } from "@rqdhw3n/react-auth-flow";
149
+ import { useSearchParams } from "react-router-dom";
150
+
151
+ function ResetPasswordPage() {
152
+ const [searchParams] = useSearchParams();
153
+ const token = searchParams.get("token") || "";
154
+
155
+ return (
156
+ <ResetPasswordForm
157
+ token={token}
158
+ title="Create a new password"
159
+ subtitle="Use at least 8 characters"
160
+ />
161
+ );
162
+ }
163
+ ```
164
+
165
+ ### Verify email form
166
+
167
+ ```tsx
168
+ import { VerifyEmailForm } from "@rqdhw3n/react-auth-flow";
169
+ import { useSearchParams } from "react-router-dom";
170
+
171
+ function VerifyEmailPage() {
172
+ const [searchParams] = useSearchParams();
173
+
174
+ return (
175
+ <VerifyEmailForm
176
+ token={searchParams.get("token") || ""}
177
+ email={searchParams.get("email") || ""}
178
+ title="Verify your email"
179
+ subtitle="Enter the verification code you received"
180
+ />
181
+ );
182
+ }
183
+ ```
184
+
185
+ ## Styling Overrides
186
+
187
+ The package ships with default classes and also supports consumer overrides through props:
188
+
189
+ - `className`
190
+ - `formClassName`
191
+ - `fieldClassName`
192
+ - `labelClassName`
193
+ - `inputClassName`
194
+ - `buttonClassName`
195
+ - `errorClassName`
196
+ - `successClassName`
197
+ - `titleClassName`
198
+ - `subtitleClassName`
199
+
200
+ Example:
201
+
202
+ ```tsx
203
+ import { LoginForm } from "@rqdhw3n/react-auth-flow";
204
+
205
+ function CustomLoginPage() {
206
+ return (
207
+ <LoginForm
208
+ className="my-auth-card"
209
+ formClassName="my-auth-form"
210
+ labelClassName="my-auth-label"
211
+ inputClassName="my-auth-input"
212
+ buttonClassName="my-auth-button"
213
+ errorClassName="my-auth-error"
214
+ successClassName="my-auth-success"
215
+ />
216
+ );
217
+ }
218
+ ```
219
+
220
+ Default packaged class names:
221
+
222
+ - `.rq-auth-container`
223
+ - `.rq-auth-form`
224
+ - `.rq-auth-field`
225
+ - `.rq-auth-label`
226
+ - `.rq-auth-input`
227
+ - `.rq-auth-button`
228
+ - `.rq-auth-error`
229
+ - `.rq-auth-success`
230
+ - `.rq-auth-title`
231
+ - `.rq-auth-subtitle`
232
+ - `.rq-auth-checkbox`
233
+
234
+ ## Protected Routes
235
+
236
+ ```tsx
237
+ import { ProtectedRoute } from "@rqdhw3n/react-auth-flow";
238
+ import { Routes, Route } from "react-router-dom";
239
+
240
+ function AppRoutes() {
241
+ return (
242
+ <Routes>
243
+ <Route path="/login" element={<LoginPage />} />
244
+ <Route
245
+ path="/dashboard"
246
+ element={
247
+ <ProtectedRoute redirectTo="/login">
248
+ <Dashboard />
249
+ </ProtectedRoute>
250
+ }
251
+ />
252
+ </Routes>
253
+ );
254
+ }
255
+ ```
256
+
257
+ ## Notes
258
+
259
+ - The package stylesheet is imported from `src/index.ts`, so consumers do not need `import "./styles.css"` in their apps.
260
+ - Build output includes JavaScript bundles and an emitted CSS asset in `dist`.
261
+ - The components are responsive by default and work on desktop and mobile without extra setup.