@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
package/README.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# 🔐 TGT One Auth Client SDK
|
|
2
|
+
|
|
3
|
+
SDK para integrar autenticación JWT + Bearer Token en aplicaciones del ecosistema TGT One.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 📦 Instalación
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @tgtone/auth-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 🚀 Quick Start
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { TGTAuthClient } from '@tgtone/auth-sdk';
|
|
19
|
+
|
|
20
|
+
const auth = new TGTAuthClient({
|
|
21
|
+
identityUrl: 'https://identity.tgtone.cl',
|
|
22
|
+
appDomain: window.location.hostname,
|
|
23
|
+
debug: true
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Verificar sesión (v1.1+)
|
|
27
|
+
const session = await auth.checkSession();
|
|
28
|
+
if (session) {
|
|
29
|
+
console.log('Usuario:', session.user.email);
|
|
30
|
+
console.log('Tenant:', session.tenantName);
|
|
31
|
+
console.log('Roles:', session.roles);
|
|
32
|
+
console.log('Expira:', session.expiresAt);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 📋 API Principal
|
|
39
|
+
|
|
40
|
+
### `checkSession(): Promise<TGTSession | null>`
|
|
41
|
+
Verifica sesión, valida JWT localmente (tenant_id + expiración), guarda en localStorage y valida con backend.
|
|
42
|
+
|
|
43
|
+
**Retorna:** `TGTSession` con `{ user, tenantId, tenantName, roles, expiresAt }` o `null`.
|
|
44
|
+
|
|
45
|
+
### `getSession(): TGTSession | null`
|
|
46
|
+
Obtiene sesión completa en memoria.
|
|
47
|
+
|
|
48
|
+
### `getTenantId(): string | null`
|
|
49
|
+
Obtiene ID del tenant actual.
|
|
50
|
+
|
|
51
|
+
### `logout(): Promise<void>`
|
|
52
|
+
Cierra sesión y limpia localStorage.
|
|
53
|
+
|
|
54
|
+
### `hasRole(app: string, role: string): boolean`
|
|
55
|
+
Verifica si tiene un rol.
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
if (auth.hasRole('console', 'admin')) {
|
|
59
|
+
// Mostrar admin panel
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 🔄 Cómo Funciona
|
|
66
|
+
|
|
67
|
+
1. Usuario visita tu app
|
|
68
|
+
2. `checkSession()` no encuentra token → redirige a Identity
|
|
69
|
+
3. Usuario hace login en Identity
|
|
70
|
+
4. Identity redirige a `tu-app?token=eyJhbGci...`
|
|
71
|
+
5. SDK lee token de URL y guarda en localStorage
|
|
72
|
+
6. SDK valida token con `Authorization: Bearer ...`
|
|
73
|
+
7. Retorna usuario
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 📚 Documentación Completa
|
|
78
|
+
|
|
79
|
+
- **[docs/LOVABLE_QUICK_START.md](./docs/LOVABLE_QUICK_START.md)** - Guía para Lovable/React
|
|
80
|
+
- **[docs/INTEGRATION_EXAMPLES.md](./docs/INTEGRATION_EXAMPLES.md)** - Ejemplos para otros frameworks
|
|
81
|
+
- **[docs/CHANGELOG.md](./docs/CHANGELOG.md)** - Historial de cambios
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 🧪 Testing Rápido
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
// 1. Obtener token con curl
|
|
89
|
+
// curl -X POST https://identity-backend.run.app/api/v1/auth/login \
|
|
90
|
+
// -d '{"email": "user@tgtone.cl", "password": "pass"}'
|
|
91
|
+
|
|
92
|
+
// 2. Guardar manualmente
|
|
93
|
+
localStorage.setItem('tgtone_auth_token', 'eyJhbGci...');
|
|
94
|
+
|
|
95
|
+
// 3. Usar
|
|
96
|
+
const user = await auth.checkSession();
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 👤 Estructura del Usuario
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
interface TGTUser {
|
|
105
|
+
sub: string; // ID
|
|
106
|
+
email: string;
|
|
107
|
+
name: string;
|
|
108
|
+
tenant_id: string;
|
|
109
|
+
tenant_name: string;
|
|
110
|
+
roles: Record<string, string[]>; // { console: ['owner'], zenith: ['admin'] }
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## ⚙️ Configuración
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
interface TGTAuthConfig {
|
|
120
|
+
identityUrl: string; // URL del backend Identity
|
|
121
|
+
appDomain: string; // Dominio de tu app
|
|
122
|
+
onAuthSuccess?: (user: TGTUser) => void;
|
|
123
|
+
onAuthFailure?: () => void;
|
|
124
|
+
debug?: boolean;
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 🔐 Seguridad
|
|
131
|
+
|
|
132
|
+
- **Token storage**: localStorage (`tgtone_auth_token`)
|
|
133
|
+
- **Transport**: Authorization header con Bearer token
|
|
134
|
+
- **Validation**: Backend valida JWT signature
|
|
135
|
+
- **No cookies**: Todo con Bearer tokens
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
**Versión:** 1.0.1
|
|
140
|
+
**Última actualización:** 2025-10-16
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { TGTAuthClient } from './tgtone-auth-client';
|
|
2
|
+
export { useTGTAuth } from './react-hook';
|
|
3
|
+
export type { TGTUser, TGTAuthConfig, SessionResponse, } from './tgtone-auth-client';
|
|
4
|
+
export type { UseTGTAuthResult } from './react-hook';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,YAAY,EACV,OAAO,EACP,aAAa,EACb,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAE9B,YAAY,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { TGTAuthClient, TGTSession, TGTAuthConfig } from './tgtone-auth-client';
|
|
2
|
+
export interface UseTGTAuthResult {
|
|
3
|
+
session: TGTSession | null;
|
|
4
|
+
loading: boolean;
|
|
5
|
+
logout: () => Promise<void>;
|
|
6
|
+
hasRole: (appName: string, roleName: string) => boolean;
|
|
7
|
+
getRoles: (appName: string) => string[];
|
|
8
|
+
hasAccessToApp: (appName: string) => boolean;
|
|
9
|
+
tenantId: string | null;
|
|
10
|
+
authClient: TGTAuthClient;
|
|
11
|
+
}
|
|
12
|
+
export declare function useTGTAuth(config: TGTAuthConfig): UseTGTAuthResult;
|
|
13
|
+
//# sourceMappingURL=react-hook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-hook.d.ts","sourceRoot":"","sources":["../react-hook.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAEhF,MAAM,WAAW,gBAAgB;IAE/B,OAAO,EAAE,UAAU,GAAG,IAAI,CAAC;IAG3B,OAAO,EAAE,OAAO,CAAC;IAGjB,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAG5B,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IAGxD,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;IAGxC,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IAG7C,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAGxB,UAAU,EAAE,aAAa,CAAC;CAC3B;AAmCD,wBAAgB,UAAU,CAAC,MAAM,EAAE,aAAa,GAAG,gBAAgB,CAoClE"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import { TGTAuthClient } from './tgtone-auth-client';
|
|
3
|
+
export function useTGTAuth(config) {
|
|
4
|
+
const [session, setSession] = useState(null);
|
|
5
|
+
const [loading, setLoading] = useState(true);
|
|
6
|
+
const [authClient] = useState(() => new TGTAuthClient(config));
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
async function validateSession() {
|
|
9
|
+
try {
|
|
10
|
+
const authenticatedSession = await authClient.checkSession();
|
|
11
|
+
setSession(authenticatedSession);
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
console.error('[useTGTAuth] Error validando sesión:', error);
|
|
15
|
+
setSession(null);
|
|
16
|
+
}
|
|
17
|
+
finally {
|
|
18
|
+
setLoading(false);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
validateSession();
|
|
22
|
+
}, [authClient]);
|
|
23
|
+
const logout = async () => {
|
|
24
|
+
await authClient.logout();
|
|
25
|
+
setSession(null);
|
|
26
|
+
};
|
|
27
|
+
return {
|
|
28
|
+
session,
|
|
29
|
+
loading,
|
|
30
|
+
logout,
|
|
31
|
+
hasRole: authClient.hasRole.bind(authClient),
|
|
32
|
+
getRoles: authClient.getRoles.bind(authClient),
|
|
33
|
+
hasAccessToApp: authClient.hasAccessToApp.bind(authClient),
|
|
34
|
+
tenantId: authClient.getTenantId(),
|
|
35
|
+
authClient,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=react-hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-hook.js","sourceRoot":"","sources":["../react-hook.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,aAAa,EAA6B,MAAM,sBAAsB,CAAC;AA6DhF,MAAM,UAAU,UAAU,CAAC,MAAqB;IAC9C,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAoB,IAAI,CAAC,CAAC;IAChE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,CAAC,UAAU,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;IAE/D,SAAS,CAAC,GAAG,EAAE;QACb,KAAK,UAAU,eAAe;YAC5B,IAAI,CAAC;gBACH,MAAM,oBAAoB,GAAG,MAAM,UAAU,CAAC,YAAY,EAAE,CAAC;gBAC7D,UAAU,CAAC,oBAAoB,CAAC,CAAC;YACnC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,KAAK,CAAC,CAAC;gBAC7D,UAAU,CAAC,IAAI,CAAC,CAAC;YACnB,CAAC;oBAAS,CAAC;gBACT,UAAU,CAAC,KAAK,CAAC,CAAC;YACpB,CAAC;QACH,CAAC;QAED,eAAe,EAAE,CAAC;IACpB,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IAEjB,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;QACxB,MAAM,UAAU,CAAC,MAAM,EAAE,CAAC;QAC1B,UAAU,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC,CAAC;IAEF,OAAO;QACL,OAAO;QACP,OAAO;QACP,MAAM;QACN,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;QAC5C,QAAQ,EAAE,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC;QAC9C,cAAc,EAAE,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC;QAC1D,QAAQ,EAAE,UAAU,CAAC,WAAW,EAAE;QAClC,UAAU;KACX,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export interface JWTPayload {
|
|
2
|
+
iss: string;
|
|
3
|
+
aud: string;
|
|
4
|
+
sub: string;
|
|
5
|
+
jti: string;
|
|
6
|
+
email: string;
|
|
7
|
+
email_verified: boolean;
|
|
8
|
+
name: string;
|
|
9
|
+
tenant_id: string;
|
|
10
|
+
tenant_name: string;
|
|
11
|
+
roles: Record<string, string[]>;
|
|
12
|
+
iat: number;
|
|
13
|
+
exp: number;
|
|
14
|
+
}
|
|
15
|
+
export interface TGTUser {
|
|
16
|
+
sub: string;
|
|
17
|
+
email: string;
|
|
18
|
+
email_verified: boolean;
|
|
19
|
+
name: string;
|
|
20
|
+
tenant_id: string;
|
|
21
|
+
tenant_name: string;
|
|
22
|
+
roles: Record<string, string[]>;
|
|
23
|
+
}
|
|
24
|
+
export interface TGTSession {
|
|
25
|
+
user: TGTUser;
|
|
26
|
+
tenantId: string;
|
|
27
|
+
tenantName: string;
|
|
28
|
+
expiresAt: Date;
|
|
29
|
+
}
|
|
30
|
+
export interface TGTAuthConfig {
|
|
31
|
+
identityUrl: string;
|
|
32
|
+
appDomain: string;
|
|
33
|
+
onAuthSuccess?: (session: TGTSession) => void;
|
|
34
|
+
onAuthFailure?: () => void;
|
|
35
|
+
debug?: boolean;
|
|
36
|
+
}
|
|
37
|
+
export interface SessionResponse {
|
|
38
|
+
user: TGTUser;
|
|
39
|
+
}
|
|
40
|
+
export declare class TGTAuthClient {
|
|
41
|
+
private static readonly TOKEN_KEY;
|
|
42
|
+
private static readonly TEMP_TOKEN_KEY;
|
|
43
|
+
private config;
|
|
44
|
+
private currentUser;
|
|
45
|
+
private currentSession;
|
|
46
|
+
constructor(config: TGTAuthConfig);
|
|
47
|
+
checkSession(): Promise<TGTSession | null>;
|
|
48
|
+
getSession(): TGTSession | null;
|
|
49
|
+
getUser(): TGTUser | null;
|
|
50
|
+
getTenantId(): string | null;
|
|
51
|
+
redirectToLogin(): void;
|
|
52
|
+
logout(): Promise<void>;
|
|
53
|
+
verifyMfa(tempToken: string, code: string): Promise<TGTSession | null>;
|
|
54
|
+
hasRole(appName: string, roleName: string): boolean;
|
|
55
|
+
getRoles(appName: string): string[];
|
|
56
|
+
hasAccessToApp(appName: string): boolean;
|
|
57
|
+
private getTokenFromUrl;
|
|
58
|
+
private removeTokenFromUrl;
|
|
59
|
+
private storeToken;
|
|
60
|
+
private getStoredToken;
|
|
61
|
+
private clearStoredToken;
|
|
62
|
+
private storeTempToken;
|
|
63
|
+
private getTempToken;
|
|
64
|
+
private clearTempToken;
|
|
65
|
+
private handleNoSession;
|
|
66
|
+
private log;
|
|
67
|
+
}
|
|
68
|
+
export declare function useTGTAuth(config: TGTAuthConfig): void;
|
|
69
|
+
export default TGTAuthClient;
|
|
70
|
+
//# sourceMappingURL=tgtone-auth-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tgtone-auth-client.d.ts","sourceRoot":"","sources":["../tgtone-auth-client.ts"],"names":[],"mappings":"AA6BA,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,OAAO,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,OAAO,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IAEnB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAK5B,WAAW,EAAE,MAAM,CAAC;IAMpB,SAAS,EAAE,MAAM,CAAC;IAMlB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC;IAM9C,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAM3B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,OAAO,CAAC;CACf;AAMD,qBAAa,aAAa;IAExB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAuB;IACxD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAuB;IAE7D,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,cAAc,CAA2B;gBAErC,MAAM,EAAE,aAAa;IAuC3B,YAAY,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAgIhD,UAAU,IAAI,UAAU,GAAG,IAAI;IAU/B,OAAO,IAAI,OAAO,GAAG,IAAI;IASzB,WAAW,IAAI,MAAM,GAAG,IAAI;IAQ5B,eAAe,IAAI,IAAI;IAWjB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAmDvB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAwE5E,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO;IAanD,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAWnC,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAYxC,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,kBAAkB;IAa1B,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,gBAAgB;IAcxB,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,YAAY;IAcpB,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,GAAG;CAKZ;AAwBD,wBAAgB,UAAU,CAAC,MAAM,EAAE,aAAa,QAS/C;AAMD,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { jwtDecode } from 'jwt-decode';
|
|
2
|
+
export class TGTAuthClient {
|
|
3
|
+
constructor(config) {
|
|
4
|
+
this.currentUser = null;
|
|
5
|
+
this.currentSession = null;
|
|
6
|
+
this.config = {
|
|
7
|
+
onAuthSuccess: () => { },
|
|
8
|
+
onAuthFailure: () => { },
|
|
9
|
+
debug: false,
|
|
10
|
+
...config,
|
|
11
|
+
};
|
|
12
|
+
this.log('🔹 TGT Auth Client inicializado', this.config);
|
|
13
|
+
}
|
|
14
|
+
async checkSession() {
|
|
15
|
+
try {
|
|
16
|
+
const tempToken = this.getTempToken();
|
|
17
|
+
if (tempToken) {
|
|
18
|
+
this.log('🔹 Flujo MFA en progreso (tempToken detectado)');
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const urlToken = this.getTokenFromUrl();
|
|
22
|
+
if (urlToken) {
|
|
23
|
+
this.log('🔹 Token encontrado en URL, guardando en localStorage');
|
|
24
|
+
this.storeToken(urlToken);
|
|
25
|
+
this.removeTokenFromUrl();
|
|
26
|
+
}
|
|
27
|
+
const token = this.getStoredToken();
|
|
28
|
+
if (!token) {
|
|
29
|
+
this.log('❌ No hay token en localStorage');
|
|
30
|
+
this.handleNoSession();
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
this.log('🔹 Decodificando JWT localmente...');
|
|
34
|
+
let decoded;
|
|
35
|
+
try {
|
|
36
|
+
decoded = jwtDecode(token);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
this.log('❌ Error decodificando JWT:', error);
|
|
40
|
+
this.clearStoredToken();
|
|
41
|
+
this.handleNoSession();
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
if (!decoded.tenant_id) {
|
|
45
|
+
this.log('❌ Token inválido: falta tenant_id');
|
|
46
|
+
this.clearStoredToken();
|
|
47
|
+
this.handleNoSession();
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const now = Date.now();
|
|
51
|
+
const expiresAt = new Date(decoded.exp * 1000);
|
|
52
|
+
if (decoded.exp * 1000 < now) {
|
|
53
|
+
this.log('❌ Token expirado:', expiresAt);
|
|
54
|
+
this.clearStoredToken();
|
|
55
|
+
this.handleNoSession();
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
this.log('✅ JWT válido localmente');
|
|
59
|
+
this.log('🔹 Tenant:', decoded.tenant_id, '-', decoded.tenant_name);
|
|
60
|
+
this.log('🔹 Expira:', expiresAt);
|
|
61
|
+
this.log('🔹 Roles:', decoded.roles);
|
|
62
|
+
this.log('🔹 Verificando sesión con backend...');
|
|
63
|
+
const response = await fetch(`${this.config.identityUrl}/api/v1/auth/me`, {
|
|
64
|
+
method: 'GET',
|
|
65
|
+
headers: {
|
|
66
|
+
'Content-Type': 'application/json',
|
|
67
|
+
'Authorization': `Bearer ${token}`,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
if (!response.ok) {
|
|
71
|
+
this.log('❌ Backend rechazó el token (HTTP', response.status, ')');
|
|
72
|
+
this.clearStoredToken();
|
|
73
|
+
this.handleNoSession();
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
const data = await response.json();
|
|
77
|
+
const session = {
|
|
78
|
+
user: data.user,
|
|
79
|
+
tenantId: decoded.tenant_id,
|
|
80
|
+
tenantName: decoded.tenant_name,
|
|
81
|
+
expiresAt: expiresAt,
|
|
82
|
+
};
|
|
83
|
+
this.currentUser = data.user;
|
|
84
|
+
this.currentSession = session;
|
|
85
|
+
this.log('✅ Sesión válida:', data.user.email);
|
|
86
|
+
this.config.onAuthSuccess(session);
|
|
87
|
+
return session;
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
this.log('❌ Error verificando sesión:', error);
|
|
91
|
+
if (error instanceof TypeError && error.message.includes('Failed to fetch')) {
|
|
92
|
+
console.error(`
|
|
93
|
+
🚫 Error de Conexión - TGT Auth Client
|
|
94
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
95
|
+
Origen: ${typeof window !== 'undefined' ? window.location.origin : 'unknown'}
|
|
96
|
+
Destino: ${this.config.identityUrl}
|
|
97
|
+
|
|
98
|
+
Posibles causas:
|
|
99
|
+
1. Identity backend está offline
|
|
100
|
+
2. Problema de CORS
|
|
101
|
+
3. Red bloqueada
|
|
102
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
103
|
+
`);
|
|
104
|
+
}
|
|
105
|
+
this.clearStoredToken();
|
|
106
|
+
this.handleNoSession();
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
getSession() {
|
|
111
|
+
return this.currentSession;
|
|
112
|
+
}
|
|
113
|
+
getUser() {
|
|
114
|
+
return this.currentUser;
|
|
115
|
+
}
|
|
116
|
+
getTenantId() {
|
|
117
|
+
return this.currentSession?.tenantId || null;
|
|
118
|
+
}
|
|
119
|
+
redirectToLogin() {
|
|
120
|
+
const loginUrl = `${this.config.identityUrl}/login?redirect=${this.config.appDomain}`;
|
|
121
|
+
this.log('🔄 Redirigiendo a login:', loginUrl);
|
|
122
|
+
this.log('🔄 Desde origen:', typeof window !== 'undefined' ? window.location.origin : 'unknown');
|
|
123
|
+
window.location.href = loginUrl;
|
|
124
|
+
}
|
|
125
|
+
async logout() {
|
|
126
|
+
try {
|
|
127
|
+
this.log('🔹 Cerrando sesión...');
|
|
128
|
+
this.log('🔹 Origen:', typeof window !== 'undefined' ? window.location.origin : 'unknown');
|
|
129
|
+
const token = this.getStoredToken();
|
|
130
|
+
await fetch(`${this.config.identityUrl}/api/v1/auth/logout`, {
|
|
131
|
+
method: 'POST',
|
|
132
|
+
headers: {
|
|
133
|
+
'Content-Type': 'application/json',
|
|
134
|
+
...(token && { 'Authorization': `Bearer ${token}` }),
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
this.currentUser = null;
|
|
138
|
+
this.clearStoredToken();
|
|
139
|
+
this.clearTempToken();
|
|
140
|
+
this.log('✅ Sesión cerrada');
|
|
141
|
+
this.redirectToLogin();
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
this.log('❌ Error al cerrar sesión:', error);
|
|
145
|
+
this.log('❌ Origen:', typeof window !== 'undefined' ? window.location.origin : 'unknown');
|
|
146
|
+
this.clearStoredToken();
|
|
147
|
+
this.clearTempToken();
|
|
148
|
+
this.redirectToLogin();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
async verifyMfa(tempToken, code) {
|
|
152
|
+
try {
|
|
153
|
+
this.log('🔹 Verificando código MFA...');
|
|
154
|
+
const response = await fetch(`${this.config.identityUrl}/api/v1/auth/mfa/verify`, {
|
|
155
|
+
method: 'POST',
|
|
156
|
+
headers: {
|
|
157
|
+
'Content-Type': 'application/json',
|
|
158
|
+
},
|
|
159
|
+
body: JSON.stringify({ tempToken, code }),
|
|
160
|
+
});
|
|
161
|
+
if (!response.ok) {
|
|
162
|
+
const error = await response.json();
|
|
163
|
+
throw new Error(error.message || 'Código MFA inválido');
|
|
164
|
+
}
|
|
165
|
+
const data = await response.json();
|
|
166
|
+
if (!data.token || !data.user) {
|
|
167
|
+
throw new Error('Respuesta inválida del servidor');
|
|
168
|
+
}
|
|
169
|
+
this.storeToken(data.token);
|
|
170
|
+
this.clearTempToken();
|
|
171
|
+
const payload = jwtDecode(data.token);
|
|
172
|
+
this.currentUser = {
|
|
173
|
+
sub: payload.sub,
|
|
174
|
+
email: payload.email,
|
|
175
|
+
email_verified: payload.email_verified,
|
|
176
|
+
name: payload.name,
|
|
177
|
+
tenant_id: payload.tenant_id,
|
|
178
|
+
tenant_name: payload.tenant_name,
|
|
179
|
+
roles: payload.roles,
|
|
180
|
+
};
|
|
181
|
+
this.currentSession = {
|
|
182
|
+
user: this.currentUser,
|
|
183
|
+
tenantId: payload.tenant_id,
|
|
184
|
+
tenantName: payload.tenant_name,
|
|
185
|
+
expiresAt: new Date(payload.exp * 1000),
|
|
186
|
+
};
|
|
187
|
+
this.log('✅ MFA verificado correctamente');
|
|
188
|
+
this.config.onAuthSuccess(this.currentSession);
|
|
189
|
+
return this.currentSession;
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
this.log('❌ Error verificando MFA:', error);
|
|
193
|
+
throw error;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
hasRole(appName, roleName) {
|
|
197
|
+
if (!this.currentUser)
|
|
198
|
+
return false;
|
|
199
|
+
const appRoles = this.currentUser.roles[appName] || [];
|
|
200
|
+
return appRoles.includes(roleName);
|
|
201
|
+
}
|
|
202
|
+
getRoles(appName) {
|
|
203
|
+
if (!this.currentUser)
|
|
204
|
+
return [];
|
|
205
|
+
return this.currentUser.roles[appName] || [];
|
|
206
|
+
}
|
|
207
|
+
hasAccessToApp(appName) {
|
|
208
|
+
return this.getRoles(appName).length > 0;
|
|
209
|
+
}
|
|
210
|
+
getTokenFromUrl() {
|
|
211
|
+
if (typeof window === 'undefined')
|
|
212
|
+
return null;
|
|
213
|
+
const params = new URLSearchParams(window.location.search);
|
|
214
|
+
return params.get('token');
|
|
215
|
+
}
|
|
216
|
+
removeTokenFromUrl() {
|
|
217
|
+
if (typeof window === 'undefined')
|
|
218
|
+
return;
|
|
219
|
+
const url = new URL(window.location.href);
|
|
220
|
+
url.searchParams.delete('token');
|
|
221
|
+
window.history.replaceState({}, '', url.toString());
|
|
222
|
+
}
|
|
223
|
+
storeToken(token) {
|
|
224
|
+
if (typeof window === 'undefined')
|
|
225
|
+
return;
|
|
226
|
+
try {
|
|
227
|
+
localStorage.setItem(TGTAuthClient.TOKEN_KEY, token);
|
|
228
|
+
this.log('✅ Token guardado en localStorage');
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
this.log('❌ Error guardando token:', error);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
getStoredToken() {
|
|
235
|
+
if (typeof window === 'undefined')
|
|
236
|
+
return null;
|
|
237
|
+
try {
|
|
238
|
+
return localStorage.getItem(TGTAuthClient.TOKEN_KEY);
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
this.log('❌ Error leyendo token:', error);
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
clearStoredToken() {
|
|
246
|
+
if (typeof window === 'undefined')
|
|
247
|
+
return;
|
|
248
|
+
try {
|
|
249
|
+
localStorage.removeItem(TGTAuthClient.TOKEN_KEY);
|
|
250
|
+
this.log('✅ Token eliminado de localStorage');
|
|
251
|
+
}
|
|
252
|
+
catch (error) {
|
|
253
|
+
this.log('❌ Error eliminando token:', error);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
storeTempToken(tempToken) {
|
|
257
|
+
if (typeof window === 'undefined')
|
|
258
|
+
return;
|
|
259
|
+
try {
|
|
260
|
+
localStorage.setItem(TGTAuthClient.TEMP_TOKEN_KEY, tempToken);
|
|
261
|
+
this.log('✅ Token temporal MFA guardado');
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
this.log('❌ Error guardando token temporal:', error);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
getTempToken() {
|
|
268
|
+
if (typeof window === 'undefined')
|
|
269
|
+
return null;
|
|
270
|
+
try {
|
|
271
|
+
return localStorage.getItem(TGTAuthClient.TEMP_TOKEN_KEY);
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
this.log('❌ Error leyendo token temporal:', error);
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
clearTempToken() {
|
|
279
|
+
if (typeof window === 'undefined')
|
|
280
|
+
return;
|
|
281
|
+
try {
|
|
282
|
+
localStorage.removeItem(TGTAuthClient.TEMP_TOKEN_KEY);
|
|
283
|
+
this.log('✅ Token temporal MFA eliminado');
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
this.log('❌ Error eliminando token temporal:', error);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
handleNoSession() {
|
|
290
|
+
this.config.onAuthFailure();
|
|
291
|
+
this.redirectToLogin();
|
|
292
|
+
}
|
|
293
|
+
log(...args) {
|
|
294
|
+
if (this.config.debug) {
|
|
295
|
+
console.log('[TGT Auth]', ...args);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
TGTAuthClient.TOKEN_KEY = 'tgtone_auth_token';
|
|
300
|
+
TGTAuthClient.TEMP_TOKEN_KEY = 'tgtone_temp_token';
|
|
301
|
+
export function useTGTAuth(config) {
|
|
302
|
+
throw new Error('useTGTAuth requiere React. Importa desde tgtone-auth-client/react');
|
|
303
|
+
}
|
|
304
|
+
export default TGTAuthClient;
|
|
305
|
+
//# sourceMappingURL=tgtone-auth-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tgtone-auth-client.js","sourceRoot":"","sources":["../tgtone-auth-client.ts"],"names":[],"mappings":"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"}
|