@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.
- package/README.md +140 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/react-hook.d.ts +13 -0
- package/dist/react-hook.d.ts.map +1 -0
- package/dist/react-hook.js +38 -0
- package/dist/react-hook.js.map +1 -0
- package/dist/tgtone-auth-client.d.ts +70 -0
- package/dist/tgtone-auth-client.d.ts.map +1 -0
- package/dist/tgtone-auth-client.js +305 -0
- package/dist/tgtone-auth-client.js.map +1 -0
- package/docs/INTEGRATION_EXAMPLES.md +536 -0
- package/docs/LOVABLE_QUICK_START.md +478 -0
- package/docs/NPM_PUBLISH.md +131 -0
- package/docs/README.md +83 -0
- package/docs/SDK_FINAL_STATUS.md +88 -0
- package/docs/SDK_INTEGRATION_RULES.md +433 -0
- package/docs/tgtone-identity-auth.code-workspace +11 -0
- package/package.json +51 -0
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
# 🔧 Ejemplos de Integración por Framework
|
|
2
|
+
|
|
3
|
+
Guía paso a paso para integrar TGT One Auth en diferentes frameworks.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 📘 React (Vite)
|
|
8
|
+
|
|
9
|
+
### **1. Copiar archivos**
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# En tu proyecto React
|
|
13
|
+
mkdir -p src/lib/auth
|
|
14
|
+
cp tgtone-auth-client.ts src/lib/auth/
|
|
15
|
+
cp react-hook.tsx src/lib/auth/
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### **2. Crear contexto de autenticación**
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
// src/contexts/AuthContext.tsx
|
|
22
|
+
import { createContext, useContext } from 'react';
|
|
23
|
+
import { useTGTAuth, UseTGTAuthResult } from '@/lib/auth/react-hook';
|
|
24
|
+
|
|
25
|
+
const AuthContext = createContext<UseTGTAuthResult | null>(null);
|
|
26
|
+
|
|
27
|
+
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|
28
|
+
const auth = useTGTAuth({
|
|
29
|
+
identityUrl: 'https://identity.tgtone.cl',
|
|
30
|
+
appDomain: 'zenith.tgtone.cl', // Cambiar según tu app
|
|
31
|
+
debug: import.meta.env.DEV
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<AuthContext.Provider value={auth}>
|
|
36
|
+
{children}
|
|
37
|
+
</AuthContext.Provider>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const useAuth = () => {
|
|
42
|
+
const context = useContext(AuthContext);
|
|
43
|
+
if (!context) {
|
|
44
|
+
throw new Error('useAuth debe usarse dentro de AuthProvider');
|
|
45
|
+
}
|
|
46
|
+
return context;
|
|
47
|
+
};
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### **3. Envolver tu app**
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
// src/main.tsx
|
|
54
|
+
import { StrictMode } from 'react';
|
|
55
|
+
import { createRoot } from 'react-dom/client';
|
|
56
|
+
import { AuthProvider } from './contexts/AuthContext';
|
|
57
|
+
import App from './App';
|
|
58
|
+
|
|
59
|
+
createRoot(document.getElementById('root')!).render(
|
|
60
|
+
<StrictMode>
|
|
61
|
+
<AuthProvider>
|
|
62
|
+
<App />
|
|
63
|
+
</AuthProvider>
|
|
64
|
+
</StrictMode>,
|
|
65
|
+
);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### **4. Usar en componentes**
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
// src/App.tsx
|
|
72
|
+
import { useAuth } from './contexts/AuthContext';
|
|
73
|
+
|
|
74
|
+
function App() {
|
|
75
|
+
const { user, loading, logout, hasRole } = useAuth();
|
|
76
|
+
|
|
77
|
+
if (loading) {
|
|
78
|
+
return (
|
|
79
|
+
<div className="flex items-center justify-center min-h-screen">
|
|
80
|
+
<div className="animate-spin rounded-full h-32 w-32 border-b-2 border-gray-900"></div>
|
|
81
|
+
</div>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (!user) {
|
|
86
|
+
// Ya está redirigiendo al login
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<div className="container mx-auto p-4">
|
|
92
|
+
<nav className="flex justify-between items-center mb-8">
|
|
93
|
+
<h1 className="text-2xl font-bold">Zenith CRM</h1>
|
|
94
|
+
<div className="flex items-center gap-4">
|
|
95
|
+
<span>{user.name}</span>
|
|
96
|
+
<span className="text-sm text-gray-600">{user.tenant_name}</span>
|
|
97
|
+
<button
|
|
98
|
+
onClick={logout}
|
|
99
|
+
className="px-4 py-2 bg-red-500 text-white rounded"
|
|
100
|
+
>
|
|
101
|
+
Cerrar sesión
|
|
102
|
+
</button>
|
|
103
|
+
</div>
|
|
104
|
+
</nav>
|
|
105
|
+
|
|
106
|
+
{hasRole('zenith', 'admin') && (
|
|
107
|
+
<div className="bg-yellow-100 p-4 rounded mb-4">
|
|
108
|
+
<h2>Panel de Administración</h2>
|
|
109
|
+
</div>
|
|
110
|
+
)}
|
|
111
|
+
|
|
112
|
+
<main>
|
|
113
|
+
{/* Tu contenido aquí */}
|
|
114
|
+
</main>
|
|
115
|
+
</div>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export default App;
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 📗 Vue 3 (Vite)
|
|
125
|
+
|
|
126
|
+
### **1. Copiar archivo**
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
mkdir -p src/lib/auth
|
|
130
|
+
cp tgtone-auth-client.ts src/lib/auth/
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### **2. Crear composable**
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
// src/composables/useAuth.ts
|
|
137
|
+
import { ref, onMounted } from 'vue';
|
|
138
|
+
import { TGTAuthClient, type TGTUser } from '@/lib/auth/tgtone-auth-client';
|
|
139
|
+
|
|
140
|
+
const authClient = new TGTAuthClient({
|
|
141
|
+
identityUrl: 'https://identity.tgtone.cl',
|
|
142
|
+
appDomain: 'baco.tgtone.cl', // Cambiar según tu app
|
|
143
|
+
debug: import.meta.env.DEV
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const user = ref<TGTUser | null>(null);
|
|
147
|
+
const loading = ref(true);
|
|
148
|
+
|
|
149
|
+
export function useAuth() {
|
|
150
|
+
onMounted(async () => {
|
|
151
|
+
user.value = await authClient.checkSession();
|
|
152
|
+
loading.value = false;
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
const logout = async () => {
|
|
156
|
+
await authClient.logout();
|
|
157
|
+
user.value = null;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const hasRole = (appName: string, roleName: string) => {
|
|
161
|
+
return authClient.hasRole(appName, roleName);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
user,
|
|
166
|
+
loading,
|
|
167
|
+
logout,
|
|
168
|
+
hasRole,
|
|
169
|
+
authClient
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### **3. Usar en App.vue**
|
|
175
|
+
|
|
176
|
+
```vue
|
|
177
|
+
<!-- src/App.vue -->
|
|
178
|
+
<template>
|
|
179
|
+
<div v-if="loading" class="loading">
|
|
180
|
+
<div class="spinner"></div>
|
|
181
|
+
</div>
|
|
182
|
+
|
|
183
|
+
<div v-else-if="user" class="app">
|
|
184
|
+
<nav class="navbar">
|
|
185
|
+
<h1>Baco Wine Management</h1>
|
|
186
|
+
<div class="user-info">
|
|
187
|
+
<span>{{ user.name }}</span>
|
|
188
|
+
<span class="tenant">{{ user.tenant_name }}</span>
|
|
189
|
+
<button @click="logout" class="logout-btn">
|
|
190
|
+
Cerrar sesión
|
|
191
|
+
</button>
|
|
192
|
+
</div>
|
|
193
|
+
</nav>
|
|
194
|
+
|
|
195
|
+
<div v-if="hasRole('baco', 'admin')" class="admin-panel">
|
|
196
|
+
Panel de Administración
|
|
197
|
+
</div>
|
|
198
|
+
|
|
199
|
+
<main>
|
|
200
|
+
<!-- Tu contenido aquí -->
|
|
201
|
+
</main>
|
|
202
|
+
</div>
|
|
203
|
+
</template>
|
|
204
|
+
|
|
205
|
+
<script setup lang="ts">
|
|
206
|
+
import { useAuth } from './composables/useAuth';
|
|
207
|
+
|
|
208
|
+
const { user, loading, logout, hasRole } = useAuth();
|
|
209
|
+
</script>
|
|
210
|
+
|
|
211
|
+
<style scoped>
|
|
212
|
+
.loading {
|
|
213
|
+
display: flex;
|
|
214
|
+
justify-content: center;
|
|
215
|
+
align-items: center;
|
|
216
|
+
height: 100vh;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.spinner {
|
|
220
|
+
border: 4px solid #f3f3f3;
|
|
221
|
+
border-top: 4px solid #3498db;
|
|
222
|
+
border-radius: 50%;
|
|
223
|
+
width: 40px;
|
|
224
|
+
height: 40px;
|
|
225
|
+
animation: spin 1s linear infinite;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
@keyframes spin {
|
|
229
|
+
0% { transform: rotate(0deg); }
|
|
230
|
+
100% { transform: rotate(360deg); }
|
|
231
|
+
}
|
|
232
|
+
</style>
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## 📙 Next.js 14 (App Router)
|
|
238
|
+
|
|
239
|
+
### **1. Copiar archivo**
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
mkdir -p lib/auth
|
|
243
|
+
cp tgtone-auth-client.ts lib/auth/
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### **2. Crear Provider**
|
|
247
|
+
|
|
248
|
+
```tsx
|
|
249
|
+
// app/providers/auth-provider.tsx
|
|
250
|
+
'use client';
|
|
251
|
+
|
|
252
|
+
import { createContext, useContext, useEffect, useState, ReactNode } from 'react';
|
|
253
|
+
import { TGTAuthClient, type TGTUser } from '@/lib/auth/tgtone-auth-client';
|
|
254
|
+
|
|
255
|
+
interface AuthContextType {
|
|
256
|
+
user: TGTUser | null;
|
|
257
|
+
loading: boolean;
|
|
258
|
+
logout: () => Promise<void>;
|
|
259
|
+
hasRole: (appName: string, roleName: string) => boolean;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const AuthContext = createContext<AuthContextType | null>(null);
|
|
263
|
+
|
|
264
|
+
export function AuthProvider({ children }: { children: ReactNode }) {
|
|
265
|
+
const [user, setUser] = useState<TGTUser | null>(null);
|
|
266
|
+
const [loading, setLoading] = useState(true);
|
|
267
|
+
|
|
268
|
+
const authClient = new TGTAuthClient({
|
|
269
|
+
identityUrl: 'https://identity.tgtone.cl',
|
|
270
|
+
appDomain: 'console.tgtone.cl', // Cambiar según tu app
|
|
271
|
+
debug: process.env.NODE_ENV === 'development'
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
useEffect(() => {
|
|
275
|
+
async function checkAuth() {
|
|
276
|
+
const authenticatedUser = await authClient.checkSession();
|
|
277
|
+
setUser(authenticatedUser);
|
|
278
|
+
setLoading(false);
|
|
279
|
+
}
|
|
280
|
+
checkAuth();
|
|
281
|
+
}, []);
|
|
282
|
+
|
|
283
|
+
const logout = async () => {
|
|
284
|
+
await authClient.logout();
|
|
285
|
+
setUser(null);
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
const hasRole = (appName: string, roleName: string) => {
|
|
289
|
+
return authClient.hasRole(appName, roleName);
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
return (
|
|
293
|
+
<AuthContext.Provider value={{ user, loading, logout, hasRole }}>
|
|
294
|
+
{children}
|
|
295
|
+
</AuthContext.Provider>
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export const useAuth = () => {
|
|
300
|
+
const context = useContext(AuthContext);
|
|
301
|
+
if (!context) {
|
|
302
|
+
throw new Error('useAuth debe usarse dentro de AuthProvider');
|
|
303
|
+
}
|
|
304
|
+
return context;
|
|
305
|
+
};
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### **3. Envolver en layout**
|
|
309
|
+
|
|
310
|
+
```tsx
|
|
311
|
+
// app/layout.tsx
|
|
312
|
+
import { AuthProvider } from './providers/auth-provider';
|
|
313
|
+
import './globals.css';
|
|
314
|
+
|
|
315
|
+
export const metadata = {
|
|
316
|
+
title: 'TGT One Console',
|
|
317
|
+
description: 'Console de administración TGT One',
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
export default function RootLayout({
|
|
321
|
+
children,
|
|
322
|
+
}: {
|
|
323
|
+
children: React.ReactNode;
|
|
324
|
+
}) {
|
|
325
|
+
return (
|
|
326
|
+
<html lang="es">
|
|
327
|
+
<body>
|
|
328
|
+
<AuthProvider>
|
|
329
|
+
{children}
|
|
330
|
+
</AuthProvider>
|
|
331
|
+
</body>
|
|
332
|
+
</html>
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### **4. Usar en páginas**
|
|
338
|
+
|
|
339
|
+
```tsx
|
|
340
|
+
// app/page.tsx
|
|
341
|
+
'use client';
|
|
342
|
+
|
|
343
|
+
import { useAuth } from './providers/auth-provider';
|
|
344
|
+
|
|
345
|
+
export default function HomePage() {
|
|
346
|
+
const { user, loading, logout, hasRole } = useAuth();
|
|
347
|
+
|
|
348
|
+
if (loading) {
|
|
349
|
+
return <div className="flex h-screen items-center justify-center">
|
|
350
|
+
<div className="animate-spin rounded-full h-32 w-32 border-b-2 border-gray-900"></div>
|
|
351
|
+
</div>;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (!user) {
|
|
355
|
+
return null; // Redirigiendo
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return (
|
|
359
|
+
<div className="container mx-auto p-8">
|
|
360
|
+
<nav className="flex justify-between items-center mb-8">
|
|
361
|
+
<h1 className="text-3xl font-bold">TGT One Console</h1>
|
|
362
|
+
<div className="flex items-center gap-4">
|
|
363
|
+
<div className="text-right">
|
|
364
|
+
<p className="font-medium">{user.name}</p>
|
|
365
|
+
<p className="text-sm text-gray-600">{user.tenant_name}</p>
|
|
366
|
+
</div>
|
|
367
|
+
<button
|
|
368
|
+
onClick={logout}
|
|
369
|
+
className="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600"
|
|
370
|
+
>
|
|
371
|
+
Cerrar sesión
|
|
372
|
+
</button>
|
|
373
|
+
</div>
|
|
374
|
+
</nav>
|
|
375
|
+
|
|
376
|
+
{hasRole('console', 'owner') && (
|
|
377
|
+
<div className="bg-blue-100 p-4 rounded mb-6">
|
|
378
|
+
<h2 className="font-bold">Configuración de Owner</h2>
|
|
379
|
+
</div>
|
|
380
|
+
)}
|
|
381
|
+
|
|
382
|
+
<main>
|
|
383
|
+
{/* Tu contenido */}
|
|
384
|
+
</main>
|
|
385
|
+
</div>
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## 📕 Angular 17+
|
|
393
|
+
|
|
394
|
+
### **1. Copiar archivo**
|
|
395
|
+
|
|
396
|
+
```bash
|
|
397
|
+
mkdir -p src/app/services/auth
|
|
398
|
+
cp tgtone-auth-client.ts src/app/services/auth/
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### **2. Crear servicio**
|
|
402
|
+
|
|
403
|
+
```typescript
|
|
404
|
+
// src/app/services/auth/auth.service.ts
|
|
405
|
+
import { Injectable } from '@angular/core';
|
|
406
|
+
import { BehaviorSubject, Observable } from 'rxjs';
|
|
407
|
+
import { TGTAuthClient, TGTUser } from './tgtone-auth-client';
|
|
408
|
+
|
|
409
|
+
@Injectable({
|
|
410
|
+
providedIn: 'root'
|
|
411
|
+
})
|
|
412
|
+
export class AuthService {
|
|
413
|
+
private authClient: TGTAuthClient;
|
|
414
|
+
private userSubject = new BehaviorSubject<TGTUser | null>(null);
|
|
415
|
+
private loadingSubject = new BehaviorSubject<boolean>(true);
|
|
416
|
+
|
|
417
|
+
public user$: Observable<TGTUser | null> = this.userSubject.asObservable();
|
|
418
|
+
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
|
419
|
+
|
|
420
|
+
constructor() {
|
|
421
|
+
this.authClient = new TGTAuthClient({
|
|
422
|
+
identityUrl: 'https://identity.tgtone.cl',
|
|
423
|
+
appDomain: 'zenith.tgtone.cl', // Cambiar según tu app
|
|
424
|
+
debug: !environment.production
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
this.checkSession();
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
private async checkSession() {
|
|
431
|
+
try {
|
|
432
|
+
const user = await this.authClient.checkSession();
|
|
433
|
+
this.userSubject.next(user);
|
|
434
|
+
} catch (error) {
|
|
435
|
+
console.error('Error checking session:', error);
|
|
436
|
+
this.userSubject.next(null);
|
|
437
|
+
} finally {
|
|
438
|
+
this.loadingSubject.next(false);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
async logout() {
|
|
443
|
+
await this.authClient.logout();
|
|
444
|
+
this.userSubject.next(null);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
hasRole(appName: string, roleName: string): boolean {
|
|
448
|
+
return this.authClient.hasRole(appName, roleName);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
get currentUser(): TGTUser | null {
|
|
452
|
+
return this.userSubject.value;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### **3. Usar en componentes**
|
|
458
|
+
|
|
459
|
+
```typescript
|
|
460
|
+
// src/app/app.component.ts
|
|
461
|
+
import { Component } from '@angular/core';
|
|
462
|
+
import { AuthService } from './services/auth/auth.service';
|
|
463
|
+
|
|
464
|
+
@Component({
|
|
465
|
+
selector: 'app-root',
|
|
466
|
+
template: `
|
|
467
|
+
<div *ngIf="authService.loading$ | async" class="loading">
|
|
468
|
+
<div class="spinner"></div>
|
|
469
|
+
</div>
|
|
470
|
+
|
|
471
|
+
<div *ngIf="(authService.user$ | async) as user" class="app">
|
|
472
|
+
<nav class="navbar">
|
|
473
|
+
<h1>Zenith CRM</h1>
|
|
474
|
+
<div class="user-info">
|
|
475
|
+
<span>{{ user.name }}</span>
|
|
476
|
+
<span class="tenant">{{ user.tenant_name }}</span>
|
|
477
|
+
<button (click)="logout()" class="logout-btn">
|
|
478
|
+
Cerrar sesión
|
|
479
|
+
</button>
|
|
480
|
+
</div>
|
|
481
|
+
</nav>
|
|
482
|
+
|
|
483
|
+
<div *ngIf="authService.hasRole('zenith', 'admin')" class="admin-panel">
|
|
484
|
+
Panel de Administración
|
|
485
|
+
</div>
|
|
486
|
+
|
|
487
|
+
<router-outlet></router-outlet>
|
|
488
|
+
</div>
|
|
489
|
+
`,
|
|
490
|
+
styleUrls: ['./app.component.css']
|
|
491
|
+
})
|
|
492
|
+
export class AppComponent {
|
|
493
|
+
constructor(public authService: AuthService) {}
|
|
494
|
+
|
|
495
|
+
logout() {
|
|
496
|
+
this.authService.logout();
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
---
|
|
502
|
+
|
|
503
|
+
## 🔑 Variables de Entorno por App
|
|
504
|
+
|
|
505
|
+
### **Zenith (CRM)**
|
|
506
|
+
```env
|
|
507
|
+
VITE_APP_DOMAIN=zenith.tgtone.cl
|
|
508
|
+
VITE_IDENTITY_URL=https://identity.tgtone.cl
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
### **Baco (Wine Management)**
|
|
512
|
+
```env
|
|
513
|
+
VITE_APP_DOMAIN=baco.tgtone.cl
|
|
514
|
+
VITE_IDENTITY_URL=https://identity.tgtone.cl
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### **Console (Admin)**
|
|
518
|
+
```env
|
|
519
|
+
VITE_APP_DOMAIN=console.tgtone.cl
|
|
520
|
+
VITE_IDENTITY_URL=https://identity.tgtone.cl
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
---
|
|
524
|
+
|
|
525
|
+
## ✅ Checklist de Integración
|
|
526
|
+
|
|
527
|
+
- [ ] Copiar `tgtone-auth-client.ts` al proyecto
|
|
528
|
+
- [ ] Configurar variables de entorno
|
|
529
|
+
- [ ] Crear wrapper/provider según framework
|
|
530
|
+
- [ ] Implementar UI de loading
|
|
531
|
+
- [ ] Implementar botón de logout
|
|
532
|
+
- [ ] Probar flujo de login/logout
|
|
533
|
+
- [ ] Probar SSO entre apps
|
|
534
|
+
- [ ] Verificar roles y permisos
|
|
535
|
+
- [ ] Manejar estados de error
|
|
536
|
+
- [ ] Documentar para el equipo
|