@tgtone/auth-sdk 1.2.0 → 1.2.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,478 +1,226 @@
1
- # 🔐 TGT One Auth Client SDK
1
+ # 🔐 TGT Auth SDK - Guía para Lovable/React
2
2
 
3
- SDK para integrar autenticación JWT + MFA en aplicaciones del ecosistema TGT One.
3
+ > Integración rápida de autenticación en proyectos React/Lovable
4
4
 
5
5
  ---
6
6
 
7
7
  ## 📦 Instalación
8
8
 
9
9
  ```bash
10
- npm install tgtone-auth-client@latest # v1.2.0
10
+ npm install @tgtone/auth-sdk
11
11
  ```
12
12
 
13
- ---
14
-
15
- ## 🚀 TGT Auth SDK v1.2.0 - Quick Start para Lovable
16
-
17
- ## 📦 Instalación
18
-
19
- ```bash
20
- npm install tgtone-auth-client@latest
21
- ```
13
+ **Versión actual:** 1.2.0
22
14
 
23
15
  ---
24
16
 
25
- ## ⚡ Uso Básico
17
+ ## ⚡ Setup en 3 Pasos
26
18
 
27
- ### **1. Inicializar el SDK**
19
+ ### **1. Crear AuthContext**
28
20
 
29
21
  ```typescript
30
- import { TGTAuthClient } from 'tgtone-auth-client';
22
+ // src/contexts/AuthContext.tsx
23
+ import { createContext, useContext, useEffect, useState } from 'react';
24
+ import { TGTAuthClient, TGTSession } from '@tgtone/auth-sdk';
31
25
 
32
- const auth = new TGTAuthClient({
26
+ const authClient = new TGTAuthClient({
33
27
  identityUrl: 'https://identity.tgtone.cl',
34
- appDomain: window.location.hostname, // ej: 'app.lovable.dev'
35
- debug: true // opcional: ver logs en consola
28
+ appDomain: window.location.hostname,
29
+ debug: import.meta.env.DEV
36
30
  });
37
- ```
38
31
 
39
- ---
32
+ interface AuthContextType {
33
+ session: TGTSession | null;
34
+ loading: boolean;
35
+ logout: () => Promise<void>;
36
+ hasRole: (app: string, role: string) => boolean;
37
+ }
40
38
 
41
- ### **2. Verificar Sesión (en App.tsx)**
39
+ const AuthContext = createContext<AuthContextType | null>(null);
42
40
 
43
- ```typescript
44
- import { useEffect, useState } from 'react';
45
- import { TGTAuthClient, type TGTSession } from 'tgtone-auth-client';
46
-
47
- function App() {
41
+ export function AuthProvider({ children }: { children: React.ReactNode }) {
48
42
  const [session, setSession] = useState<TGTSession | null>(null);
49
43
  const [loading, setLoading] = useState(true);
50
44
 
51
45
  useEffect(() => {
52
- const auth = new TGTAuthClient({
53
- identityUrl: 'https://identity.tgtone.cl',
54
- appDomain: window.location.hostname
55
- });
56
-
57
- auth.checkSession().then((session) => {
58
- setSession(session);
46
+ authClient.checkSession().then(s => {
47
+ setSession(s);
59
48
  setLoading(false);
60
49
  });
61
50
  }, []);
62
51
 
63
- if (loading) return <div>Cargando...</div>;
64
- if (!session) return null; // Ya redirigió a login
52
+ const logout = async () => {
53
+ await authClient.logout();
54
+ setSession(null);
55
+ };
56
+
57
+ const hasRole = (app: string, role: string) => {
58
+ return authClient.hasRole(app, role);
59
+ };
65
60
 
66
61
  return (
67
- <div>
68
- <h1>Bienvenido {session.user.name}</h1>
69
- <p>Tenant: {session.tenantName}</p>
70
- <p>Roles: {JSON.stringify(session.roles)}</p>
71
- </div>
62
+ <AuthContext.Provider value={{ session, loading, logout, hasRole }}>
63
+ {children}
64
+ </AuthContext.Provider>
72
65
  );
73
66
  }
74
- ```
75
-
76
- ---
77
-
78
- ## 🔑 Nuevas Propiedades de Sesión (v1.1)
79
-
80
- ```typescript
81
- const session = await auth.checkSession();
82
67
 
83
- // Información del Tenant
84
- session.tenantId // "uuid-tenant-123"
85
- session.tenantName // "TGT Technology"
68
+ export const useAuth = () => {
69
+ const context = useContext(AuthContext);
70
+ if (!context) throw new Error('useAuth must be used within AuthProvider');
71
+ return context;
72
+ };
73
+ ```
86
74
 
