@tgtone/auth-sdk 1.4.3 → 1.4.4
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/CHANGELOG.md +72 -0
- package/MIGRATION_GUIDE.md +293 -0
- package/README.md +15 -56
- package/docs/API.md +844 -0
- package/docs/INTEGRATION_EXAMPLES.md +181 -322
- package/docs/{NPM_PUBLISH.md → PUBLISHING.md} +1 -1
- package/docs/QUICKSTART_REACT.md +295 -0
- package/docs/README.md +33 -23
- package/package.json +3 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/docs/LOVABLE_QUICK_START.md +0 -316
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
# 🔐 TGT Auth SDK - Guía para Lovable/React
|
|
2
|
-
|
|
3
|
-
> Integración rápida de autenticación en proyectos React/Lovable
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 📦 Instalación
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npm install @tgtone/auth-sdk
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
**Versión actual:** 1.2.3
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## ⚡ Setup en 3 Pasos
|
|
18
|
-
|
|
19
|
-
### **1. Crear AuthContext**
|
|
20
|
-
|
|
21
|
-
```typescript
|
|
22
|
-
// src/contexts/AuthContext.tsx
|
|
23
|
-
import { createContext, useContext, useEffect, useState, ReactNode } from 'react';
|
|
24
|
-
import { TGTAuthClient, TGTUser } from '@tgtone/auth-sdk';
|
|
25
|
-
|
|
26
|
-
// Extender TGTSession para incluir roles (están en user.roles)
|
|
27
|
-
interface TGTSession {
|
|
28
|
-
user: TGTUser;
|
|
29
|
-
tenantId: string;
|
|
30
|
-
tenantName: string;
|
|
31
|
-
expiresAt: Date;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
interface AuthContextType {
|
|
35
|
-
session: TGTSession | null;
|
|
36
|
-
user: TGTUser | null; // Acceso directo al usuario
|
|
37
|
-
tenantId: string | null; // Acceso directo
|
|
38
|
-
loading: boolean;
|
|
39
|
-
logout: () => Promise<void>;
|
|
40
|
-
hasRole: (app: string, role: string) => boolean;
|
|
41
|
-
hasAccessToApp: (appName: string) => boolean;
|
|
42
|
-
getRoles: (appName: string) => string[];
|
|
43
|
-
getToken: () => string | null; // Para API calls
|
|
44
|
-
isAuthenticated: boolean; // Shorthand
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const AuthContext = createContext<AuthContextType | null>(null);
|
|
48
|
-
|
|
49
|
-
// ✅ Singleton FUERA del componente (evita re-crear en cada render)
|
|
50
|
-
let authClient: TGTAuthClient | null = null;
|
|
51
|
-
|
|
52
|
-
const getAuthClient = (): TGTAuthClient => {
|
|
53
|
-
if (!authClient) {
|
|
54
|
-
authClient = new TGTAuthClient({
|
|
55
|
-
identityUrl: import.meta.env.VITE_IDENTITY_URL || 'https://identity.tgtone.cl',
|
|
56
|
-
appDomain: window.location.host, // Usa .host (incluye puerto) para dev
|
|
57
|
-
debug: import.meta.env.DEV
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
return authClient;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
export function AuthProvider({ children }: { children: ReactNode }) {
|
|
64
|
-
const [session, setSession] = useState<TGTSession | null>(null);
|
|
65
|
-
const [loading, setLoading] = useState(true);
|
|
66
|
-
|
|
67
|
-
useEffect(() => {
|
|
68
|
-
const initAuth = async () => {
|
|
69
|
-
try {
|
|
70
|
-
const auth = getAuthClient();
|
|
71
|
-
const currentSession = await auth.checkSession();
|
|
72
|
-
setSession(currentSession as TGTSession);
|
|
73
|
-
} catch (error) {
|
|
74
|
-
console.error('Error checking session:', error);
|
|
75
|
-
setSession(null);
|
|
76
|
-
} finally {
|
|
77
|
-
setLoading(false);
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
initAuth();
|
|
81
|
-
}, []);
|
|
82
|
-
|
|
83
|
-
const logout = async () => {
|
|
84
|
-
const auth = getAuthClient();
|
|
85
|
-
await auth.logout();
|
|
86
|
-
setSession(null);
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
const hasRole = (app: string, role: string) => {
|
|
90
|
-
return getAuthClient().hasRole(app, role);
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
const hasAccessToApp = (appName: string) => {
|
|
94
|
-
return getAuthClient().hasAccessToApp(appName);
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
const getRoles = (appName: string) => {
|
|
98
|
-
return getAuthClient().getRoles(appName);
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const getToken = () => {
|
|
102
|
-
return getAuthClient().getToken();
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
return (
|
|
106
|
-
<AuthContext.Provider value={{
|
|
107
|
-
session,
|
|
108
|
-
user: session?.user || null,
|
|
109
|
-
tenantId: session?.tenantId || null,
|
|
110
|
-
loading,
|
|
111
|
-
logout,
|
|
112
|
-
hasRole,
|
|
113
|
-
hasAccessToApp,
|
|
114
|
-
getRoles,
|
|
115
|
-
getToken,
|
|
116
|
-
isAuthenticated: !!session
|
|
117
|
-
}}>
|
|
118
|
-
{/* ⚠️ CRÍTICO: No renderizar hijos mientras carga para evitar que el Router
|
|
119
|
-
limpie los parámetros de la URL (?token=...) antes de que el SDK los procese */}
|
|
120
|
-
{loading ? (
|
|
121
|
-
<div className="flex items-center justify-center min-h-screen">
|
|
122
|
-
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-primary"></div>
|
|
123
|
-
</div>
|
|
124
|
-
) : (
|
|
125
|
-
children
|
|
126
|
-
)}
|
|
127
|
-
</AuthContext.Provider>
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export const useAuth = () => {
|
|
132
|
-
const context = useContext(AuthContext);
|
|
133
|
-
if (!context) throw new Error('useAuth must be used within AuthProvider');
|
|
134
|
-
return context;
|
|
135
|
-
};
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
### **2. Envolver App**
|
|
139
|
-
|
|
140
|
-
```tsx
|
|
141
|
-
// src/App.tsx
|
|
142
|
-
import { AuthProvider } from './contexts/AuthContext';
|
|
143
|
-
|
|
144
|
-
function App() {
|
|
145
|
-
return (
|
|
146
|
-
<AuthProvider>
|
|
147
|
-
{/* Tu app */}
|
|
148
|
-
</AuthProvider>
|
|
149
|
-
);
|
|
150
|
-
}
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
### **3. Usar en Componentes**
|
|
154
|
-
|
|
155
|
-
```tsx
|
|
156
|
-
import { useAuth } from './contexts/AuthContext';
|
|
157
|
-
|
|
158
|
-
function Dashboard() {
|
|
159
|
-
const { user, tenantId, loading, logout, hasRole, isAuthenticated } = useAuth();
|
|
160
|
-
|
|
161
|
-
if (loading) return <div>Cargando...</div>;
|
|
162
|
-
|
|
163
|
-
if (!isAuthenticated) return null; // Ya está redirigiendo a login
|
|
164
|
-
|
|
165
|
-
return (
|
|
166
|
-
<div>
|
|
167
|
-
<h1>Bienvenido {user?.name}</h1>
|
|
168
|
-
<p>Tenant: {tenantId}</p>
|
|
169
|
-
|
|
170
|
-
{hasRole('console', 'admin') && (
|
|
171
|
-
<button>Panel Admin</button>
|
|
172
|
-
)}
|
|
173
|
-
|
|
174
|
-
<button onClick={logout}>Cerrar Sesión</button>
|
|
175
|
-
</div>
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
---
|
|
181
|
-
|
|
182
|
-
## 🎯 Propiedades de Sesión
|
|
183
|
-
|
|
184
|
-
```typescript
|
|
185
|
-
// Datos del usuario
|
|
186
|
-
session.user.email // "user@empresa.cl"
|
|
187
|
-
session.user.name // "Juan Pérez"
|
|
188
|
-
session.user.sub // "uuid-user-123" (ID del usuario)
|
|
189
|
-
|
|
190
|
-
// Datos del tenant
|
|
191
|
-
session.tenantId // "uuid-tenant-123"
|
|
192
|
-
session.tenantName // "Mi Empresa"
|
|
193
|
-
|
|
194
|
-
// ⚠️ IMPORTANTE: Los roles están en USER, no en session
|
|
195
|
-
session.user.roles // { console: ['owner'], crm: ['admin'] }
|
|
196
|
-
|
|
197
|
-
// Expiración
|
|
198
|
-
session.expiresAt // Date object
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
> **Nota:** Los roles se acceden via `session.user.roles`, NO `session.roles`
|
|
202
|
-
|
|
203
|
-
---
|
|
204
|
-
|
|
205
|
-
## 🔐 Verificar Roles
|
|
206
|
-
|
|
207
|
-
```typescript
|
|
208
|
-
// Usando el hook useAuth (recomendado)
|
|
209
|
-
const { hasRole, hasAccessToApp, getRoles } = useAuth();
|
|
210
|
-
|
|
211
|
-
// ¿Es admin de Console?
|
|
212
|
-
if (hasRole('console', 'admin')) {
|
|
213
|
-
// Mostrar funciones de admin
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// ¿Tiene acceso a CRM?
|
|
217
|
-
if (hasAccessToApp('crm')) {
|
|
218
|
-
// Mostrar enlace a CRM
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Obtener todos los roles en una app
|
|
222
|
-
const roles = getRoles('console'); // ['owner', 'admin']
|
|
223
|
-
|
|
224
|
-
// Verificar múltiples roles
|
|
225
|
-
const isAdmin = hasRole('myapp', 'admin') || hasRole('myapp', 'owner');
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
---
|
|
229
|
-
|
|
230
|
-
## 🆕 Verificación Silenciosa (v1.2.0)
|
|
231
|
-
|
|
232
|
-
Para páginas que no requieren autenticación obligatoria:
|
|
233
|
-
|
|
234
|
-
```typescript
|
|
235
|
-
// Landing page o página pública
|
|
236
|
-
useEffect(() => {
|
|
237
|
-
const checkAuth = async () => {
|
|
238
|
-
const session = await authClient.checkSessionSilent();
|
|
239
|
-
|
|
240
|
-
if (session) {
|
|
241
|
-
// Usuario logeado - mostrar contenido personalizado
|
|
242
|
-
showButton('Ir al Dashboard', '/dashboard');
|
|
243
|
-
} else {
|
|
244
|
-
// Usuario no logeado - mostrar botón de login
|
|
245
|
-
showButton('Iniciar Sesión', () => authClient.redirectToLogin());
|
|
246
|
-
}
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
checkAuth();
|
|
250
|
-
}, []);
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
---
|
|
254
|
-
|
|
255
|
-
## 🔄 Flujo de Autenticación
|
|
256
|
-
|
|
257
|
-
```
|
|
258
|
-
1. Usuario entra a tu app
|
|
259
|
-
↓
|
|
260
|
-
2. checkSession() no encuentra token
|
|
261
|
-
↓
|
|
262
|
-
3. SDK redirige a identity.tgtone.cl/login
|
|
263
|
-
↓
|
|
264
|
-
4. Usuario hace login (+ MFA si está habilitado)
|
|
265
|
-
↓
|
|
266
|
-
5. Identity redirige: tu-app?token=eyJhbGci...
|
|
267
|
-
↓
|
|
268
|
-
6. SDK guarda token y valida con backend
|
|
269
|
-
↓
|
|
270
|
-
7. ✅ Usuario autenticado
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
---
|
|
274
|
-
|
|
275
|
-
## 🧪 Testing sin Login
|
|
276
|
-
|
|
277
|
-
```typescript
|
|
278
|
-
// Guardar token manualmente en localStorage
|
|
279
|
-
localStorage.setItem('tgtone_auth_token', 'eyJhbGci...');
|
|
280
|
-
window.location.reload();
|
|
281
|
-
|
|
282
|
-
// Obtener token de prueba con curl:
|
|
283
|
-
// curl -X POST https://tgtone-console-backend.run.app/api/v1/auth/login \
|
|
284
|
-
// -d '{"email": "user@test.cl", "password": "Test123!"}'
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
---
|
|
288
|
-
|
|
289
|
-
## 📚 API Completa
|
|
290
|
-
|
|
291
|
-
Ver documentación completa: **[README.md](../README.md)**
|
|
292
|
-
|
|
293
|
-
Métodos disponibles:
|
|
294
|
-
- `checkSession()` - Verifica sesión (redirige si no hay)
|
|
295
|
-
- `checkSessionSilent()` - Verifica sin redirigir
|
|
296
|
-
- `signup()` - Crear cuenta
|
|
297
|
-
- `login()` - Iniciar sesión
|
|
298
|
-
- `logout()` - Cerrar sesión
|
|
299
|
-
- `verifyMfa()` - Validar código MFA
|
|
300
|
-
- `hasRole()` - Verificar roles
|
|
301
|
-
- `redirectToLogin()` - Redirigir a login
|
|
302
|
-
|
|
303
|
-
---
|
|
304
|
-
|
|
305
|
-
## 🔧 Variables de Entorno
|
|
306
|
-
|
|
307
|
-
```env
|
|
308
|
-
# .env.local
|
|
309
|
-
VITE_IDENTITY_URL=https://identity.tgtone.cl
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
> En desarrollo local, si no defines `VITE_IDENTITY_URL`, usará `https://identity.tgtone.cl` por defecto.
|
|
313
|
-
|
|
314
|
-
---
|
|
315
|
-
|
|
316
|
-
**Última actualización:** 2025-12-19
|