@skylabs-digital/react-identity-access 2.24.0 โ 2.25.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 +560 -150
- package/dist/components/LoginForm.d.ts +5 -0
- package/dist/components/LoginForm.d.ts.map +1 -1
- package/dist/components/MagicLinkForm.d.ts +10 -0
- package/dist/components/MagicLinkForm.d.ts.map +1 -1
- package/dist/components/MagicLinkVerify.d.ts +3 -0
- package/dist/components/MagicLinkVerify.d.ts.map +1 -1
- package/dist/components/PasswordRecoveryForm.d.ts +5 -0
- package/dist/components/PasswordRecoveryForm.d.ts.map +1 -1
- package/dist/components/SignupForm.d.ts +4 -0
- package/dist/components/SignupForm.d.ts.map +1 -1
- package/dist/components/TenantSelector.d.ts +13 -1
- package/dist/components/TenantSelector.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +1212 -1161
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/providers/AppProvider.d.ts.map +1 -1
- package/dist/providers/AuthProvider.d.ts.map +1 -1
- package/dist/providers/TenantProvider.d.ts.map +1 -1
- package/dist/services/SessionManager.d.ts.map +1 -1
- package/dist/utils/crossDomainAuth.d.ts.map +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -15,6 +15,7 @@ A powerful, modern authentication and authorization library for React applicatio
|
|
|
15
15
|
- **๐ Session Management** - Automatic session handling and token refresh
|
|
16
16
|
- **๐จ Feature Flags** - Built-in feature flag management
|
|
17
17
|
- **๐ณ Subscription Management** - Integrated billing and subscription handling
|
|
18
|
+
- **๐๏ธ Fully Customizable Components** - All texts, styles, and icons are overridable via props
|
|
18
19
|
|
|
19
20
|
## ๐ฆ Installation
|
|
20
21
|
|
|
@@ -22,21 +23,19 @@ A powerful, modern authentication and authorization library for React applicatio
|
|
|
22
23
|
npm install @skylabs-digital/react-identity-access
|
|
23
24
|
# or
|
|
24
25
|
yarn add @skylabs-digital/react-identity-access
|
|
25
|
-
# or
|
|
26
|
-
pnpm add @skylabs-digital/react-identity-access
|
|
27
26
|
```
|
|
28
27
|
|
|
29
28
|
## ๐โโ๏ธ Quick Start
|
|
30
29
|
|
|
31
30
|
### 1. Setup Providers
|
|
32
31
|
|
|
33
|
-
Wrap your application with the required providers:
|
|
32
|
+
Wrap your application with the required providers in order:
|
|
34
33
|
|
|
35
34
|
```tsx
|
|
36
|
-
import {
|
|
37
|
-
AppProvider,
|
|
38
|
-
TenantProvider,
|
|
39
|
-
AuthProvider
|
|
35
|
+
import {
|
|
36
|
+
AppProvider,
|
|
37
|
+
TenantProvider,
|
|
38
|
+
AuthProvider,
|
|
40
39
|
} from '@skylabs-digital/react-identity-access';
|
|
41
40
|
|
|
42
41
|
function App() {
|
|
@@ -49,7 +48,7 @@ function App() {
|
|
|
49
48
|
>
|
|
50
49
|
<TenantProvider
|
|
51
50
|
config={{
|
|
52
|
-
tenantMode: 'selector', // 'subdomain'
|
|
51
|
+
tenantMode: 'selector', // 'subdomain' | 'selector' | 'fixed' | 'optional'
|
|
53
52
|
selectorParam: 'tenant',
|
|
54
53
|
}}
|
|
55
54
|
>
|
|
@@ -68,14 +67,12 @@ function App() {
|
|
|
68
67
|
import { useAuth } from '@skylabs-digital/react-identity-access';
|
|
69
68
|
|
|
70
69
|
function LoginComponent() {
|
|
71
|
-
const { login, logout,
|
|
72
|
-
const user = sessionManager.getUser();
|
|
70
|
+
const { login, logout, currentUser } = useAuth();
|
|
73
71
|
|
|
74
72
|
const handleLogin = async () => {
|
|
75
73
|
try {
|
|
76
74
|
// Supports both email and phone number
|
|
77
|
-
await login('user@example.com', 'password');
|
|
78
|
-
// await login('+1234567890', 'password'); // Phone
|
|
75
|
+
await login({ username: 'user@example.com', password: 'password' });
|
|
79
76
|
} catch (error) {
|
|
80
77
|
console.error('Login failed:', error);
|
|
81
78
|
}
|
|
@@ -83,9 +80,9 @@ function LoginComponent() {
|
|
|
83
80
|
|
|
84
81
|
return (
|
|
85
82
|
<div>
|
|
86
|
-
{
|
|
83
|
+
{currentUser ? (
|
|
87
84
|
<div>
|
|
88
|
-
<p>Welcome, {
|
|
85
|
+
<p>Welcome, {currentUser.name}!</p>
|
|
89
86
|
<button onClick={logout}>Logout</button>
|
|
90
87
|
</div>
|
|
91
88
|
) : (
|
|
@@ -96,53 +93,22 @@ function LoginComponent() {
|
|
|
96
93
|
}
|
|
97
94
|
```
|
|
98
95
|
|
|
99
|
-
### 3.
|
|
96
|
+
### 3. Pre-built Login Form
|
|
100
97
|
|
|
101
98
|
```tsx
|
|
102
|
-
import {
|
|
103
|
-
MagicLinkForm,
|
|
104
|
-
MagicLinkVerify,
|
|
105
|
-
useAuth
|
|
106
|
-
} from '@skylabs-digital/react-identity-access';
|
|
99
|
+
import { LoginForm } from '@skylabs-digital/react-identity-access';
|
|
107
100
|
import { useNavigate } from 'react-router-dom';
|
|
108
101
|
|
|
109
|
-
|
|
110
|
-
function MagicLinkLogin() {
|
|
102
|
+
function LoginPage() {
|
|
111
103
|
const navigate = useNavigate();
|
|
112
104
|
|
|
113
|
-
const handleSuccess = (response) => {
|
|
114
|
-
console.log('Magic link sent successfully!');
|
|
115
|
-
};
|
|
116
|
-
|
|
117
105
|
return (
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
onLoginClick={() => navigate('/login')}
|
|
106
|
+
<LoginForm
|
|
107
|
+
onSuccess={() => navigate('/dashboard')}
|
|
108
|
+
onForgotPassword={() => navigate('/forgot-password')}
|
|
122
109
|
onSignupClick={() => navigate('/signup')}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Verify Magic Link (at /magic-link/verify route)
|
|
128
|
-
function MagicLinkVerifyPage() {
|
|
129
|
-
const navigate = useNavigate();
|
|
130
|
-
|
|
131
|
-
const handleSuccess = (data) => {
|
|
132
|
-
console.log('Magic link verified!', data);
|
|
133
|
-
navigate('/dashboard');
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
const handleError = (error) => {
|
|
137
|
-
console.error('Verification failed:', error);
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
return (
|
|
141
|
-
<MagicLinkVerify
|
|
142
|
-
onSuccess={handleSuccess}
|
|
143
|
-
onError={handleError}
|
|
144
|
-
onBackToLogin={() => navigate('/login')}
|
|
145
|
-
autoRedirectDelay={3000}
|
|
110
|
+
onMagicLinkClick={() => navigate('/magic-link')}
|
|
111
|
+
showMagicLinkOption={true}
|
|
146
112
|
/>
|
|
147
113
|
);
|
|
148
114
|
}
|
|
@@ -165,117 +131,565 @@ function AdminPanel() {
|
|
|
165
131
|
}
|
|
166
132
|
```
|
|
167
133
|
|
|
168
|
-
|
|
134
|
+
---
|
|
169
135
|
|
|
170
|
-
|
|
136
|
+
## ๐งฉ Component Reference
|
|
171
137
|
|
|
172
|
-
|
|
138
|
+
All form components support three customization axes:
|
|
173
139
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
140
|
+
- **`copy`** - Override any user-facing text (labels, placeholders, messages, buttons)
|
|
141
|
+
- **`styles`** - Override any inline style on any element (`React.CSSProperties`)
|
|
142
|
+
- **`icons`** - Override SVG icons (where applicable)
|
|
143
|
+
|
|
144
|
+
All customization props are **optional** and **backward compatible** โ if you omit them, sensible defaults are used.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
### LoginForm
|
|
149
|
+
|
|
150
|
+
Traditional email/phone + password login form.
|
|
151
|
+
|
|
152
|
+
#### Props (`LoginFormProps`)
|
|
153
|
+
|
|
154
|
+
| Prop | Type | Default | Description |
|
|
155
|
+
|------|------|---------|-------------|
|
|
156
|
+
| `copy` | `LoginFormCopy` | See below | Override user-facing texts |
|
|
157
|
+
| `styles` | `LoginFormStyles` | See below | Override inline styles |
|
|
158
|
+
| `icons` | `LoginFormIcons` | Eye/EyeOff SVGs | Override password toggle icons |
|
|
159
|
+
| `onSuccess` | `(data: any) => void` | โ | Called after successful login |
|
|
160
|
+
| `onError` | `(error: string) => void` | โ | Called on login failure |
|
|
161
|
+
| `onForgotPassword` | `() => void` | โ | Navigate to forgot password |
|
|
162
|
+
| `onSignupClick` | `() => void` | โ | Navigate to signup |
|
|
163
|
+
| `onMagicLinkClick` | `() => void` | โ | Navigate to magic link |
|
|
164
|
+
| `showForgotPassword` | `boolean` | `true` | Show "Forgot password?" link |
|
|
165
|
+
| `showSignupLink` | `boolean` | `true` | Show signup link |
|
|
166
|
+
| `showMagicLinkOption` | `boolean` | `false` | Show magic link option |
|
|
167
|
+
| `className` | `string` | โ | CSS class for the root element |
|
|
168
|
+
|
|
169
|
+
#### Copy (`LoginFormCopy`)
|
|
170
|
+
|
|
171
|
+
| Key | Default |
|
|
172
|
+
|-----|---------|
|
|
173
|
+
| `title` | `'Sign In'` |
|
|
174
|
+
| `usernameLabel` | `'Email or Phone'` |
|
|
175
|
+
| `usernamePlaceholder` | `'Enter your email or phone number'` |
|
|
176
|
+
| `passwordLabel` | `'Password'` |
|
|
177
|
+
| `passwordPlaceholder` | `'Enter your password'` |
|
|
178
|
+
| `submitButton` | `'Sign In'` |
|
|
179
|
+
| `loadingText` | `'Signing in...'` |
|
|
180
|
+
| `errorMessage` | `'Invalid credentials'` |
|
|
181
|
+
| `forgotPasswordLink` | `'Forgot your password?'` |
|
|
182
|
+
| `signupLink` | `'Sign up here'` |
|
|
183
|
+
| `signupText` | `"Don't have an account?"` |
|
|
184
|
+
| `magicLinkText` | `'Prefer passwordless?'` |
|
|
185
|
+
| `magicLinkLink` | `'Use Magic Link'` |
|
|
186
|
+
| `tenantNotFoundError` | `'Tenant not found'` |
|
|
187
|
+
| `dividerBullet` | `'โข'` |
|
|
188
|
+
| `showPasswordAriaLabel` | `'Show password'` |
|
|
189
|
+
| `hidePasswordAriaLabel` | `'Hide password'` |
|
|
190
|
+
|
|
191
|
+
#### Styles (`LoginFormStyles`)
|
|
192
|
+
|
|
193
|
+
| Key | Targets |
|
|
194
|
+
|-----|---------|
|
|
195
|
+
| `container` | Root wrapper |
|
|
196
|
+
| `title` | `<h2>` heading |
|
|
197
|
+
| `form` | `<form>` element |
|
|
198
|
+
| `fieldGroup` | Each label+input group |
|
|
199
|
+
| `label` | `<label>` elements |
|
|
200
|
+
| `input` | `<input>` elements |
|
|
201
|
+
| `inputError` | Input in error state (merged on top of `input`) |
|
|
202
|
+
| `inputContainer` | Password field wrapper |
|
|
203
|
+
| `inputWithIcon` | Password input with toggle icon |
|
|
204
|
+
| `passwordToggle` | Show/hide password button |
|
|
205
|
+
| `button` | Submit button |
|
|
206
|
+
| `buttonDisabled` | Disabled state (merged on top of `button`) |
|
|
207
|
+
| `buttonLoading` | Loading state (merged on top of `button`) |
|
|
208
|
+
| `errorText` | Error message text |
|
|
209
|
+
| `linkContainer` | Links section wrapper |
|
|
210
|
+
| `link` | `<a>` link elements |
|
|
211
|
+
| `divider` | Bullet divider between links |
|
|
212
|
+
|
|
213
|
+
#### Usage Example
|
|
182
214
|
|
|
183
|
-
|
|
215
|
+
```tsx
|
|
184
216
|
<LoginForm
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
217
|
+
copy={{
|
|
218
|
+
title: 'Bienvenido',
|
|
219
|
+
submitButton: 'Iniciar Sesion',
|
|
220
|
+
usernameLabel: 'Correo electronico',
|
|
221
|
+
forgotPasswordLink: 'ยฟOlvidaste tu contraseรฑa?',
|
|
222
|
+
}}
|
|
223
|
+
styles={{
|
|
224
|
+
container: { maxWidth: '500px', backgroundColor: '#f0f4f8' },
|
|
225
|
+
button: { backgroundColor: '#4f46e5', borderRadius: '12px' },
|
|
226
|
+
}}
|
|
227
|
+
icons={{
|
|
228
|
+
showPassword: <MyEyeIcon />,
|
|
229
|
+
hidePassword: <MyEyeOffIcon />,
|
|
230
|
+
}}
|
|
231
|
+
onSuccess={(data) => navigate('/dashboard')}
|
|
188
232
|
onMagicLinkClick={() => navigate('/magic-link')}
|
|
189
|
-
showMagicLinkOption
|
|
233
|
+
showMagicLinkOption
|
|
190
234
|
/>
|
|
235
|
+
```
|
|
191
236
|
|
|
192
|
-
|
|
193
|
-
<SignupForm
|
|
194
|
-
onSuccess={(user) => console.log('Signed up:', user)}
|
|
195
|
-
onLoginClick={() => navigate('/login')}
|
|
196
|
-
onMagicLinkClick={() => navigate('/magic-link')}
|
|
197
|
-
showMagicLinkOption={true}
|
|
198
|
-
/>
|
|
237
|
+
---
|
|
199
238
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
239
|
+
### SignupForm
|
|
240
|
+
|
|
241
|
+
User registration form with email/phone, password, and optional tenant creation.
|
|
242
|
+
|
|
243
|
+
#### Props (`SignupFormProps`)
|
|
244
|
+
|
|
245
|
+
| Prop | Type | Default | Description |
|
|
246
|
+
|------|------|---------|-------------|
|
|
247
|
+
| `copy` | `SignupFormCopy` | See below | Override user-facing texts |
|
|
248
|
+
| `styles` | `SignupFormStyles` | See below | Override inline styles |
|
|
249
|
+
| `signupType` | `'user' \| 'tenant'` | `'user'` | User signup or tenant admin signup |
|
|
250
|
+
| `onSuccess` | `(data: any) => void` | โ | Called after successful signup |
|
|
251
|
+
| `onError` | `(error: string) => void` | โ | Called on signup failure |
|
|
252
|
+
| `onLoginClick` | `() => void` | โ | Navigate to login |
|
|
253
|
+
| `onMagicLinkClick` | `() => void` | โ | Navigate to magic link |
|
|
254
|
+
| `showLoginLink` | `boolean` | `true` | Show login link |
|
|
255
|
+
| `showMagicLinkOption` | `boolean` | `false` | Show magic link option |
|
|
256
|
+
| `className` | `string` | โ | CSS class for the root element |
|
|
257
|
+
|
|
258
|
+
#### Copy (`SignupFormCopy`)
|
|
259
|
+
|
|
260
|
+
| Key | Default |
|
|
261
|
+
|-----|---------|
|
|
262
|
+
| `title` | `'Create Account'` |
|
|
263
|
+
| `nameLabel` | `'First Name'` |
|
|
264
|
+
| `namePlaceholder` | `'Enter your first name'` |
|
|
265
|
+
| `lastNameLabel` | `'Last Name'` |
|
|
266
|
+
| `lastNamePlaceholder` | `'Enter your last name'` |
|
|
267
|
+
| `emailLabel` | `'Email'` |
|
|
268
|
+
| `emailPlaceholder` | `'Enter your email'` |
|
|
269
|
+
| `phoneNumberLabel` | `'Phone Number'` |
|
|
270
|
+
| `phoneNumberPlaceholder` | `'Enter your phone number'` |
|
|
271
|
+
| `passwordLabel` | `'Password'` |
|
|
272
|
+
| `passwordPlaceholder` | `'Enter your password'` |
|
|
273
|
+
| `confirmPasswordLabel` | `'Confirm Password'` |
|
|
274
|
+
| `confirmPasswordPlaceholder` | `'Confirm your password'` |
|
|
275
|
+
| `tenantNameLabel` | `'Organization Name'` |
|
|
276
|
+
| `tenantNamePlaceholder` | `'Enter your organization name'` |
|
|
277
|
+
| `submitButton` | `'Create Account'` |
|
|
278
|
+
| `loadingText` | `'Creating account...'` |
|
|
279
|
+
| `errorMessage` | `'Failed to create account'` |
|
|
280
|
+
| `passwordMismatchError` | `'Passwords do not match'` |
|
|
281
|
+
| `loginLink` | `'Sign in here'` |
|
|
282
|
+
| `loginText` | `'Already have an account?'` |
|
|
283
|
+
| `magicLinkText` | `'Prefer passwordless?'` |
|
|
284
|
+
| `magicLinkLink` | `'Use Magic Link'` |
|
|
285
|
+
| `isAdminLabel` | `'Create new organization'` |
|
|
286
|
+
| `isAdminDescription` | `'Check this if you want to create a new organization'` |
|
|
287
|
+
| `contactMethodHint` | `'At least one contact method (email or phone) is required'` |
|
|
288
|
+
| `tenantNotFoundError` | `'Tenant not found'` |
|
|
289
|
+
| `dividerBullet` | `'โข'` |
|
|
290
|
+
|
|
291
|
+
#### Styles (`SignupFormStyles`)
|
|
292
|
+
|
|
293
|
+
| Key | Targets |
|
|
294
|
+
|-----|---------|
|
|
295
|
+
| `container` | Root wrapper |
|
|
296
|
+
| `title` | `<h2>` heading |
|
|
297
|
+
| `form` | `<form>` element |
|
|
298
|
+
| `fieldGroup` | Each label+input group |
|
|
299
|
+
| `label` | `<label>` elements |
|
|
300
|
+
| `input` | `<input>` elements |
|
|
301
|
+
| `inputError` | Input in error state |
|
|
302
|
+
| `checkbox` | Checkbox input |
|
|
303
|
+
| `checkboxContainer` | Checkbox + label wrapper |
|
|
304
|
+
| `checkboxLabel` | Checkbox label text |
|
|
305
|
+
| `button` | Submit button |
|
|
306
|
+
| `buttonDisabled` | Disabled state (merged on top of `button`) |
|
|
307
|
+
| `buttonLoading` | Loading state (merged on top of `button`) |
|
|
308
|
+
| `errorText` | Error message text |
|
|
309
|
+
| `linkContainer` | Links section wrapper |
|
|
310
|
+
| `link` | `<a>` link elements |
|
|
311
|
+
| `divider` | Bullet divider between links |
|
|
312
|
+
| `hintText` | Contact method hint text |
|
|
207
313
|
|
|
208
|
-
|
|
209
|
-
<MagicLinkVerify
|
|
210
|
-
onSuccess={(data) => navigate('/dashboard')}
|
|
211
|
-
onError={(error) => console.error(error)}
|
|
212
|
-
onBackToLogin={() => navigate('/login')}
|
|
213
|
-
/>
|
|
314
|
+
---
|
|
214
315
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
316
|
+
### MagicLinkForm
|
|
317
|
+
|
|
318
|
+
Passwordless Magic Link send form. Handles both new and existing users.
|
|
319
|
+
|
|
320
|
+
#### Props (`MagicLinkFormProps`)
|
|
321
|
+
|
|
322
|
+
| Prop | Type | Default | Description |
|
|
323
|
+
|------|------|---------|-------------|
|
|
324
|
+
| `copy` | `MagicLinkFormCopy` | See below | Override user-facing texts |
|
|
325
|
+
| `styles` | `MagicLinkFormStyles` | See below | Override inline styles |
|
|
326
|
+
| `onSuccess` | `(data: any) => void` | โ | Called after magic link sent |
|
|
327
|
+
| `onError` | `(error: string) => void` | โ | Called on failure |
|
|
328
|
+
| `onLoginClick` | `() => void` | โ | Navigate to login |
|
|
329
|
+
| `onSignupClick` | `() => void` | โ | Navigate to signup |
|
|
330
|
+
| `showTraditionalLinks` | `boolean` | `true` | Show login/signup links |
|
|
331
|
+
| `className` | `string` | โ | CSS class for the root element |
|
|
332
|
+
| `verifyToken` | `string` | โ | Auto-verify a magic link token |
|
|
333
|
+
| `frontendUrl` | `string` | `window.location.origin` | Base URL for the magic link callback |
|
|
334
|
+
|
|
335
|
+
#### Copy (`MagicLinkFormCopy`)
|
|
336
|
+
|
|
337
|
+
| Key | Default |
|
|
338
|
+
|-----|---------|
|
|
339
|
+
| `title` | `'Sign In with Magic Link'` |
|
|
340
|
+
| `description` | `"Enter your email to receive a magic link..."` |
|
|
341
|
+
| `emailLabel` | `'Email'` |
|
|
342
|
+
| `emailPlaceholder` | `'Enter your email'` |
|
|
343
|
+
| `nameLabel` | `'Name'` |
|
|
344
|
+
| `namePlaceholder` | `'Enter your name'` |
|
|
345
|
+
| `lastNameLabel` | `'Last Name'` |
|
|
346
|
+
| `lastNamePlaceholder` | `'Enter your last name'` |
|
|
347
|
+
| `submitButton` | `'Send Magic Link'` |
|
|
348
|
+
| `loadingText` | `'Sending magic link...'` |
|
|
349
|
+
| `successMessage` | `'Magic link sent! Check your email...'` |
|
|
350
|
+
| `errorMessage` | `'Failed to send magic link. Please try again.'` |
|
|
351
|
+
| `verifyingText` | `'Verifying magic link...'` |
|
|
352
|
+
| `verifyingDescription` | `'Please wait while we verify your magic link...'` |
|
|
353
|
+
| `showNameToggle` | `'New user? Add your name'` |
|
|
354
|
+
| `hideNameToggle` | `'Existing user? Hide name fields'` |
|
|
355
|
+
| `loginLink` | `'Sign in with password'` |
|
|
356
|
+
| `loginText` | `'Already have an account?'` |
|
|
357
|
+
| `signupLink` | `'Sign up with password'` |
|
|
358
|
+
| `signupText` | `'Prefer traditional signup?'` |
|
|
359
|
+
| `tenantNotFoundError` | `'Tenant not found'` |
|
|
360
|
+
| `missingTenantOrEmailError` | `'Missing tenant or email'` |
|
|
361
|
+
| `dividerBullet` | `'โข'` |
|
|
362
|
+
|
|
363
|
+
#### Styles (`MagicLinkFormStyles`)
|
|
364
|
+
|
|
365
|
+
| Key | Targets |
|
|
366
|
+
|-----|---------|
|
|
367
|
+
| `container` | Root wrapper |
|
|
368
|
+
| `title` | `<h2>` heading |
|
|
369
|
+
| `description` | Description paragraph |
|
|
370
|
+
| `form` | `<form>` element |
|
|
371
|
+
| `fieldGroup` | Each label+input group |
|
|
372
|
+
| `label` | `<label>` elements |
|
|
373
|
+
| `input` | `<input>` elements |
|
|
374
|
+
| `inputError` | Input in error state |
|
|
375
|
+
| `button` | Submit button |
|
|
376
|
+
| `buttonDisabled` | Disabled state (merged on top of `button`) |
|
|
377
|
+
| `buttonLoading` | Loading state (merged on top of `button`) |
|
|
378
|
+
| `errorText` | Error message text |
|
|
379
|
+
| `successText` | Success message text |
|
|
380
|
+
| `linkContainer` | Links section wrapper |
|
|
381
|
+
| `link` | `<a>` link elements |
|
|
382
|
+
| `divider` | Bullet divider between links |
|
|
383
|
+
| `verifyingContainer` | Verification loading wrapper |
|
|
384
|
+
| `verifyingText` | Verification description text |
|
|
385
|
+
| `toggleContainer` | Name fields toggle wrapper |
|
|
386
|
+
| `toggleLink` | "New user? Add your name" toggle button |
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
### MagicLinkVerify
|
|
391
|
+
|
|
392
|
+
Automatic Magic Link verification component. Reads token from URL params or accepts them as props.
|
|
393
|
+
|
|
394
|
+
#### Props (`MagicLinkVerifyProps`)
|
|
395
|
+
|
|
396
|
+
| Prop | Type | Default | Description |
|
|
397
|
+
|------|------|---------|-------------|
|
|
398
|
+
| `copy` | `MagicLinkVerifyCopy` | See below | Override user-facing texts |
|
|
399
|
+
| `styles` | `MagicLinkVerifyStyles` | See below | Override inline styles |
|
|
400
|
+
| `icons` | `MagicLinkVerifyIcons` | SVG icons | Override loading/success/error icons |
|
|
401
|
+
| `onSuccess` | `(data: any) => void` | โ | Called after successful verification |
|
|
402
|
+
| `onError` | `(error: string) => void` | โ | Called on verification failure |
|
|
403
|
+
| `onRetry` | `() => void` | โ | Called before retry attempt |
|
|
404
|
+
| `onBackToLogin` | `() => void` | โ | Navigate back to login |
|
|
405
|
+
| `className` | `string` | โ | CSS class for the root element |
|
|
406
|
+
| `token` | `string` | URL param | Magic link token (auto-extracted from `?token=`) |
|
|
407
|
+
| `email` | `string` | URL param | User email (auto-extracted from `?email=`) |
|
|
408
|
+
| `appId` | `string` | URL param | App ID (auto-extracted from `?appId=`) |
|
|
409
|
+
| `tenantSlug` | `string` | URL param | Tenant slug (auto-extracted from `?tenantSlug=`) |
|
|
410
|
+
| `autoRedirectDelay` | `number` | `3000` | Milliseconds before auto-redirect (0 to disable) |
|
|
411
|
+
|
|
412
|
+
#### Copy (`MagicLinkVerifyCopy`)
|
|
413
|
+
|
|
414
|
+
| Key | Default |
|
|
415
|
+
|-----|---------|
|
|
416
|
+
| `title` | `'Verifying Magic Link'` |
|
|
417
|
+
| `verifyingMessage` | `'Please wait while we verify your magic link...'` |
|
|
418
|
+
| `successMessage` | `'Magic link verified successfully! You are now logged in.'` |
|
|
419
|
+
| `errorMessage` | `'Failed to verify magic link. The link may be expired or invalid.'` |
|
|
420
|
+
| `redirectingMessage` | `'Redirecting you to the dashboard...'` |
|
|
421
|
+
| `retryButton` | `'Try Again'` |
|
|
422
|
+
| `backToLoginButton` | `'Back to Login'` |
|
|
423
|
+
| `missingParamsError` | `'Missing required parameters: token or email'` |
|
|
424
|
+
|
|
425
|
+
#### Styles (`MagicLinkVerifyStyles`)
|
|
426
|
+
|
|
427
|
+
| Key | Targets |
|
|
428
|
+
|-----|---------|
|
|
429
|
+
| `container` | Root wrapper |
|
|
430
|
+
| `card` | Inner card (kept for compatibility) |
|
|
431
|
+
| `title` | `<h1>` heading |
|
|
432
|
+
| `message` | Verifying/redirecting message |
|
|
433
|
+
| `successMessage` | Success state message |
|
|
434
|
+
| `errorMessage` | Error state message |
|
|
435
|
+
| `spinner` | Loading spinner |
|
|
436
|
+
| `buttonContainer` | Error buttons wrapper |
|
|
437
|
+
| `retryButton` | "Try Again" button |
|
|
438
|
+
| `retryButtonHover` | Hover state for retry button |
|
|
439
|
+
| `backButton` | "Back to Login" button |
|
|
440
|
+
| `backButtonHover` | Hover state for back button |
|
|
441
|
+
|
|
442
|
+
#### Icons (`MagicLinkVerifyIcons`)
|
|
443
|
+
|
|
444
|
+
| Key | Default | Description |
|
|
445
|
+
|-----|---------|-------------|
|
|
446
|
+
| `loading` | Animated spinner | Shown during verification |
|
|
447
|
+
| `success` | Green checkmark SVG | Shown on success |
|
|
448
|
+
| `error` | Red X circle SVG | Shown on error |
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
452
|
+
### PasswordRecoveryForm
|
|
453
|
+
|
|
454
|
+
Password reset flow with two modes: request (send email) and reset (set new password).
|
|
455
|
+
|
|
456
|
+
#### Props (`PasswordRecoveryFormProps`)
|
|
457
|
+
|
|
458
|
+
| Prop | Type | Default | Description |
|
|
459
|
+
|------|------|---------|-------------|
|
|
460
|
+
| `copy` | `PasswordRecoveryFormCopy` | See below | Override user-facing texts |
|
|
461
|
+
| `styles` | `PasswordRecoveryFormStyles` | See below | Override inline styles |
|
|
462
|
+
| `mode` | `'request' \| 'reset'` | `'request'` | Current form mode |
|
|
463
|
+
| `token` | `string` | โ | Pre-fill reset token |
|
|
464
|
+
| `onSuccess` | `(data?: any) => void` | โ | Called after success |
|
|
465
|
+
| `onError` | `(error: string) => void` | โ | Called on failure |
|
|
466
|
+
| `onBackToLogin` | `() => void` | โ | Navigate back to login |
|
|
467
|
+
| `onModeChange` | `(mode: 'request' \| 'reset') => void` | โ | Show mode switch links |
|
|
468
|
+
| `className` | `string` | โ | CSS class for the root element |
|
|
469
|
+
|
|
470
|
+
#### Copy (`PasswordRecoveryFormCopy`)
|
|
471
|
+
|
|
472
|
+
| Key | Default |
|
|
473
|
+
|-----|---------|
|
|
474
|
+
| `title` | `'Reset Password'` |
|
|
475
|
+
| `subtitle` | `"Enter your email address and we'll send you a link..."` |
|
|
476
|
+
| `emailLabel` | `'Email'` |
|
|
477
|
+
| `emailPlaceholder` | `'Enter your email'` |
|
|
478
|
+
| `submitButton` | `'Send Reset Link'` |
|
|
479
|
+
| `loadingText` | `'Sending...'` |
|
|
480
|
+
| `successMessage` | `'Password reset link sent! Check your email.'` |
|
|
481
|
+
| `errorMessage` | `'Failed to send reset link'` |
|
|
482
|
+
| `backToLoginLink` | `'Back to Sign In'` |
|
|
483
|
+
| `resetTitle` | `'Set New Password'` |
|
|
484
|
+
| `resetSubtitle` | `'Enter your reset token and new password.'` |
|
|
485
|
+
| `tokenLabel` | `'Reset Token'` |
|
|
486
|
+
| `tokenPlaceholder` | `'Enter reset token from email'` |
|
|
487
|
+
| `newPasswordLabel` | `'New Password'` |
|
|
488
|
+
| `newPasswordPlaceholder` | `'Enter new password'` |
|
|
489
|
+
| `confirmPasswordLabel` | `'Confirm Password'` |
|
|
490
|
+
| `confirmPasswordPlaceholder` | `'Confirm new password'` |
|
|
491
|
+
| `resetSubmitButton` | `'Reset Password'` |
|
|
492
|
+
| `resetLoadingText` | `'Resetting...'` |
|
|
493
|
+
| `resetSuccessMessage` | `'Password reset successfully!'` |
|
|
494
|
+
| `passwordMismatchError` | `'Passwords do not match'` |
|
|
495
|
+
| `requestNewLinkLink` | `'Request New Link'` |
|
|
496
|
+
| `haveTokenLink` | `'I have a token'` |
|
|
497
|
+
| `tenantNotFoundError` | `'Tenant not found'` |
|
|
498
|
+
| `dividerBullet` | `'โข'` |
|
|
499
|
+
|
|
500
|
+
#### Styles (`PasswordRecoveryFormStyles`)
|
|
501
|
+
|
|
502
|
+
| Key | Targets |
|
|
503
|
+
|-----|---------|
|
|
504
|
+
| `container` | Root wrapper |
|
|
505
|
+
| `title` | `<h2>` heading |
|
|
506
|
+
| `subtitle` | Subtitle paragraph |
|
|
507
|
+
| `form` | `<form>` element |
|
|
508
|
+
| `fieldGroup` | Each label+input group |
|
|
509
|
+
| `label` | `<label>` elements |
|
|
510
|
+
| `input` | `<input>` elements |
|
|
511
|
+
| `inputError` | Input in error state |
|
|
512
|
+
| `button` | Submit button |
|
|
513
|
+
| `buttonDisabled` | Disabled state (merged on top of `button`) |
|
|
514
|
+
| `buttonLoading` | Loading state (merged on top of `button`) |
|
|
515
|
+
| `errorText` | Error message text |
|
|
516
|
+
| `successText` | Success message text |
|
|
517
|
+
| `linkContainer` | Links section wrapper |
|
|
518
|
+
| `link` | `<a>` link elements |
|
|
519
|
+
| `modeSwitchDivider` | Bullet divider between mode links |
|
|
520
|
+
|
|
521
|
+
---
|
|
522
|
+
|
|
523
|
+
### TenantSelector
|
|
524
|
+
|
|
525
|
+
Dropdown component for switching between tenants. Integrates with `AuthProvider` context automatically.
|
|
526
|
+
|
|
527
|
+
#### Props (`TenantSelectorProps`)
|
|
528
|
+
|
|
529
|
+
| Prop | Type | Default | Description |
|
|
530
|
+
|------|------|---------|-------------|
|
|
531
|
+
| `tenants` | `UserTenantMembership[]` | From context | Override tenant list |
|
|
532
|
+
| `currentTenantId` | `string \| null` | From context | Override current tenant |
|
|
533
|
+
| `onSelect` | `(tenantId: string) => void` | `auth.switchToTenant` | Custom selection handler |
|
|
534
|
+
| `styles` | `TenantSelectorStyles` | See below | Override inline styles |
|
|
535
|
+
| `className` | `string` | โ | CSS class for root element |
|
|
536
|
+
| `dropdownClassName` | `string` | โ | CSS class for dropdown |
|
|
537
|
+
| `itemClassName` | `string` | โ | CSS class for each item |
|
|
538
|
+
| `renderItem` | `(tenant, isSelected) => ReactNode` | Default renderer | Custom item renderer |
|
|
539
|
+
| `placeholder` | `string` | `'Select tenant'` | Placeholder when no tenant selected |
|
|
540
|
+
| `disabled` | `boolean` | `false` | Disable the selector |
|
|
541
|
+
| `showCurrentTenant` | `boolean` | `true` | Show name when only 1 tenant |
|
|
542
|
+
|
|
543
|
+
#### Styles (`TenantSelectorStyles`)
|
|
544
|
+
|
|
545
|
+
| Key | Targets |
|
|
546
|
+
|-----|---------|
|
|
547
|
+
| `wrapper` | Root `<div>` (position: relative) |
|
|
548
|
+
| `button` | Trigger button |
|
|
549
|
+
| `buttonDisabled` | Disabled button state (merged on top of `button`) |
|
|
550
|
+
| `dropdown` | Dropdown menu container |
|
|
551
|
+
| `item` | Each tenant item |
|
|
552
|
+
| `itemSelected` | Selected tenant item (merged on top of `item`) |
|
|
553
|
+
| `itemHover` | Hover state for items |
|
|
554
|
+
| `itemRole` | Role badge next to tenant name |
|
|
555
|
+
| `arrow` | Arrow indicator (โฒ/โผ) |
|
|
556
|
+
|
|
557
|
+
---
|
|
558
|
+
|
|
559
|
+
### Protected
|
|
560
|
+
|
|
561
|
+
Conditionally renders content based on permissions and/or roles.
|
|
562
|
+
|
|
563
|
+
```tsx
|
|
564
|
+
<Protected
|
|
565
|
+
requiredPermissions={['users:read', 'users:write']}
|
|
566
|
+
requireAll={true}
|
|
567
|
+
fallback={<div>Access denied</div>}
|
|
568
|
+
>
|
|
569
|
+
<AdminPanel />
|
|
570
|
+
</Protected>
|
|
220
571
|
```
|
|
221
572
|
|
|
222
|
-
|
|
573
|
+
| Prop | Type | Default | Description |
|
|
574
|
+
|------|------|---------|-------------|
|
|
575
|
+
| `requiredPermissions` | `string[]` | โ | Required permissions |
|
|
576
|
+
| `requiredRole` | `string` | โ | Required user role |
|
|
577
|
+
| `requireAll` | `boolean` | `true` | All permissions required? |
|
|
578
|
+
| `fallback` | `ReactNode` | `null` | Shown when access denied |
|
|
579
|
+
| `onUnauthorized` | `() => void` | โ | Callback on denial |
|
|
580
|
+
|
|
581
|
+
---
|
|
582
|
+
|
|
583
|
+
## ๐จ Customization Examples
|
|
584
|
+
|
|
585
|
+
### Internationalization (i18n)
|
|
223
586
|
|
|
224
|
-
|
|
587
|
+
Override all user-facing text for your locale:
|
|
225
588
|
|
|
226
589
|
```tsx
|
|
227
590
|
<LoginForm
|
|
228
591
|
copy={{
|
|
229
|
-
title: '
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
592
|
+
title: 'Iniciar Sesion',
|
|
593
|
+
usernameLabel: 'Correo o Telefono',
|
|
594
|
+
usernamePlaceholder: 'Ingrese su correo o telefono',
|
|
595
|
+
passwordLabel: 'Contraseรฑa',
|
|
596
|
+
passwordPlaceholder: 'Ingrese su contraseรฑa',
|
|
597
|
+
submitButton: 'Entrar',
|
|
598
|
+
loadingText: 'Ingresando...',
|
|
599
|
+
errorMessage: 'Credenciales invalidas',
|
|
600
|
+
forgotPasswordLink: 'ยฟOlvidaste tu contraseรฑa?',
|
|
601
|
+
signupText: 'ยฟNo tienes cuenta?',
|
|
602
|
+
signupLink: 'Registrate aqui',
|
|
603
|
+
showPasswordAriaLabel: 'Mostrar contraseรฑa',
|
|
604
|
+
hidePasswordAriaLabel: 'Ocultar contraseรฑa',
|
|
236
605
|
}}
|
|
606
|
+
/>
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
### Brand Theming
|
|
610
|
+
|
|
611
|
+
Apply your brand colors and spacing:
|
|
612
|
+
|
|
613
|
+
```tsx
|
|
614
|
+
const brandStyles = {
|
|
615
|
+
container: {
|
|
616
|
+
maxWidth: '480px',
|
|
617
|
+
backgroundColor: '#1a1a2e',
|
|
618
|
+
borderRadius: '16px',
|
|
619
|
+
padding: '3rem',
|
|
620
|
+
},
|
|
621
|
+
title: { color: '#e94560', fontSize: '2rem' },
|
|
622
|
+
input: {
|
|
623
|
+
backgroundColor: '#16213e',
|
|
624
|
+
color: '#ffffff',
|
|
625
|
+
border: '1px solid #0f3460',
|
|
626
|
+
borderRadius: '8px',
|
|
627
|
+
},
|
|
628
|
+
button: {
|
|
629
|
+
backgroundColor: '#e94560',
|
|
630
|
+
borderRadius: '8px',
|
|
631
|
+
fontWeight: '600',
|
|
632
|
+
},
|
|
633
|
+
link: { color: '#e94560' },
|
|
634
|
+
};
|
|
635
|
+
|
|
636
|
+
<LoginForm styles={brandStyles} />
|
|
637
|
+
<SignupForm styles={brandStyles} />
|
|
638
|
+
<MagicLinkForm styles={brandStyles} />
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
### Custom Icons
|
|
642
|
+
|
|
643
|
+
```tsx
|
|
644
|
+
import { Eye, EyeOff } from 'lucide-react';
|
|
645
|
+
|
|
646
|
+
<LoginForm
|
|
237
647
|
icons={{
|
|
238
|
-
showPassword: <
|
|
239
|
-
hidePassword: <
|
|
648
|
+
showPassword: <Eye size={16} />,
|
|
649
|
+
hidePassword: <EyeOff size={16} />,
|
|
240
650
|
}}
|
|
241
651
|
/>
|
|
242
652
|
```
|
|
243
653
|
|
|
654
|
+
---
|
|
655
|
+
|
|
244
656
|
## ๐๏ธ Architecture
|
|
245
657
|
|
|
246
658
|
### Core Providers
|
|
247
659
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
660
|
+
| Provider | Purpose |
|
|
661
|
+
|----------|---------|
|
|
662
|
+
| **AppProvider** | Application configuration (baseUrl, appId) |
|
|
663
|
+
| **TenantProvider** | Multi-tenant detection and management |
|
|
664
|
+
| **AuthProvider** | Authentication, session, and user data |
|
|
665
|
+
| **FeatureFlagProvider** | Feature flag management |
|
|
666
|
+
| **SubscriptionProvider** | Billing and subscription handling |
|
|
667
|
+
| **RoutingProvider** | Zone-based routing (RFC-005) |
|
|
253
668
|
|
|
254
669
|
### Permission System
|
|
255
670
|
|
|
256
|
-
The library uses a resource
|
|
671
|
+
The library uses a `resource:action` permission format:
|
|
257
672
|
|
|
258
673
|
```
|
|
259
|
-
|
|
674
|
+
users:read - Read user data
|
|
675
|
+
products:write - Create/update products
|
|
676
|
+
admin:* - All admin permissions
|
|
677
|
+
reports:read - View reports
|
|
260
678
|
```
|
|
261
679
|
|
|
262
|
-
Examples:
|
|
263
|
-
- `users:read` - Read user data
|
|
264
|
-
- `products:write` - Create/update products
|
|
265
|
-
- `admin:*` - All admin permissions
|
|
266
|
-
- `reports:read` - View reports
|
|
267
|
-
|
|
268
680
|
## ๐ Documentation
|
|
269
681
|
|
|
270
682
|
- [๐ Implementation Guide](./docs/implementation.md)
|
|
271
683
|
- [๐ง Advanced Usage](./docs/advanced-usage.md)
|
|
272
|
-
- [๐ค Contributing](./docs/contributing.md)
|
|
273
684
|
- [๐ API Reference](./docs/api-reference.md)
|
|
274
685
|
- [๐ฏ Examples](./docs/examples.md)
|
|
686
|
+
- [โจ Magic Link Guide](./MAGIC_LINK_USAGE.md)
|
|
687
|
+
- [๐ฃ๏ธ Zone Routing](./docs/ZONE_ROUTING.md)
|
|
688
|
+
- [๐ค Contributing](./docs/contributing.md)
|
|
275
689
|
|
|
276
690
|
## ๐ฎ Demo Application
|
|
277
691
|
|
|
278
|
-
A complete demo application is included in the `example/` directory
|
|
692
|
+
A complete demo application is included in the `example/` directory:
|
|
279
693
|
|
|
280
694
|
```bash
|
|
281
695
|
cd example
|
|
@@ -299,7 +713,7 @@ The demo showcases:
|
|
|
299
713
|
### Prerequisites
|
|
300
714
|
|
|
301
715
|
- Node.js 18+
|
|
302
|
-
- yarn
|
|
716
|
+
- yarn
|
|
303
717
|
|
|
304
718
|
### Setup
|
|
305
719
|
|
|
@@ -317,26 +731,26 @@ yarn build
|
|
|
317
731
|
# Run tests
|
|
318
732
|
yarn test
|
|
319
733
|
|
|
320
|
-
# Run CI pipeline
|
|
734
|
+
# Run full CI pipeline (type-check + test + build)
|
|
321
735
|
yarn ci
|
|
322
|
-
|
|
323
|
-
# Start example app
|
|
324
|
-
cd example && yarn start
|
|
325
736
|
```
|
|
326
737
|
|
|
327
738
|
### Project Structure
|
|
328
739
|
|
|
329
740
|
```
|
|
330
741
|
react-identity-access/
|
|
331
|
-
โโโ src/
|
|
332
|
-
โ โโโ components/ # React components (forms, guards,
|
|
333
|
-
โ โโโ providers/ # Context providers (
|
|
742
|
+
โโโ src/
|
|
743
|
+
โ โโโ components/ # React components (forms, guards, selectors)
|
|
744
|
+
โ โโโ providers/ # Context providers (App, Tenant, Auth, etc.)
|
|
334
745
|
โ โโโ services/ # API services and HTTP client
|
|
335
|
-
โ โโโ
|
|
336
|
-
โ
|
|
746
|
+
โ โโโ hooks/ # Custom React hooks
|
|
747
|
+
โ โโโ types/ # TypeScript type definitions
|
|
748
|
+
โ โโโ utils/ # Utility functions
|
|
749
|
+
โ โโโ errors/ # Custom error classes
|
|
750
|
+
โ โโโ index.ts # Public API exports
|
|
337
751
|
โโโ example/ # Demo application
|
|
338
752
|
โโโ docs/ # Documentation
|
|
339
|
-
โโโ dist/ # Built library
|
|
753
|
+
โโโ dist/ # Built library (ES + CJS)
|
|
340
754
|
โโโ package.json
|
|
341
755
|
```
|
|
342
756
|
|
|
@@ -356,24 +770,20 @@ REACT_APP_TENANT_MODE=subdomain
|
|
|
356
770
|
// AppProvider Config
|
|
357
771
|
interface AppConfig {
|
|
358
772
|
baseUrl: string; // API base URL
|
|
359
|
-
appId: string;
|
|
360
|
-
apiTimeout?: number; // Request timeout (default: 30000)
|
|
361
|
-
retryAttempts?: number; // Retry attempts (default: 3)
|
|
773
|
+
appId: string; // Application identifier
|
|
362
774
|
}
|
|
363
775
|
|
|
364
776
|
// TenantProvider Config
|
|
365
777
|
interface TenantConfig {
|
|
366
|
-
tenantMode: 'subdomain' | 'selector' | 'fixed';
|
|
367
|
-
selectorParam?: string;
|
|
368
|
-
fixedTenantSlug?: string;
|
|
369
|
-
initialTenant?: string;
|
|
778
|
+
tenantMode: 'subdomain' | 'selector' | 'fixed' | 'optional';
|
|
779
|
+
selectorParam?: string; // For 'selector' mode
|
|
780
|
+
fixedTenantSlug?: string; // For 'fixed' mode
|
|
781
|
+
initialTenant?: string; // Initial tenant value
|
|
370
782
|
}
|
|
371
783
|
```
|
|
372
784
|
|
|
373
785
|
## ๐งช Testing
|
|
374
786
|
|
|
375
|
-
The library includes comprehensive tests:
|
|
376
|
-
|
|
377
787
|
```bash
|
|
378
788
|
# Run all tests
|
|
379
789
|
yarn test
|
|
@@ -394,11 +804,11 @@ yarn test:coverage
|
|
|
394
804
|
|
|
395
805
|
## ๐ Security
|
|
396
806
|
|
|
397
|
-
- **JWT tokens** with automatic refresh
|
|
398
|
-
- **Secure storage**
|
|
399
|
-
- **
|
|
807
|
+
- **JWT tokens** with automatic refresh and proactive renewal
|
|
808
|
+
- **Secure token storage** with configurable backends
|
|
809
|
+
- **Session generation tracking** to prevent stale token usage
|
|
400
810
|
- **Permission validation** on both client and server
|
|
401
|
-
- **
|
|
811
|
+
- **Console output suppressed** in production and test environments
|
|
402
812
|
|
|
403
813
|
## ๐ Browser Support
|
|
404
814
|
|
|
@@ -424,14 +834,14 @@ We welcome contributions! Please see our [Contributing Guide](./docs/contributin
|
|
|
424
834
|
|
|
425
835
|
## ๐ฏ Roadmap
|
|
426
836
|
|
|
427
|
-
- [x] **Magic Link Authentication** - Passwordless authentication via email
|
|
428
|
-
- [x] **Email/Phone Login Support** - Flexible authentication methods
|
|
429
|
-
- [x] **Pre-built Form Components** - Ready-to-use authentication forms
|
|
430
|
-
- [x] **Multi-tenant Architecture** - Separate App and Tenant providers
|
|
837
|
+
- [x] **Magic Link Authentication** - Passwordless authentication via email
|
|
838
|
+
- [x] **Email/Phone Login Support** - Flexible authentication methods
|
|
839
|
+
- [x] **Pre-built Form Components** - Ready-to-use, fully customizable authentication forms
|
|
840
|
+
- [x] **Multi-tenant Architecture** - Separate App and Tenant providers
|
|
841
|
+
- [x] **Zone-based Routing** - Declarative route access control (RFC-005)
|
|
842
|
+
- [x] **Customizable Copy & Styles** - All components support i18n and brand theming
|
|
431
843
|
- [ ] **OAuth 2.0 / OpenID Connect** - Social login integration
|
|
432
844
|
- [ ] **Multi-factor Authentication** - SMS/TOTP support
|
|
433
|
-
- [ ] **Advanced Audit Logging** - Comprehensive security tracking
|
|
434
|
-
- [ ] **GraphQL Integration** - GraphQL API support
|
|
435
845
|
- [ ] **React Native Support** - Mobile app integration
|
|
436
846
|
- [ ] **SSR/Next.js Optimization** - Server-side rendering support
|
|
437
847
|
- [ ] **Biometric Authentication** - WebAuthn/FIDO2 support
|