87
- // Roles por Aplicación
88
- session.roles // { "console": ["owner"], "crm": ["admin"] }
75
+ ### **2. Envolver App**
89
76
 
90
- // ✅ Usuario
91
- session.user.email // "user@tgtone.cl"
92
- session.user.name // "Juan Pérez"
77
+ ```tsx
78
+ // src/App.tsx
79
+ import { AuthProvider } from './contexts/AuthContext';
93
80
 
94
- // Expiración
95
- session.expiresAt // Date object
81
+ function App() {
82
+ return (
83
+ <AuthProvider>
84
+ {/* Tu app */}
85
+ </AuthProvider>
86
+ );
87
+ }
96
88
  ```
97
89
 
98
- ---
90
+ ### **3. Usar en Componentes**
99
91
 
100
- ## 🎯 Métodos Útiles
92
+ ```tsx
93
+ import { useAuth } from './contexts/AuthContext';
101
94
 
102
- ### **Obtener Tenant ID**
103
- ```typescript
104
- const tenantId = auth.getTenantId();
105
- // Usar en requests al backend:
106
- fetch(`/api/v1/tenants/${tenantId}/data`)
107
- ```
95
+ function Dashboard() {
96
+ const { session, loading, logout, hasRole } = useAuth();
108
97
 
109
- ### **Verificar Roles**
110
- ```typescript
111
- // ¿Es admin de Console?
112
- if (auth.hasRole('console', 'admin')) {
113
- // Mostrar panel de administración
114
- }
98
+ if (loading) return <div>Cargando...</div>;
99
+
100
+ if (!session) return null; // Ya está redirigiendo a login
115
101
 
116
- // ¿Tiene acceso a CRM?
117
- if (auth.hasAccessToApp('crm')) {
118
- // Mostrar enlace a CRM
102
+ return (
103
+ <div>
104
+ <h1>Bienvenido {session.user.name}</h1>
105
+ <p>Tenant: {session.tenantName}</p>
106
+
107
+ {hasRole('console', 'admin') && (
108
+ <button>Panel Admin</button>
109
+ )}
110
+
111
+ <button onClick={logout}>Cerrar Sesión</button>
112
+ </div>
113
+ );
119
114
  }
120
-
121
- // Obtener todos los roles de una app
122
- const roles = auth.getRoles('console'); // ["owner", "admin"]
123
- ```
124
-
125
- ### **Cerrar Sesión**
126
- ```typescript
127
- <button onClick={() => auth.logout()}>
128
- Cerrar Sesión
129
- </button>
130
115
  ```
131
116
 
132
117
  ---
133
118
 
134
- ## 📡 Requests al Backend con Tenant
119
+ ## 🎯 Propiedades de Sesión
135
120
 
136
121
  ```typescript
