@tgtone/auth-sdk 1.0.0

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.
@@ -0,0 +1,88 @@
1
+ # ✅ SDK Organizado - Resumen Final
2
+
3
+ ## 📁 Estructura Actual
4
+
5
+ ```
6
+ sdk/
7
+ ├── README.md # ✅ Guía principal (simplificado, 70 líneas)
8
+ ├── package.json # ✅ Actualizado (v1.0.2, incluye docs/)
9
+ ├── tsconfig.json
10
+ ├── index.ts # Entry point
11
+ ├── tgtone-auth-client.ts # ✅ SDK (limpio, sin cookies)
12
+ ├── react-hook.tsx # Hook React
13
+ ├── .npmignore
14
+ ├── dist/ # Archivos compilados
15
+ └── docs/
16
+ ├── README.md # ✅ Índice de documentación
17
+ ├── LOVABLE_QUICK_START.md # ✅ Guía para Lovable
18
+ ├── INTEGRATION_EXAMPLES.md # Ejemplos otros frameworks
19
+ ├── CHANGELOG.md # Historial versiones
20
+ ├── ORGANIZATION_SUMMARY.md # Este resumen
21
+ └── README_OLD.md # Archivo (referencia)
22
+ ```
23
+
24
+ ---
25
+
26
+ ## ✅ Cambios Completados
27
+
28
+ ### 1. Código SDK
29
+ - ✅ Eliminado `credentials: 'include'` (ya no usamos cookies)
30
+ - ✅ Solo Bearer Token en Authorization header
31
+ - ✅ localStorage para guardar tokens
32
+
33
+ ### 2. Documentación
34
+ - ✅ README.md simplificado (70 líneas vs 391)
35
+ - ✅ Creada carpeta `docs/` con toda la doc organizada
36
+ - ✅ `LOVABLE_QUICK_START.md` - Guía específica para Lovable
37
+ - ✅ `docs/README.md` - Índice completo
38
+ - ✅ README antiguo archivado como referencia
39
+
40
+ ### 3. Package.json
41
+ - ✅ Versión actualizada: `1.0.1` → `1.0.2`
42
+ - ✅ Descripción actualizada: "JWT + Bearer Token"
43
+ - ✅ Files incluye carpeta `docs/`
44
+
45
+ ---
46
+
47
+ ## 📖 Guía de Uso
48
+
49
+ ### Para desarrollar en Lovable
50
+ 1. Leer: `docs/LOVABLE_QUICK_START.md`
51
+ 2. Copiar: `tgtone-auth-client.ts` a tu proyecto
52
+ 3. Usar código de ejemplo
53
+
54
+ ### Para instalar vía NPM
55
+ ```bash
56
+ npm install tgtone-auth-client
57
+ ```
58
+
59
+ Ver: `README.md`
60
+
61
+ ### Para otros frameworks
62
+ Ver: `docs/INTEGRATION_EXAMPLES.md`
63
+
64
+ ---
65
+
66
+ ## 🎯 Documentación por Necesidad
67
+
68
+ | Necesitas... | Archivo |
69
+ |--------------|---------|
70
+ | Setup rápido | `README.md` |
71
+ | Lovable/React | `docs/LOVABLE_QUICK_START.md` |
72
+ | Vue/Next/Angular | `docs/INTEGRATION_EXAMPLES.md` |
73
+ | API completa | `README.md` + `docs/README_OLD.md` |
74
+ | Ver cambios | `docs/CHANGELOG.md` |
75
+
76
+ ---
77
+
78
+ ## 🚀 Listo para Usar
79
+
80
+ El SDK está completamente organizado y listo para:
81
+ - ✅ Copiar archivo directamente a Lovable
82
+ - ✅ Instalar vía NPM (si está publicado)
83
+ - ✅ Integrar en cualquier framework
84
+ - ✅ Testing con tokens manuales
85
+
86
+ ---
87
+
88
+ **Última actualización:** 2025-10-16
@@ -0,0 +1,433 @@
1
+ # 🔐 Reglas de Integración del SDK TGT Auth Client
2
+
3
+ > **Para Lovable AI**: Este documento especifica EXACTAMENTE cómo integrar `tgtone-auth-client` en Console.
4
+
5
+ ---
6
+
7
+ ## ❌ Lo que Lovable NO debe hacer
8
+
9
+ ### 1. NO crear sistema de "Mock Auth"
10
+ ```typescript
11
+ // ❌ ELIMINAR ESTO:
12
+ import { checkMockSession, mockLogout } from '@/services/mockAuth.service';
13
+ const isMockMode = import.meta.env.VITE_AUTH_MODE === 'mock';
14
+ ```
15
+
16
+ **Razón**: El SDK ya maneja todo. No necesitas simular autenticación.
17
+
18
+ ### 2. NO crear variables de entorno personalizadas
19
+ ```typescript
20
+ // ❌ NO USAR:
21
+ VITE_AUTH_MODE=mock
22
+ VITE_IDENTITY_URL=...
23
+ ```
24
+
25
+ **Razón**: Las URLs están hardcodeadas en el código según ambiente (dev/prod).
26
+
27
+ ### 3. NO inicializar el cliente múltiples veces
28
+ ```typescript
29
+ // ❌ MAL - Crear cliente en cada componente
30
+ function MyComponent() {
31
+ const auth = new TGTAuthClient({ ... });
32
+ }
33
+
34
+ // ✅ BIEN - Crear UNA VEZ en AuthContext
35
+ let authClient: TGTAuthClient | null = null;
36
+ const getAuthClient = () => {
37
+ if (!authClient) {
38
+ authClient = new TGTAuthClient({ ... });
39
+ }
40
+ return authClient;
41
+ };
42
+ ```
43
+
44
+ ### 4. NO manejar redirecciones manualmente
45
+ ```typescript
46
+ // ❌ MAL - Redirigir manualmente al login
47
+ if (!user) {
48
+ navigate('/login');
49
+ }
50
+
51
+ // ✅ BIEN - El SDK redirige automáticamente
52
+ if (!user) {
53
+ return null; // SDK ya está redirigiendo
54
+ }
55
+ ```
56
+
57
+ ### 5. NO crear páginas de login
58
+ ```typescript
59
+ // ❌ ELIMINAR:
60
+ <Route path="/login" element={<Login />} />
61
+ <Route path="/auth" element={<Auth />} />
62
+ ```
63
+
64
+ **Razón**: El login está en `identity.tgtone.cl`, no en Console.
65
+
66
+ ---
67
+
68
+ ## ✅ Implementación Correcta
69
+
70
+ ### 1. AuthContext.tsx (Mínimo Necesario)
71
+
72
+ ```typescript
73
+ import { createContext, useContext, useEffect, useState, ReactNode } from 'react';
74
+ import { TGTAuthClient, TGTUser } from 'tgtone-auth-client';
75
+
76
+ interface AuthContextType {
77
+ user: TGTUser | null;
78
+ loading: boolean;
79
+ logout: () => Promise<void>;
80
+ hasRole: (appName: string, roleName: string) => boolean;
81
+ hasAccessToApp: (appName: string) => boolean;
82
+ getRoles: (appName: string) => string[];
83
+ }
84
+
85
+ const AuthContext = createContext<AuthContextType | null>(null);
86
+
87
+ // Singleton del cliente
88
+ let authClient: TGTAuthClient | null = null;
89
+
90
+ const getAuthClient = (): TGTAuthClient => {
91
+ if (!authClient) {
92
+ authClient = new TGTAuthClient({
93
+ // ✅ URL unificada con reverse proxy
94
+ identityUrl: 'https://identity.tgtone.cl',
95
+ appDomain: window.location.hostname,
96
+ debug: import.meta.env.DEV
97
+ });
98
+ }
99
+ return authClient;
100
+ };
101
+
102
+ export function AuthProvider({ children }: { children: ReactNode }) {
103
+ const [user, setUser] = useState<TGTUser | null>(null);
104
+ const [loading, setLoading] = useState(true);
105
+
106
+ useEffect(() => {
107
+ const initAuth = async () => {
108
+ try {
109
+ const auth = getAuthClient();
110
+ const currentUser = await auth.checkSession();
111
+ setUser(currentUser);
112
+ } catch (error) {
113
+ console.error('Error checking session:', error);
114
+ setUser(null);
115
+ } finally {
116
+ setLoading(false);
117
+ }
118
+ };
119
+
120
+ initAuth();
121
+ }, []);
122
+
123
+ const logout = async () => {
124
+ const auth = getAuthClient();
125
+ await auth.logout();
126
+ setUser(null);
127
+ };
128
+
129
+ const hasRole = (appName: string, roleName: string) => {
130
+ const auth = getAuthClient();
131
+ return auth.hasRole(appName, roleName);
132
+ };
133
+
134
+ const hasAccessToApp = (appName: string) => {
135
+ const auth = getAuthClient();
136
+ return auth.hasAccessToApp(appName);
137
+ };
138
+
139
+ const getRoles = (appName: string) => {
140
+ const auth = getAuthClient();
141
+ return auth.getRoles(appName);
142
+ };
143
+
144
+ return (
145
+ <AuthContext.Provider value={{
146
+ user,
147
+ loading,
148
+ logout,
149
+ hasRole,
150
+ hasAccessToApp,
151
+ getRoles
152
+ }}>
153
+ {children}
154
+ </AuthContext.Provider>
155
+ );
156
+ }
157
+
158
+ export function useAuth() {
159
+ const context = useContext(AuthContext);
160
+ if (!context) {
161
+ throw new Error('useAuth debe usarse dentro de AuthProvider');
162
+ }
163
+ return context;
164
+ }
165
+ ```
166
+
167
+ ### 2. ProtectedRoute.tsx (Ya está bien implementado)
168
+
169
+ ```typescript
170
+ import { ReactNode } from 'react';
171
+ import { useAuth } from '@/contexts/AuthContext';
172
+ import { Card, CardContent } from '@/components/ui/card';
173
+
174
+ interface ProtectedRouteProps {
175
+ children: ReactNode;
176
+ requiredApp?: string;
177
+ requiredRole?: string;
178
+ }
179
+
180
+ export function ProtectedRoute({
181
+ children,
182
+ requiredApp,
183
+ requiredRole
184
+ }: ProtectedRouteProps) {
185
+ const { user, loading, hasRole, hasAccessToApp } = useAuth();
186
+
187
+ // Mostrar loading mientras verifica sesión
188
+ if (loading) {
189
+ return (
190
+ <div className="min-h-screen flex items-center justify-center">
191
+ <Card className="w-full max-w-md">
192
+ <CardContent className="pt-6">
193
+ <div className="flex flex-col items-center space-y-4">
194
+ <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-primary"></div>
195
+ <p className="text-muted-foreground">Verificando autenticación...</p>
196
+ </div>
197
+ </CardContent>
198
+ </Card>
199
+ </div>
200
+ );
201
+ }
202
+
203
+ // Si no hay usuario, el SDK ya está redirigiendo a Identity
204
+ if (!user) {
205
+ return null;
206
+ }
207
+
208
+ // Verificar acceso a la app
209
+ if (requiredApp && !hasAccessToApp(requiredApp)) {
210
+ return (
211
+ <div className="min-h-screen flex items-center justify-center">
212
+ <Card className="w-full max-w-md">
213
+ <CardContent className="pt-6">
214
+ <h2 className="text-xl font-semibold text-destructive">
215
+ Acceso Denegado
216
+ </h2>
217
+ <p className="text-muted-foreground">
218
+ No tienes permisos para acceder a esta aplicación.
219
+ </p>
220
+ </CardContent>
221
+ </Card>
222
+ </div>
223
+ );
224
+ }
225
+
226
+ // Verificar rol específico
227
+ if (requiredApp && requiredRole && !hasRole(requiredApp, requiredRole)) {
228
+ return (
229
+ <div className="min-h-screen flex items-center justify-center">
230
+ <Card className="w-full max-w-md">
231
+ <CardContent className="pt-6">
232
+ <h2 className="text-xl font-semibold text-destructive">
233
+ Permisos Insuficientes
234
+ </h2>
235
+ <p className="text-muted-foreground">
236
+ No tienes el rol necesario para acceder a esta página.
237
+ </p>
238
+ </CardContent>
239
+ </Card>
240
+ </div>
241
+ );
242
+ }
243
+
244
+ return <>{children}</>;
245
+ }
246
+ ```
247
+
248
+ ### 3. App.tsx (Sin rutas de login)
249
+
250
+ ```typescript
251
+ import { AuthProvider } from "./contexts/AuthContext";
252
+ import { ProtectedRoute } from "./components/ProtectedRoute";
253
+ import { BrowserRouter, Routes, Route } from "react-router-dom";
254
+
255
+ const App = () => (
256
+ <BrowserRouter>
257
+ <AuthProvider>
258
+ <Routes>
259
+ {/* Todas las rutas protegidas */}
260
+ <Route
261
+ path="/dashboard"
262
+ element={
263
+ <ProtectedRoute requiredApp="console">
264
+ <Dashboard />
265
+ </ProtectedRoute>
266
+ }
267
+ />
268
+
269
+ <Route
270
+ path="/dashboard/users"
271
+ element={
272
+ <ProtectedRoute requiredApp="console" requiredRole="admin">
273
+ <Users />
274
+ </ProtectedRoute>
275
+ }
276
+ />
277
+
278
+ {/* Más rutas... */}
279
+ </Routes>
280
+ </AuthProvider>
281
+ </BrowserRouter>
282
+ );
283
+ ```
284
+
285
+ ---
286
+
287
+ ## 🔄 Flujo de Autenticación (Lo que hace el SDK)
288
+
289
+ ```
290
+ 1. Usuario entra a console.tgtone.cl
291
+
292
+ 2. AuthContext se monta → ejecuta auth.checkSession()
293
+
294
+ 3. SDK busca token en URL (?token=...) o localStorage
295
+
296
+ 4. Si NO hay token → SDK redirige a identity.tgtone.cl/login?redirect=console.tgtone.cl
297
+
298
+ 5. Usuario hace login en Identity
299
+
300
+ 6. Identity redirige a console.tgtone.cl?token=eyJhbGci...
301
+
302
+ 7. SDK lee token de URL → lo guarda en localStorage
303
+
304
+ 8. SDK valida token con backend (GET /api/v1/auth/me)
305
+
306
+ 9. Si válido → setUser(userData) → App se renderiza
307
+
308
+ 10. Si inválido → SDK redirige a login nuevamente
309
+ ```
310
+
311
+ **Lovable NO debe intervenir en este flujo. Todo lo maneja el SDK.**
312
+
313
+ ---
314
+
315
+ ## 🧪 Testing Local (Sin Login)
316
+
317
+ Para desarrollo rápido sin pasar por el flujo completo:
318
+
319
+ ```typescript
320
+ // En consola del browser o en código temporal
321
+ const testToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'; // Token de curl
322
+ localStorage.setItem('tgtone_auth_token', testToken);
323
+ window.location.reload();
324
+ ```
325
+
326
+ **Obtener token de prueba:**
327
+ ```bash
328
+ curl -X POST https://tgtone-identity-backend-1086175589490.us-central1.run.app/api/v1/auth/login \
329
+ -H "Content-Type: application/json" \
330
+ -d '{"email": "console@tgtone.cl", "password": "Tgt123."}'
331
+ ```
332
+
333
+ ---
334
+
335
+ ## 📦 Dependencias Necesarias
336
+
337
+ ```json
338
+ {
339
+ "dependencies": {
340
+ "tgtone-auth-client": "^1.0.2"
341
+ }
342
+ }
343
+ ```
344
+
345
+ **NO se necesita:**
346
+ - `@supabase/supabase-js`
347
+ - Ningún otro cliente de auth
348
+
349
+ ---
350
+
351
+ ## 🎯 Verificación de Roles
352
+
353
+ ```typescript
354
+ // En cualquier componente
355
+ import { useAuth } from '@/contexts/AuthContext';
356
+
357
+ function MyComponent() {
358
+ const { user, hasRole, getRoles } = useAuth();
359
+
360
+ // Verificar rol específico
361
+ if (hasRole('console', 'admin')) {
362
+ return <AdminPanel />;
363
+ }
364
+
365
+ // Obtener todos los roles
366
+ const roles = getRoles('console'); // ['owner', 'admin']
367
+
368
+ // Acceder a datos del usuario
369
+ console.log(user.email); // console@tgtone.cl
370
+ console.log(user.tenant_name); // Console Only Tenant
371
+ console.log(user.roles); // { console: ['owner', 'admin'] }
372
+ }
373
+ ```
374
+
375
+ ---
376
+
377
+ ## 🚨 Errores Comunes
378
+
379
+ ### Error: "Failed to fetch"
380
+ **Causa**: CORS o backend offline
381
+ **Solución**: Verificar que backend esté corriendo y CORS permita tu origen
382
+
383
+ ### Error: "No se puede leer token"
384
+ **Causa**: localStorage bloqueado o sesión expirada
385
+ **Solución**: Limpiar localStorage y volver a hacer login
386
+
387
+ ### Error: "Bucle infinito de redirecciones"
388
+ **Causa**: Token inválido guardado en localStorage
389
+ **Solución**:
390
+ ```typescript
391
+ localStorage.removeItem('tgtone_auth_token');
392
+ ```
393
+
394
+ ---
395
+
396
+ ## 📚 Estructura de Archivos
397
+
398
+ ```
399
+ src/
400
+ ├── contexts/
401
+ │ └── AuthContext.tsx ✅ Solo este archivo
402
+ ├── components/
403
+ │ └── ProtectedRoute.tsx ✅ Ya implementado
404
+ └── App.tsx ✅ Wrapper con AuthProvider
405
+
406
+ ❌ NO crear:
407
+ ├── services/
408
+ │ └── mockAuth.service.ts ❌ Eliminar
409
+ ├── pages/
410
+ │ ├── Login.tsx ❌ Eliminar
411
+ │ └── Auth.tsx ❌ Eliminar
412
+ ```
413
+
414
+ ---
415
+
416
+ ## 🎯 Resumen para Lovable
417
+
418
+ **Cuando Lovable necesite implementar autenticación:**
419
+
420
+ 1. ✅ Instalar: `npm install tgtone-auth-client`
421
+ 2. ✅ Copiar `AuthContext.tsx` de este documento (sin cambios)
422
+ 3. ✅ Usar `ProtectedRoute` para rutas privadas
423
+ 4. ✅ Usar `useAuth()` hook en componentes
424
+ 5. ❌ NO crear sistema mock
425
+ 6. ❌ NO crear páginas de login
426
+ 7. ❌ NO agregar variables de entorno personalizadas
427
+ 8. ❌ NO manejar tokens manualmente
428
+
429
+ **El SDK hace TODO el trabajo de autenticación.**
430
+
431
+ ---
432
+
433
+ **Última actualización:** 2025-10-17
@@ -0,0 +1,11 @@
1
+ {
2
+ "folders": [
3
+ {
4
+ "path": "../.."
5
+ },
6
+ {
7
+ "path": "../../../tgtone-console"
8
+ }
9
+ ],
10
+ "settings": {}
11
+ }
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@tgtone/auth-sdk",
3
+ "version": "1.0.0",
4
+ "description": "SDK de autenticación JWT + Bearer Token para el ecosistema TGT One",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "prepublishOnly": "npm run build",
10
+ "clean": "rm -rf dist"
11
+ },
12
+ "keywords": [
13
+ "sso",
14
+ "authentication",
15
+ "tgtone",
16
+ "jwt",
17
+ "oauth",
18
+ "identity"
19
+ ],
20
+ "author": "TGT Technology",
21
+ "license": "MIT",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/tgt-technology/tgtone-console.git",
25
+ "directory": "packages/auth-sdk"
26
+ },
27
+ "publishConfig": {
28
+ "registry": "https://registry.npmjs.org",
29
+ "access": "public"
30
+ },
31
+ "files": [
32
+ "dist",
33
+ "README.md",
34
+ "docs"
35
+ ],
36
+ "dependencies": {
37
+ "jwt-decode": "^4.0.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/react": "^18.2.0",
41
+ "typescript": "^5.3.0"
42
+ },
43
+ "peerDependencies": {
44
+ "react": "^18.0.0"
45
+ },
46
+ "peerDependenciesMeta": {
47
+ "react": {
48
+ "optional": true
49
+ }
50
+ }
51
+ }