@nocios/crudify-ui 1.3.0 → 1.3.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.
@@ -1,312 +0,0 @@
1
- # Migration Guide: Refresh Token Pattern Implementation
2
-
3
- ## Overview
4
-
5
- This guide helps you migrate from the standard JWT authentication to the new **Refresh Token Pattern** implementation in CRUDIFY v1.2.0+.
6
-
7
- The Refresh Token Pattern addresses security vulnerabilities by:
8
- - Using short-lived access tokens (15 minutes)
9
- - Implementing long-lived refresh tokens (7 days)
10
- - Automatic token refresh before expiration
11
- - Secure token storage with encryption
12
- - Session restoration on page reload
13
-
14
- ## Prerequisites
15
-
16
- Ensure you have the following versions installed:
17
- - `@nocios/crudify-core` v1.2.0+
18
- - `@nocios/crudify-ui` v1.2.0+
19
-
20
- ```bash
21
- npm update @nocios/crudify-core @nocios/crudify-ui
22
- ```
23
-
24
- ## Migration Steps
25
-
26
- ### 1. Update Your Backend (if applicable)
27
-
28
- If you're using the CRUDIFY backend, ensure you've deployed the refresh token endpoints. The new login response now includes:
29
-
30
- ```typescript
31
- {
32
- token: string, // Access token (short-lived)
33
- refreshToken: string, // Refresh token (long-lived)
34
- expiresIn: number, // Access token expiration
35
- refreshExpiresIn: number // Refresh token expiration
36
- }
37
- ```
38
-
39
- ### 2. Replace SessionProvider Implementation
40
-
41
- **BEFORE (Old implementation):**
42
- ```tsx
43
- import { CrudifyDataProvider } from '@nocios/crudify-ui';
44
-
45
- function App() {
46
- return (
47
- <CrudifyDataProvider>
48
- <YourApp />
49
- </CrudifyDataProvider>
50
- );
51
- }
52
- ```
53
-
54
- **AFTER (New Refresh Token Pattern):**
55
- ```tsx
56
- import { SessionProvider } from '@nocios/crudify-ui';
57
-
58
- function App() {
59
- return (
60
- <SessionProvider
61
- options={{
62
- autoRestore: true, // Restore session on page reload
63
- enableLogging: true, // Enable debug logs
64
- onSessionExpired: () => { // Handle session expiration
65
- console.log('Session expired');
66
- // Redirect to login or show modal
67
- },
68
- onSessionRestored: (tokens) => {
69
- console.log('Session restored:', tokens);
70
- }
71
- }}
72
- >
73
- <YourApp />
74
- </SessionProvider>
75
- );
76
- }
77
- ```
78
-
79
- ### 3. Update Authentication Logic
80
-
81
- **BEFORE (Manual login handling):**
82
- ```tsx
83
- import { useCrudifyLogin } from '@nocios/crudify-ui';
84
-
85
- function LoginForm() {
86
- const { login, isLoading } = useCrudifyLogin();
87
-
88
- const handleLogin = async () => {
89
- const result = await login(email, password);
90
- // Manual token handling
91
- };
92
- }
93
- ```
94
-
95
- **AFTER (Automatic session management):**
96
- ```tsx
97
- import { useSessionContext } from '@nocios/crudify-ui';
98
-
99
- function LoginForm() {
100
- const { login, isLoading, isAuthenticated, logout } = useSessionContext();
101
-
102
- const handleLogin = async () => {
103
- const result = await login(email, password);
104
- // Session is managed automatically
105
- if (result.success) {
106
- // User is now authenticated
107
- }
108
- };
109
- }
110
- ```
111
-
112
- ### 4. Replace Authentication Checks
113
-
114
- **BEFORE (Manual token checking):**
115
- ```tsx
116
- import { getCurrentUserEmail, isTokenExpired } from '@nocios/crudify-ui';
117
-
118
- function ProtectedComponent() {
119
- const userEmail = getCurrentUserEmail();
120
- const tokenExpired = isTokenExpired();
121
-
122
- if (!userEmail || tokenExpired) {
123
- return <LoginRequired />;
124
- }
125
-
126
- return <ProtectedContent />;
127
- }
128
- ```
129
-
130
- **AFTER (Using ProtectedRoute):**
131
- ```tsx
132
- import { ProtectedRoute } from '@nocios/crudify-ui';
133
-
134
- function ProtectedComponent() {
135
- return (
136
- <ProtectedRoute fallback={<LoginRequired />}>
137
- <ProtectedContent />
138
- </ProtectedRoute>
139
- );
140
- }
141
- ```
142
-
143
- ### 5. Update API Calls
144
-
145
- The good news is that your existing CRUDIFY API calls **don't need to change**! The automatic refresh mechanism is built into the core library:
146
-
147
- ```tsx
148
- import { crudify } from '@nocios/crudify-ui';
149
-
150
- // This automatically handles token refresh if needed
151
- const result = await crudify.getPermissions();
152
- ```
153
-
154
- ## New Features Available
155
-
156
- ### 1. Session Status Component
157
-
158
- Display authentication status anywhere in your app:
159
-
160
- ```tsx
161
- import { SessionStatus } from '@nocios/crudify-ui';
162
-
163
- function AppHeader() {
164
- return (
165
- <AppBar>
166
- <Toolbar>
167
- <Typography variant="h6">My App</Typography>
168
- <SessionStatus /> {/* Shows auth status */}
169
- </Toolbar>
170
- </AppBar>
171
- );
172
- }
173
- ```
174
-
175
- ### 2. Login Component (Optional)
176
-
177
- Ready-to-use login component with Material-UI:
178
-
179
- ```tsx
180
- import { LoginComponent } from '@nocios/crudify-ui';
181
-
182
- function LoginPage() {
183
- return <LoginComponent />;
184
- }
185
- ```
186
-
187
- ### 3. Session Debug Info
188
-
189
- For development, show detailed session information:
190
-
191
- ```tsx
192
- import { SessionDebugInfo } from '@nocios/crudify-ui';
193
-
194
- function App() {
195
- return (
196
- <div>
197
- <YourApp />
198
- {process.env.NODE_ENV === 'development' && (
199
- <SessionDebugInfo />
200
- )}
201
- </div>
202
- );
203
- }
204
- ```
205
-
206
- ### 4. Session Context Hook
207
-
208
- Access session state from any component:
209
-
210
- ```tsx
211
- import { useSessionContext } from '@nocios/crudify-ui';
212
-
213
- function MyComponent() {
214
- const {
215
- isAuthenticated,
216
- isLoading,
217
- tokens,
218
- error,
219
- login,
220
- logout,
221
- refreshTokens,
222
- isExpiringSoon,
223
- expiresIn
224
- } = useSessionContext();
225
-
226
- return (
227
- <div>
228
- {isExpiringSoon && (
229
- <Alert>Token expires in {Math.round(expiresIn / 60000)} minutes</Alert>
230
- )}
231
- </div>
232
- );
233
- }
234
- ```
235
-
236
- ## Migration Checklist
237
-
238
- - [ ] Update package versions to v1.2.0+
239
- - [ ] Replace `CrudifyDataProvider` with `SessionProvider`
240
- - [ ] Update login logic to use `useSessionContext`
241
- - [ ] Replace manual auth checks with `ProtectedRoute`
242
- - [ ] Test automatic token refresh functionality
243
- - [ ] Test session restoration on page reload
244
- - [ ] Update logout logic to use session context
245
- - [ ] Remove manual token management code
246
- - [ ] Test error handling for expired refresh tokens
247
- - [ ] Add session debug info for development
248
-
249
- ## Troubleshooting
250
-
251
- ### Issue: "useSessionContext must be used within a SessionProvider"
252
- **Solution:** Ensure your entire app is wrapped with `SessionProvider`
253
-
254
- ### Issue: Session not restoring on page reload
255
- **Solution:** Check that `autoRestore: true` is set in SessionProvider options
256
-
257
- ### Issue: Automatic refresh not working
258
- **Solution:** Verify that your backend returns refresh tokens in the login response
259
-
260
- ### Issue: Tokens not persisting between sessions
261
- **Solution:** Check browser storage permissions and ensure localStorage is enabled
262
-
263
- ## Example Complete Implementation
264
-
265
- ```tsx
266
- // App.tsx
267
- import React from 'react';
268
- import { SessionProvider, ProtectedRoute } from '@nocios/crudify-ui';
269
- import { LoginPage } from './pages/LoginPage';
270
- import { Dashboard } from './pages/Dashboard';
271
-
272
- function App() {
273
- return (
274
- <SessionProvider
275
- options={{
276
- autoRestore: true,
277
- enableLogging: process.env.NODE_ENV === 'development',
278
- onSessionExpired: () => {
279
- console.log('Session expired - redirecting to login');
280
- }
281
- }}
282
- >
283
- <AppContent />
284
- </SessionProvider>
285
- );
286
- }
287
-
288
- function AppContent() {
289
- return (
290
- <div>
291
- <LoginPage />
292
-
293
- <ProtectedRoute fallback={null}>
294
- <Dashboard />
295
- </ProtectedRoute>
296
- </div>
297
- );
298
- }
299
-
300
- export default App;
301
- ```
302
-
303
- ## Need Help?
304
-
305
- If you encounter issues during migration:
306
-
307
- 1. Check the browser console for detailed error messages
308
- 2. Enable logging with `enableLogging: true` in SessionProvider
309
- 3. Use `<SessionDebugInfo />` to inspect session state
310
- 4. Verify your backend is returning refresh tokens properly
311
-
312
- The new Refresh Token Pattern provides enhanced security and better user experience with automatic session management.
package/MIGRATION.md DELETED
@@ -1,201 +0,0 @@
1
- # Guía de Migración - useCrudifyUser v1.2.25+
2
-
3
- ## Cambios Importantes
4
-
5
- A partir de la versión 1.2.25, el hook `useCrudifyUser` ha sido completamente reestructurado para ser más simple y claro.
6
-
7
- ## Antes (❌ Estructura Anterior)
8
-
9
- ```typescript
10
- const {
11
- userEmail,
12
- userId,
13
- userIdentifier,
14
- userProfile,
15
- profileLoading,
16
- profileError,
17
- extendedData,
18
- refreshProfile,
19
- clearProfile
20
- } = useCrudifyUser();
21
-
22
- // Acceso a datos
23
- console.log(extendedData.fullProfile);
24
- console.log(extendedData.displayData);
25
- console.log(extendedData.totalFields);
26
- ```
27
-
28
- ## Ahora (✅ Nueva Estructura)
29
-
30
- ```typescript
31
- const {
32
- user,
33
- loading,
34
- error,
35
- refreshProfile,
36
- clearProfile
37
- } = useCrudifyUser();
38
-
39
- // Acceso a datos
40
- console.log(user.session); // Datos del JWT token
41
- console.log(user.data); // Datos de la base de datos
42
- ```
43
-
44
- ## Estructura del objeto `user`
45
-
46
- ```typescript
47
- interface CrudifyUserData {
48
- session: JWTPayload | null; // Datos del token JWT
49
- data: UserProfile | null; // Datos de la base de datos
50
- }
51
- ```
52
-
53
- ### `user.session` (Datos del JWT)
54
- - `user.session.sub` - User ID
55
- - `user.session.email` - Email del usuario
56
- - `user.session.name` - Nombre del usuario
57
- - `user.session.exp` - Timestamp de expiración
58
- - `user.session.iat` - Timestamp de emisión
59
- - Y todos los demás campos del JWT token
60
-
61
- ### `user.data` (Datos de la Base de Datos)
62
- - `user.data.id` - ID del perfil en la BD
63
- - `user.data.email` - Email del perfil
64
- - `user.data.firstName` - Nombre
65
- - `user.data.lastName` - Apellido
66
- - `user.data.role` - Rol del usuario
67
- - Y todos los demás campos del perfil de usuario
68
-
69
- ## Migraciones Necesarias
70
-
71
- ### 1. Cambiar las destructuraciones
72
- ```typescript
73
- // ❌ Antes
74
- const { userProfile, profileLoading, profileError } = useCrudifyUser();
75
-
76
- // ✅ Ahora
77
- const { user, loading, error } = useCrudifyUser();
78
- ```
79
-
80
- ### 2. Actualizar acceso a datos de sesión
81
- ```typescript
82
- // ❌ Antes
83
- const email = userEmail;
84
- const userId = userId;
85
-
86
- // ✅ Ahora
87
- const email = user.session?.email;
88
- const userId = user.session?.sub;
89
- ```
90
-
91
- ### 3. Actualizar acceso a datos de perfil
92
- ```typescript
93
- // ❌ Antes
94
- const profileData = userProfile;
95
- const fullName = extendedData.displayData.fullName;
96
-
97
- // ✅ Ahora
98
- const profileData = user.data;
99
- const fullName = user.data?.fullName;
100
- ```
101
-
102
- ### 4. Actualizar estados de carga y error
103
- ```typescript
104
- // ❌ Antes
105
- if (profileLoading) return <Loading />;
106
- if (profileError) return <Error message={profileError} />;
107
-
108
- // ✅ Ahora
109
- if (loading) return <Loading />;
110
- if (error) return <Error message={error} />;
111
- ```
112
-
113
- ## Beneficios de la Nueva Estructura
114
-
115
- 1. **Más Simple**: Solo un objeto `user` con `session` y `data`
116
- 2. **Más Claro**: Es obvio qué viene del JWT (`session`) y qué de la DB (`data`)
117
- 3. **Sin Duplicación**: La información no se repite en múltiples lugares
118
- 4. **Mejor TypeScript**: Tipos más precisos y claros
119
- 5. **Más Fácil de Usar**: Los desarrolladores entienden inmediatamente la estructura
120
-
121
- ## Ejemplo Completo de Migración
122
-
123
- ### Antes
124
- ```tsx
125
- function UserProfile() {
126
- const {
127
- userEmail,
128
- userProfile,
129
- profileLoading,
130
- profileError,
131
- extendedData,
132
- refreshProfile
133
- } = useCrudifyUser();
134
-
135
- if (profileLoading) return <div>Cargando...</div>;
136
- if (profileError) return <div>Error: {profileError}</div>;
137
-
138
- return (
139
- <div>
140
- <h1>Welcome {userProfile?.fullName || userEmail}</h1>
141
- <p>Total fields: {extendedData.totalFields}</p>
142
- <pre>{JSON.stringify(extendedData.displayData, null, 2)}</pre>
143
- <button onClick={refreshProfile}>Refresh</button>
144
- </div>
145
- );
146
- }
147
- ```
148
-
149
- ### Después
150
- ```tsx
151
- function UserProfile() {
152
- const {
153
- user,
154
- loading,
155
- error,
156
- refreshProfile
157
- } = useCrudifyUser();
158
-
159
- if (loading) return <div>Cargando...</div>;
160
- if (error) return <div>Error: {error}</div>;
161
-
162
- return (
163
- <div>
164
- <h1>Welcome {user.data?.fullName || user.session?.email}</h1>
165
- <h2>Datos de Sesión:</h2>
166
- <pre>{JSON.stringify(user.session, null, 2)}</pre>
167
- <h2>Datos de Perfil:</h2>
168
- <pre>{JSON.stringify(user.data, null, 2)}</pre>
169
- <button onClick={refreshProfile}>Refresh</button>
170
- </div>
171
- );
172
- }
173
- ```
174
-
175
- ## Retrocompatibilidad
176
-
177
- Para mantener compatibilidad temporal, puedes crear un wrapper:
178
-
179
- ```typescript
180
- // wrapper temporal para compatibilidad
181
- export const useLegacyUserProfile = () => {
182
- const { user, loading, error, refreshProfile, clearProfile } = useCrudifyUser();
183
-
184
- return {
185
- userEmail: user.session?.email || null,
186
- userId: user.session?.sub || null,
187
- userProfile: user.data,
188
- profileLoading: loading,
189
- profileError: error,
190
- extendedData: {
191
- fullProfile: user.data,
192
- displayData: user.data,
193
- totalFields: user.data ? Object.keys(user.data).length : 0
194
- },
195
- refreshProfile,
196
- clearProfile
197
- };
198
- };
199
- ```
200
-
201
- **Nota**: Este wrapper es solo para facilitar la migración. Se recomienda migrar completamente a la nueva estructura.