137
- const session = await auth.checkSession();
138
-
139
- // ✅ Incluir tenantId en headers
140
- fetch('https://api.tgtone.cl/v1/data', {
141
- headers: {
142
- 'Authorization': `Bearer ${localStorage.getItem('tgtone_auth_token')}`,
143
- 'X-Tenant-ID': session.tenantId, // ✅ Tenant context
144
- }
145
- });
122
+ session.user.email // "user@empresa.cl"
123
+ session.user.name // "Juan Pérez"
124
+ session.tenantId // "uuid-tenant-123"
125
+ session.tenantName // "Mi Empresa"
126
+ session.user.roles // { console: ['owner'], crm: ['admin'] }
127
+ session.expiresAt // Date object
146
128
  ```
147
129
 
148
130
  ---
149
131
 
150
- ## 🛡️ Validación Local de JWT
151
-
152
- El SDK ahora **decodifica el JWT localmente** antes de validar con el backend:
153
-
154
- ✅ Verifica `tenant_id` obligatorio
155
- ✅ Valida expiración del token
156
- ✅ Extrae roles sin hacer request
157
-
158
- **Ventaja:** Menos latencia, mejor UX.
159
-
160
- ---
161
-
162
- ## 🔐 Soporte MFA (v1.2.0)
163
-
164
- El SDK ahora soporta **Multi-Factor Authentication** con Google Authenticator/TOTP.
165
-
166
- ### Flujo de Login con MFA
167
-
168
- Si el usuario tiene MFA habilitado, el backend NO hace redirect automático. En su lugar, el frontend de Identity maneja el flujo MFA completo:
132
+ ## 🔐 Verificar Roles
169
133
 
170
- **1. Login con MFA habilitado:**
171
134
  ```typescript
