@tgtone/auth-sdk 1.3.0 → 1.3.1
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/docs/MIGRATION_GUIDE.md +315 -0
- package/package.json +1 -1
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
# Guía de Migración a v1.3.0 - Session Revocation
|
|
2
|
+
|
|
3
|
+
Esta guía explica cómo migrar tus aplicaciones existentes para usar las nuevas funcionalidades de detección de sesión revocada.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 📋 Resumen de Cambios
|
|
8
|
+
|
|
9
|
+
| Feature | Descripción |
|
|
10
|
+
|---------|-------------|
|
|
11
|
+
| `onSessionRevoked` | Callback ejecutado cuando usuario/tenant es eliminado |
|
|
12
|
+
| `heartbeatIntervalMs` | Intervalo de validación periódica de sesión |
|
|
13
|
+
| `startHeartbeat()` / `stopHeartbeat()` | Control manual del heartbeat |
|
|
14
|
+
| `getBlockedRedirectUrl()` | Genera URL de redirección para sesión revocada |
|
|
15
|
+
| `createAxiosInterceptor()` | Interceptor para Axios que maneja 401 |
|
|
16
|
+
| `createAuthFetch()` | Wrapper de fetch con manejo de sesión |
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 🔄 Migración por Tipo de App
|
|
21
|
+
|
|
22
|
+
### 1. Apps React con Context (Console, Baco, Zenith)
|
|
23
|
+
|
|
24
|
+
**Antes (v1.2.x):**
|
|
25
|
+
```tsx
|
|
26
|
+
// src/lib/auth-client.ts
|
|
27
|
+
import { TGTAuthClient } from '@tgtone/auth-sdk';
|
|
28
|
+
|
|
29
|
+
export const authClient = new TGTAuthClient({
|
|
30
|
+
identityUrl: 'https://identity.tgtone.cl',
|
|
31
|
+
appDomain: window.location.host,
|
|
32
|
+
debug: import.meta.env.DEV,
|
|
33
|
+
onAuthFailure: (error) => {
|
|
34
|
+
if (error?.code) {
|
|
35
|
+
window.location.href = `${identityUrl}/login?error=${error.code.toLowerCase()}`;
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Después (v1.3.0):**
|
|
42
|
+
```tsx
|
|
43
|
+
// src/lib/auth-client.ts
|
|
44
|
+
import { TGTAuthClient, AuthError, isRevocationError } from '@tgtone/auth-sdk';
|
|
45
|
+
|
|
46
|
+
const identityUrl = import.meta.env.VITE_IDENTITY_URL || 'https://identity.tgtone.cl';
|
|
47
|
+
|
|
48
|
+
export const authClient = new TGTAuthClient({
|
|
49
|
+
identityUrl,
|
|
50
|
+
appDomain: window.location.host,
|
|
51
|
+
debug: import.meta.env.DEV,
|
|
52
|
+
|
|
53
|
+
// 🆕 Validar sesión cada 5 minutos
|
|
54
|
+
heartbeatIntervalMs: 5 * 60 * 1000,
|
|
55
|
+
|
|
56
|
+
onAuthFailure: (error) => {
|
|
57
|
+
if (error?.code) {
|
|
58
|
+
window.location.href = `${identityUrl}/login?error=${error.code.toLowerCase()}`;
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
// 🆕 Manejar sesión revocada
|
|
63
|
+
onSessionRevoked: (error: AuthError) => {
|
|
64
|
+
console.log('[Auth] Sesión revocada:', error.code, error.message);
|
|
65
|
+
const blockedUrl = authClient.getBlockedRedirectUrl(error);
|
|
66
|
+
window.location.href = blockedUrl;
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 2. Apps con Hook useTGTAuth
|
|
72
|
+
|
|
73
|
+
**Antes (v1.2.x):**
|
|
74
|
+
```tsx
|
|
75
|
+
import { useTGTAuth } from '@tgtone/auth-sdk';
|
|
76
|
+
|
|
77
|
+
function App() {
|
|
78
|
+
const { session, loading, logout } = useTGTAuth({
|
|
79
|
+
identityUrl: 'https://identity.tgtone.cl',
|
|
80
|
+
appDomain: 'zenith.tgtone.cl',
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// ...
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Después (v1.3.0):**
|
|
88
|
+
```tsx
|
|
89
|
+
import { useTGTAuth } from '@tgtone/auth-sdk';
|
|
90
|
+
|
|
91
|
+
function App() {
|
|
92
|
+
const {
|
|
93
|
+
session,
|
|
94
|
+
loading,
|
|
95
|
+
logout,
|
|
96
|
+
revokedError, // 🆕 Error de sesión revocada
|
|
97
|
+
isHeartbeatActive // 🆕 Estado del heartbeat
|
|
98
|
+
} = useTGTAuth({
|
|
99
|
+
identityUrl: 'https://identity.tgtone.cl',
|
|
100
|
+
appDomain: 'zenith.tgtone.cl',
|
|
101
|
+
enableHeartbeat: true, // 🆕 Default: true
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// El heartbeat se inicia automáticamente después del login
|
|
105
|
+
// ...
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 3. Landing Pages (sin redirección automática)
|
|
110
|
+
|
|
111
|
+
**Después (v1.3.0):**
|
|
112
|
+
```tsx
|
|
113
|
+
import { useTGTAuth } from '@tgtone/auth-sdk';
|
|
114
|
+
|
|
115
|
+
function LandingApp() {
|
|
116
|
+
const { session, loading, revokedError } = useTGTAuth({
|
|
117
|
+
identityUrl: 'https://identity.tgtone.cl',
|
|
118
|
+
appDomain: 'tgtone.cl',
|
|
119
|
+
showRevokedState: true, // 🆕 No redirigir, mostrar estado
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
if (loading) return <Spinner />;
|
|
123
|
+
|
|
124
|
+
// 🆕 Manejar sesión revocada con UI personalizado
|
|
125
|
+
if (revokedError) {
|
|
126
|
+
return (
|
|
127
|
+
<RevokedSessionPage
|
|
128
|
+
error={revokedError}
|
|
129
|
+
onContactSupport={() => window.open('mailto:soporte@tgtone.cl')}
|
|
130
|
+
/>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (!session) {
|
|
135
|
+
return <PublicLanding onLogin={() => authClient.redirectToLogin()} />;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return <PrivateContent user={session.user} />;
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 4. Apps con Axios
|
|
143
|
+
|
|
144
|
+
**Después (v1.3.0):**
|
|
145
|
+
```tsx
|
|
146
|
+
import axios from 'axios';
|
|
147
|
+
import { createAxiosInterceptor } from '@tgtone/auth-sdk/interceptor';
|
|
148
|
+
import { authClient } from './lib/auth-client';
|
|
149
|
+
|
|
150
|
+
const api = axios.create({
|
|
151
|
+
baseURL: '/api',
|
|
152
|
+
headers: { 'Content-Type': 'application/json' }
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// 🆕 Configurar interceptor
|
|
156
|
+
const removeInterceptor = createAxiosInterceptor(api, authClient, {
|
|
157
|
+
handleRevoked: true,
|
|
158
|
+
excludeUrls: ['/public/health', '/public/metrics'],
|
|
159
|
+
onAuthError: (error) => {
|
|
160
|
+
// Opcional: logging, analytics
|
|
161
|
+
console.error('Auth error:', error.code);
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
export default api;
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### 5. Apps con Fetch nativo
|
|
169
|
+
|
|
170
|
+
**Después (v1.3.0):**
|
|
171
|
+
```tsx
|
|
172
|
+
import { createAuthFetch } from '@tgtone/auth-sdk/interceptor';
|
|
173
|
+
import { authClient } from './lib/auth-client';
|
|
174
|
+
|
|
175
|
+
// 🆕 Crear fetch con autenticación automática
|
|
176
|
+
const authFetch = createAuthFetch(authClient, {
|
|
177
|
+
handleRevoked: true,
|
|
178
|
+
excludeUrls: ['/public/'],
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// Uso igual que fetch nativo
|
|
182
|
+
const response = await authFetch('/api/users');
|
|
183
|
+
const data = await response.json();
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## 🎯 Casos de Uso por Escenario
|
|
189
|
+
|
|
190
|
+
### Escenario 1: Usuario eliminado mientras trabaja
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
1. Admin elimina usuario desde Console
|
|
194
|
+
2. Usuario hace request API o heartbeat se ejecuta
|
|
195
|
+
3. Backend retorna 401 + USER_NOT_FOUND
|
|
196
|
+
4. SDK detecta error de revocación
|
|
197
|
+
5. Se ejecuta onSessionRevoked callback
|
|
198
|
+
6. Usuario es redirigido a /blocked?type=user
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Escenario 2: Tenant suspendido
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
1. Se suspende el tenant (falta de pago, etc.)
|
|
205
|
+
2. Usuario continúa trabajando
|
|
206
|
+
3. Heartbeat detecta TENANT_INACTIVE
|
|
207
|
+
4. Usuario es redirigido a /blocked?type=tenant
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Escenario 3: Usuario desactivado
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
1. Admin desactiva usuario
|
|
214
|
+
2. Backend retorna USER_INACTIVE
|
|
215
|
+
3. Usuario ve página de blocked con mensaje apropiado
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## ⚙️ Configuración Avanzada
|
|
221
|
+
|
|
222
|
+
### Deshabilitar Heartbeat
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
const authClient = new TGTAuthClient({
|
|
226
|
+
// ...
|
|
227
|
+
heartbeatIntervalMs: 0, // Deshabilitado
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Heartbeat más frecuente (1 minuto)
|
|
232
|
+
|
|
233
|
+
```tsx
|
|
234
|
+
const authClient = new TGTAuthClient({
|
|
235
|
+
// ...
|
|
236
|
+
heartbeatIntervalMs: 60 * 1000, // 1 minuto
|
|
237
|
+
});
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Callback personalizado sin redirección
|
|
241
|
+
|
|
242
|
+
```tsx
|
|
243
|
+
const authClient = new TGTAuthClient({
|
|
244
|
+
// ...
|
|
245
|
+
onSessionRevoked: (error) => {
|
|
246
|
+
// Loguear para analytics
|
|
247
|
+
analytics.track('session_revoked', { code: error.code });
|
|
248
|
+
|
|
249
|
+
// Mostrar modal en lugar de redirigir
|
|
250
|
+
showSessionRevokedModal(error);
|
|
251
|
+
},
|
|
252
|
+
});
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## 🧪 Testing
|
|
258
|
+
|
|
259
|
+
### Simular sesión revocada
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
// En desarrollo, puedes simular el error:
|
|
263
|
+
const testError = {
|
|
264
|
+
code: 'USER_NOT_FOUND' as AuthErrorCode,
|
|
265
|
+
message: 'El usuario ha sido eliminado',
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
authClient.onSessionRevoked?.(testError);
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Verificar heartbeat
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
// Verificar si está activo
|
|
275
|
+
console.log('Heartbeat activo:', authClient.isHeartbeatActive());
|
|
276
|
+
|
|
277
|
+
// Iniciar manualmente
|
|
278
|
+
authClient.startHeartbeat();
|
|
279
|
+
|
|
280
|
+
// Detener
|
|
281
|
+
authClient.stopHeartbeat();
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## 📦 Checklist de Migración
|
|
287
|
+
|
|
288
|
+
- [ ] Actualizar `@tgtone/auth-sdk` a `^1.3.0`
|
|
289
|
+
- [ ] Agregar `heartbeatIntervalMs` a la configuración
|
|
290
|
+
- [ ] Agregar `onSessionRevoked` callback
|
|
291
|
+
- [ ] (Opcional) Configurar interceptor Axios
|
|
292
|
+
- [ ] (Opcional) Actualizar hook useTGTAuth
|
|
293
|
+
- [ ] Probar flujo de sesión revocada
|
|
294
|
+
- [ ] Verificar redirección a `/blocked`
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## ❓ FAQ
|
|
299
|
+
|
|
300
|
+
**P: ¿El heartbeat afecta el rendimiento?**
|
|
301
|
+
R: No, es un request ligero cada 5 minutos por defecto.
|
|
302
|
+
|
|
303
|
+
**P: ¿Qué pasa si el backend está offline durante el heartbeat?**
|
|
304
|
+
R: El heartbeat ignora errores de red y reintenta en el próximo intervalo.
|
|
305
|
+
|
|
306
|
+
**P: ¿Puedo usar mi propia página de blocked?**
|
|
307
|
+
R: Sí, usa `onSessionRevoked` para manejar el error y mostrar tu propia UI.
|
|
308
|
+
|
|
309
|
+
**P: ¿Necesito configurar el interceptor si uso el heartbeat?**
|
|
310
|
+
R: No es obligatorio, pero recomendado para detectar errores en requests API también.
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
**Versión:** 1.3.0
|
|
315
|
+
**Última actualización:** 2026-03-26
|