@ttoss/react-auth-strapi 0.4.0 → 0.4.2
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 +127 -0
- package/dist/esm/index.js +53 -3
- package/dist/index.d.cts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +53 -3
- package/package.json +10 -6
package/README.md
CHANGED
|
@@ -123,6 +123,35 @@ The component automatically handles:
|
|
|
123
123
|
- **Email confirmation**: Manages email verification process
|
|
124
124
|
- **Error notifications**: Shows user-friendly error messages
|
|
125
125
|
|
|
126
|
+
#### Props
|
|
127
|
+
|
|
128
|
+
```tsx
|
|
129
|
+
<Auth
|
|
130
|
+
initialScreen={{ value: 'signUp' }} // Optional: start on a specific screen
|
|
131
|
+
logo={<MyLogo />} // Optional: custom logo
|
|
132
|
+
layout={{
|
|
133
|
+
// Optional: layout configuration
|
|
134
|
+
fullScreen: true,
|
|
135
|
+
sideContent: <BrandingContent />,
|
|
136
|
+
sideContentPosition: 'left',
|
|
137
|
+
}}
|
|
138
|
+
/>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**initialScreen**: Set the initial authentication screen to display. Useful for:
|
|
142
|
+
|
|
143
|
+
- Deep linking to specific auth flows (e.g., `/auth/signup` → `{ value: 'signUp' }`)
|
|
144
|
+
- Redirecting users to password reset from email links
|
|
145
|
+
- Pre-selecting sign up vs sign in based on user context
|
|
146
|
+
|
|
147
|
+
Available screens:
|
|
148
|
+
|
|
149
|
+
- `{ value: 'signIn' }` - Sign in screen (default)
|
|
150
|
+
- `{ value: 'signUp' }` - Sign up screen
|
|
151
|
+
- `{ value: 'forgotPassword' }` - Forgot password screen
|
|
152
|
+
- `{ value: 'confirmSignUpCheckEmail' }` - Email confirmation reminder
|
|
153
|
+
- `{ value: 'confirmResetPassword', context: { email: string } }` - Password reset screen
|
|
154
|
+
|
|
126
155
|
### useAuth Hook
|
|
127
156
|
|
|
128
157
|
Enhanced version of the core useAuth hook with Strapi-specific context:
|
|
@@ -162,6 +191,104 @@ sequenceDiagram
|
|
|
162
191
|
A->>A: Restore authentication state
|
|
163
192
|
```
|
|
164
193
|
|
|
194
|
+
## Password Reset Flow with Email Links
|
|
195
|
+
|
|
196
|
+
### Email Template Configuration
|
|
197
|
+
|
|
198
|
+
When configuring the password reset email template in Strapi, use this URL format to enable deep linking:
|
|
199
|
+
|
|
200
|
+
```html
|
|
201
|
+
<p>We received a request to reset your password.</p>
|
|
202
|
+
<p>If it was you, click the link below to create a new password:</p>
|
|
203
|
+
<p><%= URL %>/auth?initialScreen=confirmResetPassword&code=<%= TOKEN %></p>
|
|
204
|
+
<p>If it wasn't you, ignore this email. Your account will remain secure.</p>
|
|
205
|
+
<p>Thank you,</p>
|
|
206
|
+
<p>Team</p>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### React Router Integration
|
|
210
|
+
|
|
211
|
+
To handle password reset links from email, configure your route to parse URL parameters and pass them to the Auth component:
|
|
212
|
+
|
|
213
|
+
```tsx
|
|
214
|
+
import { useSearchParams } from 'react-router-dom';
|
|
215
|
+
import { Auth, type AuthScreen } from '@ttoss/react-auth-strapi';
|
|
216
|
+
|
|
217
|
+
function AuthPage() {
|
|
218
|
+
const [searchParams] = useSearchParams();
|
|
219
|
+
|
|
220
|
+
// Parse URL parameters from email link
|
|
221
|
+
const initialScreenParam = searchParams.get('initialScreen');
|
|
222
|
+
const code = searchParams.get('code');
|
|
223
|
+
|
|
224
|
+
// Build the initialScreen object
|
|
225
|
+
let initialScreen: AuthScreen | undefined;
|
|
226
|
+
|
|
227
|
+
if (initialScreenParam === 'confirmResetPassword' && code) {
|
|
228
|
+
initialScreen = {
|
|
229
|
+
value: 'confirmResetPassword',
|
|
230
|
+
context: { code },
|
|
231
|
+
};
|
|
232
|
+
} else if (initialScreenParam) {
|
|
233
|
+
// Handle other screen types without context
|
|
234
|
+
initialScreen = { value: initialScreenParam };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return <Auth initialScreen={initialScreen} />;
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Route Configuration
|
|
242
|
+
|
|
243
|
+
```tsx
|
|
244
|
+
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
|
|
245
|
+
import { AuthProvider } from '@ttoss/react-auth-strapi';
|
|
246
|
+
import { NotificationProvider } from '@ttoss/react-notifications';
|
|
247
|
+
|
|
248
|
+
function App() {
|
|
249
|
+
return (
|
|
250
|
+
<NotificationProvider>
|
|
251
|
+
<AuthProvider apiUrl="https://your-strapi-api.com/api">
|
|
252
|
+
<BrowserRouter>
|
|
253
|
+
<Routes>
|
|
254
|
+
<Route path="/auth" element={<AuthPage />} />
|
|
255
|
+
<Route path="/" element={<HomePage />} />
|
|
256
|
+
</Routes>
|
|
257
|
+
</BrowserRouter>
|
|
258
|
+
</AuthProvider>
|
|
259
|
+
</NotificationProvider>
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Complete Flow
|
|
265
|
+
|
|
266
|
+
```mermaid
|
|
267
|
+
sequenceDiagram
|
|
268
|
+
participant U as User
|
|
269
|
+
participant E as Email
|
|
270
|
+
participant R as React Router
|
|
271
|
+
participant A as Auth Component
|
|
272
|
+
participant S as Strapi API
|
|
273
|
+
|
|
274
|
+
U->>A: Click "Forgot Password"
|
|
275
|
+
A->>S: POST /auth/forgot-password
|
|
276
|
+
S->>E: Send reset email with link
|
|
277
|
+
E-->>U: Email: /auth?initialScreen=confirmResetPassword&code=ABC123
|
|
278
|
+
|
|
279
|
+
Note over U,R: User clicks email link
|
|
280
|
+
U->>R: Navigate to /auth?initialScreen=...&code=...
|
|
281
|
+
R->>R: Parse searchParams
|
|
282
|
+
R->>A: <Auth initialScreen={{ value: 'confirmResetPassword', context: { code: 'ABC123' } }} />
|
|
283
|
+
A-->>U: Display Reset Password form with pre-filled code
|
|
284
|
+
|
|
285
|
+
U->>A: Enter new password
|
|
286
|
+
A->>S: POST /auth/reset-password { code, password }
|
|
287
|
+
S-->>A: Success
|
|
288
|
+
A->>A: setScreen({ value: 'signIn' })
|
|
289
|
+
A-->>U: Display Sign In screen with success notification
|
|
290
|
+
```
|
|
291
|
+
|
|
165
292
|
## Error Handling
|
|
166
293
|
|
|
167
294
|
The package integrates with `@ttoss/react-notifications` to display authentication errors:
|
package/dist/esm/index.js
CHANGED
|
@@ -135,7 +135,7 @@ var Auth = /* @__PURE__ */__name(props => {
|
|
|
135
135
|
const {
|
|
136
136
|
screen,
|
|
137
137
|
setScreen
|
|
138
|
-
} = useAuthScreen();
|
|
138
|
+
} = useAuthScreen(props.initialScreen);
|
|
139
139
|
const {
|
|
140
140
|
addNotification
|
|
141
141
|
} = useNotifications();
|
|
@@ -267,6 +267,12 @@ var Auth = /* @__PURE__ */__name(props => {
|
|
|
267
267
|
});
|
|
268
268
|
return;
|
|
269
269
|
}
|
|
270
|
+
setScreen({
|
|
271
|
+
value: "confirmResetPassword",
|
|
272
|
+
context: {
|
|
273
|
+
email
|
|
274
|
+
}
|
|
275
|
+
});
|
|
270
276
|
} catch {
|
|
271
277
|
addNotification({
|
|
272
278
|
title: "Network Error",
|
|
@@ -274,19 +280,63 @@ var Auth = /* @__PURE__ */__name(props => {
|
|
|
274
280
|
type: "error"
|
|
275
281
|
});
|
|
276
282
|
}
|
|
277
|
-
}, [addNotification, apiUrl]);
|
|
283
|
+
}, [addNotification, setScreen, apiUrl]);
|
|
284
|
+
const onForgotPasswordResetPassword = React2.useCallback(async ({
|
|
285
|
+
email: _email,
|
|
286
|
+
code,
|
|
287
|
+
newPassword
|
|
288
|
+
}) => {
|
|
289
|
+
try {
|
|
290
|
+
const response = await fetch(`${apiUrl}/auth/reset-password`, {
|
|
291
|
+
method: "POST",
|
|
292
|
+
headers: {
|
|
293
|
+
"Content-Type": "application/json"
|
|
294
|
+
},
|
|
295
|
+
body: JSON.stringify({
|
|
296
|
+
code,
|
|
297
|
+
password: newPassword,
|
|
298
|
+
passwordConfirmation: newPassword
|
|
299
|
+
})
|
|
300
|
+
});
|
|
301
|
+
const data = await response.json();
|
|
302
|
+
if (!response.ok) {
|
|
303
|
+
addNotification({
|
|
304
|
+
title: "Reset password failed",
|
|
305
|
+
message: data.error?.message || "An error occurred during password reset.",
|
|
306
|
+
type: "error"
|
|
307
|
+
});
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
addNotification({
|
|
311
|
+
title: "Password reset successful",
|
|
312
|
+
message: "You can now sign in with your new password.",
|
|
313
|
+
type: "success"
|
|
314
|
+
});
|
|
315
|
+
setScreen({
|
|
316
|
+
value: "signIn"
|
|
317
|
+
});
|
|
318
|
+
} catch {
|
|
319
|
+
addNotification({
|
|
320
|
+
title: "Network Error",
|
|
321
|
+
message: "Unable to connect to the server. Please check your connection.",
|
|
322
|
+
type: "error"
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}, [addNotification, setScreen, apiUrl]);
|
|
278
326
|
const onConfirmSignUpCheckEmail = React2.useCallback(async () => {
|
|
279
327
|
setScreen({
|
|
280
328
|
value: "signIn"
|
|
281
329
|
});
|
|
282
330
|
}, [setScreen]);
|
|
283
331
|
return /* @__PURE__ */React2.createElement(AuthCore, {
|
|
284
|
-
|
|
332
|
+
logo: props.logo,
|
|
333
|
+
layout: props.layout,
|
|
285
334
|
screen,
|
|
286
335
|
setScreen,
|
|
287
336
|
onSignIn,
|
|
288
337
|
onSignUp,
|
|
289
338
|
onForgotPassword,
|
|
339
|
+
onForgotPasswordResetPassword,
|
|
290
340
|
onConfirmSignUpCheckEmail
|
|
291
341
|
});
|
|
292
342
|
}, "Auth");
|
package/dist/index.d.cts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as _ttoss_react_auth_core from '@ttoss/react-auth-core';
|
|
3
|
-
import { AuthProps } from '@ttoss/react-auth-core';
|
|
3
|
+
import { AuthProps, AuthScreen } from '@ttoss/react-auth-core';
|
|
4
|
+
export { AuthScreen } from '@ttoss/react-auth-core';
|
|
4
5
|
import * as React from 'react';
|
|
5
6
|
|
|
6
|
-
declare const Auth: (props: Pick<AuthProps, "logo" | "layout">
|
|
7
|
+
declare const Auth: (props: Pick<AuthProps, "logo" | "layout"> & {
|
|
8
|
+
initialScreen?: AuthScreen;
|
|
9
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
7
10
|
|
|
8
11
|
declare const AuthProvider: (props: React.PropsWithChildren<{
|
|
9
12
|
apiUrl: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as _ttoss_react_auth_core from '@ttoss/react-auth-core';
|
|
3
|
-
import { AuthProps } from '@ttoss/react-auth-core';
|
|
3
|
+
import { AuthProps, AuthScreen } from '@ttoss/react-auth-core';
|
|
4
|
+
export { AuthScreen } from '@ttoss/react-auth-core';
|
|
4
5
|
import * as React from 'react';
|
|
5
6
|
|
|
6
|
-
declare const Auth: (props: Pick<AuthProps, "logo" | "layout">
|
|
7
|
+
declare const Auth: (props: Pick<AuthProps, "logo" | "layout"> & {
|
|
8
|
+
initialScreen?: AuthScreen;
|
|
9
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
7
10
|
|
|
8
11
|
declare const AuthProvider: (props: React.PropsWithChildren<{
|
|
9
12
|
apiUrl: string;
|
package/dist/index.js
CHANGED
|
@@ -179,7 +179,7 @@ var Auth = /* @__PURE__ */__name(props => {
|
|
|
179
179
|
const {
|
|
180
180
|
screen,
|
|
181
181
|
setScreen
|
|
182
|
-
} = (0, import_react_auth_core2.useAuthScreen)();
|
|
182
|
+
} = (0, import_react_auth_core2.useAuthScreen)(props.initialScreen);
|
|
183
183
|
const {
|
|
184
184
|
addNotification
|
|
185
185
|
} = (0, import_react_notifications.useNotifications)();
|
|
@@ -311,6 +311,12 @@ var Auth = /* @__PURE__ */__name(props => {
|
|
|
311
311
|
});
|
|
312
312
|
return;
|
|
313
313
|
}
|
|
314
|
+
setScreen({
|
|
315
|
+
value: "confirmResetPassword",
|
|
316
|
+
context: {
|
|
317
|
+
email
|
|
318
|
+
}
|
|
319
|
+
});
|
|
314
320
|
} catch {
|
|
315
321
|
addNotification({
|
|
316
322
|
title: "Network Error",
|
|
@@ -318,19 +324,63 @@ var Auth = /* @__PURE__ */__name(props => {
|
|
|
318
324
|
type: "error"
|
|
319
325
|
});
|
|
320
326
|
}
|
|
321
|
-
}, [addNotification, apiUrl]);
|
|
327
|
+
}, [addNotification, setScreen, apiUrl]);
|
|
328
|
+
const onForgotPasswordResetPassword = React2.useCallback(async ({
|
|
329
|
+
email: _email,
|
|
330
|
+
code,
|
|
331
|
+
newPassword
|
|
332
|
+
}) => {
|
|
333
|
+
try {
|
|
334
|
+
const response = await fetch(`${apiUrl}/auth/reset-password`, {
|
|
335
|
+
method: "POST",
|
|
336
|
+
headers: {
|
|
337
|
+
"Content-Type": "application/json"
|
|
338
|
+
},
|
|
339
|
+
body: JSON.stringify({
|
|
340
|
+
code,
|
|
341
|
+
password: newPassword,
|
|
342
|
+
passwordConfirmation: newPassword
|
|
343
|
+
})
|
|
344
|
+
});
|
|
345
|
+
const data = await response.json();
|
|
346
|
+
if (!response.ok) {
|
|
347
|
+
addNotification({
|
|
348
|
+
title: "Reset password failed",
|
|
349
|
+
message: data.error?.message || "An error occurred during password reset.",
|
|
350
|
+
type: "error"
|
|
351
|
+
});
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
addNotification({
|
|
355
|
+
title: "Password reset successful",
|
|
356
|
+
message: "You can now sign in with your new password.",
|
|
357
|
+
type: "success"
|
|
358
|
+
});
|
|
359
|
+
setScreen({
|
|
360
|
+
value: "signIn"
|
|
361
|
+
});
|
|
362
|
+
} catch {
|
|
363
|
+
addNotification({
|
|
364
|
+
title: "Network Error",
|
|
365
|
+
message: "Unable to connect to the server. Please check your connection.",
|
|
366
|
+
type: "error"
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
}, [addNotification, setScreen, apiUrl]);
|
|
322
370
|
const onConfirmSignUpCheckEmail = React2.useCallback(async () => {
|
|
323
371
|
setScreen({
|
|
324
372
|
value: "signIn"
|
|
325
373
|
});
|
|
326
374
|
}, [setScreen]);
|
|
327
375
|
return /* @__PURE__ */React2.createElement(import_react_auth_core2.Auth, {
|
|
328
|
-
|
|
376
|
+
logo: props.logo,
|
|
377
|
+
layout: props.layout,
|
|
329
378
|
screen,
|
|
330
379
|
setScreen,
|
|
331
380
|
onSignIn,
|
|
332
381
|
onSignUp,
|
|
333
382
|
onForgotPassword,
|
|
383
|
+
onForgotPasswordResetPassword,
|
|
334
384
|
onConfirmSignUpCheckEmail
|
|
335
385
|
});
|
|
336
386
|
}, "Auth");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttoss/react-auth-strapi",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "Authentication components and abstractions for React apps using Strapi.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ttoss",
|
|
@@ -26,19 +26,23 @@
|
|
|
26
26
|
"sideEffects": false,
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"react": ">=16.8.0",
|
|
29
|
-
"@ttoss/react-auth-core": "^0.4.0",
|
|
30
29
|
"@ttoss/react-i18n": "^2.1.0",
|
|
31
|
-
"@ttoss/react-
|
|
30
|
+
"@ttoss/react-auth-core": "^0.4.2",
|
|
31
|
+
"@ttoss/react-notifications": "^2.6.1"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
+
"@jest/globals": "^29.7.0",
|
|
34
35
|
"@types/react": "^19.2.14",
|
|
35
36
|
"jest": "^30.2.0",
|
|
36
37
|
"react": "^19.2.4",
|
|
37
38
|
"tsup": "^8.5.1",
|
|
39
|
+
"@ttoss/config": "^1.36.0",
|
|
38
40
|
"@ttoss/i18n-cli": "^0.7.39",
|
|
41
|
+
"@ttoss/react-auth-core": "^0.4.2",
|
|
39
42
|
"@ttoss/react-i18n": "^2.1.0",
|
|
40
|
-
"@ttoss/react-
|
|
41
|
-
"@ttoss/
|
|
43
|
+
"@ttoss/react-notifications": "^2.6.1",
|
|
44
|
+
"@ttoss/ui": "^6.7.0",
|
|
45
|
+
"@ttoss/test-utils": "^4.1.0"
|
|
42
46
|
},
|
|
43
47
|
"keywords": [
|
|
44
48
|
"React",
|
|
@@ -53,6 +57,6 @@
|
|
|
53
57
|
"scripts": {
|
|
54
58
|
"build": "tsup",
|
|
55
59
|
"i18n": "ttoss-i18n",
|
|
56
|
-
"test": "
|
|
60
|
+
"test": "jest --projects tests/unit"
|
|
57
61
|
}
|
|
58
62
|
}
|