172
- // El usuario hace login en Identity (https://identity.tgtone.cl)
173
- // Si tiene MFA habilitado:
174
- // Identity muestra pantalla de código de 6 dígitos
175
- // → Usuario ingresa código de Google Authenticator
176
- // → Identity valida y redirige con token final
177
- ```
178
-
179
- **2. Tu app en Lovable recibe el token:**
180
- ```typescript
181
- // Cuando Identity redirige de vuelta a tu app:
182
- const session = await auth.checkSession();
183
- // ✅ El token ya viene validado (con MFA completado)
184
- ```
185
-
186
- ### Métodos MFA del SDK
187
-
188
- Aunque Identity maneja el flujo MFA visualmente, el SDK expone métodos para casos avanzados:
189
-
190
- ```typescript
191
- // Verificar código MFA programáticamente (uso avanzado)
192
- const session = await auth.verifyMfa(tempToken, '123456');
193
-
194
- // Guardar tempToken en localStorage
195
- auth.storeTempToken(tempToken);
196
-
197
- // Obtener tempToken guardado
198
- const tempToken = auth.getTempToken();
199
-
200
- // Limpiar tempToken
201
- auth.clearTempToken();
202
- ```
203
-
204
- > **💡 Nota para Lovable**: En la mayoría de casos NO necesitas llamar `verifyMfa()` directamente. Identity maneja el flujo MFA completo y tu app solo recibe el token final validado.
205
-
206
- ### ¿Cuándo usar los métodos MFA?
207
-
208
- **✅ Caso común (recomendado):**
209
- ```typescript
210
- // Identity maneja todo el flujo MFA
211
- const session = await auth.checkSession();
212
- // Ya viene con MFA validado si el usuario lo tiene habilitado
213
- ```
214
-
215
- **🔧 Caso avanzado (si implementas login custom):**
216
- ```typescript
217
- // Solo si NO usas el frontend de Identity
218
- const loginResponse = await fetch('/api/auth/login', {
219
- method: 'POST',
220
- body: JSON.stringify({ email, password })
221
- });
222
-
223
- const data = await loginResponse.json();
224
-
225
- if (data.requiresMfa && data.tempToken) {
226
- auth.storeTempToken(data.tempToken);
227
- // Mostrar input para código
228
- const code = getUserInputCode();
229
- const session = await auth.verifyMfa(data.tempToken, code);
135
+ // ¿Es admin de Console?
136
+ if (hasRole('console', 'admin')) {
137
+ // Mostrar funciones de admin
230
138
  }
231
- ```
232
-
233
- ---
234
139
 
235
- ## 🆕 Cambios por Versión
236
-
237
- ### v1.2.0 (Octubre 2025)
238
- - ✅ **Soporte MFA** con TOTP (Google Authenticator)
239
- - ✅ Métodos `verifyMfa()`, `storeTempToken()`, `getTempToken()`, `clearTempToken()`
240
- - ✅ Detección automática de flujo MFA en `checkSession()`
241
- - ✅ Identity maneja UI de MFA (no requiere código custom en apps)
242
-
243
- ### v1.1.0 (Octubre 2025)
244
- - ✅ Validación de `tenant_id` obligatorio
245
- - ✅ Decodificación local de JWT
246
- - ✅ Nuevo retorno `TGTSession` en lugar de `TGTUser`
247
- - ✅ Métodos `hasRole()`, `getRoles()`, `hasAccessToApp()`
248
-
249
- ### v1.0.0
250
- - ✅ Versión inicial con SSO básico
251
-
252
- ---
253
-
254
- ## 🔧 TypeScript Types
255
-
256
- ```typescript
257
- import type {
258
- TGTSession,
259
- TGTUser,
260
- JWTPayload
261
- } from 'tgtone-auth-client';
262
-
263
- interface TGTSession {
264
- user: TGTUser;
265
- tenantId: string;
266
- tenantName: string;
267
- roles: Record<string, string[]>; // { "console": ["admin"] }
268
- expiresAt: Date;
140
+ // ¿Tiene acceso a CRM?
141
+ if (authClient.hasAccessToApp('crm')) {
142
+ // Mostrar enlace a CRM
269
143
  }
270
- ```
271
-
272
- ---
273
-
274
- ## ⚠️ Breaking Changes
275
-
276
- Si usabas v1.0, actualizar código:
277
144
 
278
- ```typescript
279
- // Antes (v1.0)
280
- const user = await auth.checkSession();
281
- console.log(user.email);
282
-
283
- // ✅ Ahora (v1.1)
284
- const session = await auth.checkSession();
285
- console.log(session.user.email);
286
- console.log(session.tenantId); // ← NUEVO
145
+ // Obtener todos los roles
146
+ const roles = authClient.getRoles('console'); // ['owner', 'admin']
287
147
  ```
288
148
 
289
149
  ---
290
150
 
291
- ## 🚨 Troubleshooting
292
-
293
- ### Error: "Invalid token: missing tenant_id"
294
- → Tu backend no está incluyendo `tenant_id` en el JWT. Verificar `auth.service.ts`.
295
-
296
- ### Error: "Token expired"
297
- → El token tiene > 90 días (dev) o > 1h (prod). Re-login automático.
298
-
299
- ### No redirige a login
300
- → Verificar que `identityUrl` y `appDomain` sean correctos.
301
-
302
- ---
303
-
304
- ## 📚 Docs Completas
305
-
306
- Ver: `sdk/README.md` o https://github.com/tgt-technology/tgtone-identity-auth
307
-
308
- ---
309
-
310
- ## 📋 API
311
-
312
- ### `checkSession(): Promise<TGTUser | null>`
313
- Verifica sesión. Lee token de URL (si viene del redirect), lo guarda en localStorage y valida con backend.
314
-
315
- ```typescript
316
- const user = await auth.checkSession();
317
- if (user) {
318
- console.log('Usuario logueado:', user.email);
319
- }
320
- ```
321
-
322
- ### `getUser(): TGTUser | null`
323
- Obtiene usuario en memoria (sin request). Requiere llamar `checkSession()` primero.
324
-
325
- ### `logout(): Promise<void>`
326
- Cierra sesión, limpia localStorage y redirige al login.
151
+ ## 🆕 Verificación Silenciosa (v1.2.0)
327
152
 
328
- ### `hasRole(app: string, role: string): boolean`
329
- Verifica si tiene un rol específico.
153
+ Para páginas que no requieren autenticación obligatoria:
330
154
 
331
155
  ```typescript
332
- if (auth.hasRole('console', 'admin')) {
333
- // Mostrar panel admin
334
- }
156
+ // Landing page o página pública
157
+ useEffect(() => {
158
+ const checkAuth = async () => {
159
+ const session = await authClient.checkSessionSilent();
160
+
161
+ if (session) {
162
+ // Usuario logeado - mostrar contenido personalizado
163
+ showButton('Ir al Dashboard', '/dashboard');
164
+ } else {
165
+ // Usuario no logeado - mostrar botón de login
166
+ showButton('Iniciar Sesión', () => authClient.redirectToLogin());
167
+ }
168
+ };
169
+
170
+ checkAuth();
171
+ }, []);
335
172
  ```
336
173
 
337
- ### `getRoles(app: string): string[]`
338
- Obtiene roles del usuario en una app.
339
-
340
- ### `redirectToLogin(): void`
341
- Redirige manualmente al login.
342
-
343
174
  ---
344
175
 
345
- ## 🔄 Flujo Completo (con MFA)
176
+ ## 🔄 Flujo de Autenticación
346
177
 
347
178
  ```
348
- 1. Usuario visita tu app en Lovable
349
-
350
- 2. App ejecuta auth.checkSession()
179
+ 1. Usuario entra a tu app
351
180
 
352
- 3. No hay token → Redirect a Identity con ?redirect=tu-dominio
181
+ 2. checkSession() no encuentra token
353
182
 
354
- 4. Usuario ingresa email + password en Identity
183
+ 3. SDK redirige a identity.tgtone.cl/login
355
184
 
356
- 5a. Sin MFA habilitado:
357
- → Identity redirige a tu-dominio?token=eyJ...
358
- → SDK guarda token y retorna sesión
359
-
360
- 5b. 🔐 Con MFA habilitado:
361
- → Identity muestra pantalla de código de 6 dígitos
362
- → Usuario ingresa código de Google Authenticator
363
- → Identity valida código con backend
364
- → ✅ Código válido → Identity redirige a tu-dominio?token=eyJ...
365
- → SDK guarda token y retorna sesión
185
+ 4. Usuario hace login (+ MFA si está habilitado)
366
186
 
367
- 6. SDK lee token de URL y lo guarda en localStorage
187
+ 5. Identity redirige: tu-app?token=eyJhbGci...
368
188
 
369
- 7. SDK valida token con backend (Authorization: Bearer ...)
189
+ 6. SDK guarda token y valida con backend
370
190
 
371
- 8. ✅ Retorna sesión completa
191
+ 7. ✅ Usuario autenticado
372
192
  ```
373
193
 
374
- **💡 Clave:** Tu app en Lovable NO necesita manejar MFA. Identity lo hace todo y te devuelve el token final ya validado.
375
-
376
194
  ---
377
195
 
378
- ## 🧪 Testing Rápido (Sin Login)
379
-
380
- Para desarrollo rápido sin pasar por login:
196
+ ## 🧪 Testing sin Login
381
197
 
382
198
  ```typescript
383
- useEffect(() => {
384
- // 1. Hacer login con curl y copiar el token
385
- // 2. Guardarlo manualmente:
386
- const testToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';
387
- localStorage.setItem('tgtone_auth_token', testToken);
388
-
389
- // 3. Ahora checkSession funcionará
390
- auth.checkSession().then(setUser);
391
- }, []);
392
- ```
199
+ // Guardar token manualmente en localStorage
200
+ localStorage.setItem('tgtone_auth_token', 'eyJhbGci...');
201
+ window.location.reload();
393
202
 
394
- **Obtener token:**
395
- ```bash
396
- curl -X POST https://identity.tgtone.cl/api/v1/auth/login \
397
- -H "Content-Type: application/json" \
398
- -d '{"email": "superadmin@tgtone.cl", "password": "Tgt123."}'
203
+ // Obtener token de prueba con curl:
204
+ // curl -X POST https://tgtone-console-backend.run.app/api/v1/auth/login \
205
+ // -d '{"email": "user@test.cl", "password": "Test123!"}'
399
206
  ```
400
207
 
401
208
  ---
402
209
 
403
- ## 👤 Estructura del Usuario
404
-
405
- ```typescript
406
- interface TGTUser {
407
- sub: string; // ID usuario
408
- email: string;
409
- name: string;
410
- tenant_id: string;
411
- tenant_name: string;
412
- roles: Record<string, string[]>; // { console: ['owner'], zenith: ['admin'] }
413
- }
414
- ```
415
-
416
- ---
210
+ ## 📚 API Completa
417
211
 
418
- ## ⚙️ Configuración
212
+ Ver documentación completa: **[README.md](../README.md)**
419
213
 
420
- ```typescript
421
- interface TGTAuthConfig {
422
- identityUrl: string; // URL del backend Identity
423
- appDomain: string; // Dominio de tu app (sin protocolo)
424
- onAuthSuccess?: (user: TGTUser) => void; // Callback cuando se autentica
425
- onAuthFailure?: () => void; // Callback cuando falla
426
- debug?: boolean; // Logs en consola
427
- }
428
- ```
429
-
430
- ---
431
-
432
- ## 🔐 Cómo Funciona
433
-
434
- 1. **Token en URL**: Después del login, Identity redirige con `?token=...`
435
- 2. **localStorage**: SDK guarda token en `tgtone_auth_token`
436
- 3. **Bearer Token**: Todas las requests usan `Authorization: Bearer <token>`
437
- 4. **Validación**: Backend valida JWT y retorna datos del usuario
438
- 5. **No cookies**: Todo se maneja con Bearer tokens en localStorage
439
-
440
- ---
441
-
442
- ## 🛠️ Para Producción
443
-
444
- Cambiar `identityUrl` según ambiente:
445
-
446
- ```typescript
447
- const auth = new TGTAuthClient({
448
- identityUrl: import.meta.env.PROD
449
- ? 'https://identity.tgtone.cl'
450
- : 'https://identity.tgtone.cl', // Mismo dominio en dev y prod
451
- appDomain: window.location.hostname
452
- });
453
- ```
454
-
455
- ---
456
-
457
- ## 🔐 Seguridad MFA
458
-
459
- El sistema MFA de TGT One usa **TOTP (Time-based One-Time Password)** basado en RFC 6238:
460
-
461
- - 🔑 **Secret compartido**: Generado al activar MFA, guardado encriptado en BD
462
- - ⏱️ **Códigos temporales**: Válidos por 30 segundos
463
- - 🔄 **Ventana de tolerancia**: ±30 segundos para compensar desfase de reloj
464
- - 📱 **Compatible con**: Google Authenticator, Microsoft Authenticator, Authy, 1Password, etc.
465
-
466
- ### Cómo funciona:
467
- ```
468
- Usuario habilita MFA → Backend genera secret único
469
- → Muestra QR code
470
- → Usuario escanea con Google Authenticator
471
- → App genera códigos cada 30s: HMAC-SHA1(secret, tiempo)
472
- → Al login: Backend valida con mismo algoritmo
473
- ```
214
+ Métodos disponibles:
215
+ - `checkSession()` - Verifica sesión (redirige si no hay)
216
+ - `checkSessionSilent()` - Verifica sin redirigir
217
+ - `signup()` - Crear cuenta
218
+ - `login()` - Iniciar sesión
219
+ - `logout()` - Cerrar sesión
220
+ - `verifyMfa()` - Validar código MFA
221
+ - `hasRole()` - Verificar roles
222
+ - `redirectToLogin()` - Redirigir a login
474
223
 
475
224
  ---
476
225
 
477
- **Última actualización:** 2025-10-29
478
- **Versión SDK:** v1.2.0
226
+ **Última actualización:** 2025-11-03