@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
package/docs/API.md
ADDED
|
@@ -0,0 +1,844 @@
|
|
|
1
|
+
# API Reference - @tgtone/auth-sdk
|
|
2
|
+
|
|
3
|
+
> Complete API reference for `@tgtone/auth-sdk` v1.4.4
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [TGTAuthClient](#tgtauthclient)
|
|
10
|
+
- [Constructor](#constructor)
|
|
11
|
+
- [Authentication](#authentication)
|
|
12
|
+
- [signup()](#signup)
|
|
13
|
+
- [login()](#login)
|
|
14
|
+
- [verifyMfa()](#verifymfa)
|
|
15
|
+
- [logout()](#logout)
|
|
16
|
+
- [Session](#session)
|
|
17
|
+
- [checkSession()](#checksession)
|
|
18
|
+
- [checkSessionSilent()](#checksessionsilent)
|
|
19
|
+
- [getSession()](#getsession)
|
|
20
|
+
- [getUser()](#getuser)
|
|
21
|
+
- [getTenantId()](#gettenantid)
|
|
22
|
+
- [getToken()](#gettoken)
|
|
23
|
+
- [redirectToLogin()](#redirecttologin)
|
|
24
|
+
- [isRedirectAllowed()](#isredirectallowed)
|
|
25
|
+
- [Authorization](#authorization)
|
|
26
|
+
- [hasRole()](#hasrole)
|
|
27
|
+
- [getRoles()](#getroles)
|
|
28
|
+
- [hasAccessToApp()](#hasaccesstoapp)
|
|
29
|
+
- [Heartbeat & Session Revocation](#heartbeat--session-revocation)
|
|
30
|
+
- [startHeartbeat()](#startheartbeat)
|
|
31
|
+
- [stopHeartbeat()](#stopheartbeat)
|
|
32
|
+
- [isHeartbeatActive()](#isheartbeatactive)
|
|
33
|
+
- [getBlockedRedirectUrl()](#getblockedredirecturl)
|
|
34
|
+
- [Utilities](#utilities)
|
|
35
|
+
- [isRevocationError()](#isrevocationerror)
|
|
36
|
+
- [REVOCATION_ERROR_CODES](#revocation_error_codes)
|
|
37
|
+
- [HTTP Interceptors](#http-interceptors)
|
|
38
|
+
- [createAxiosInterceptor()](#createaxiosinterceptor)
|
|
39
|
+
- [createAuthFetch()](#createauthfetch)
|
|
40
|
+
- [handleAuthError()](#handleautherror)
|
|
41
|
+
- [React Hook](#react-hook)
|
|
42
|
+
- [useTGTAuth()](#usetgtauth)
|
|
43
|
+
- [TypeScript Types](#typescript-types)
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## TGTAuthClient
|
|
48
|
+
|
|
49
|
+
Main authentication client. Handles JWT tokens, session management, SSO flow, and heartbeat.
|
|
50
|
+
|
|
51
|
+
### Constructor
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
new TGTAuthClient(config: TGTAuthConfig)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Parameters:**
|
|
58
|
+
|
|
59
|
+
| Parameter | Type | Required | Description |
|
|
60
|
+
|-----------|------|----------|-------------|
|
|
61
|
+
| `config` | `TGTAuthConfig` | Yes | Configuration object |
|
|
62
|
+
|
|
63
|
+
**Example:**
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { TGTAuthClient } from '@tgtone/auth-sdk';
|
|
67
|
+
|
|
68
|
+
const auth = new TGTAuthClient({
|
|
69
|
+
identityUrl: 'https://identity.tgtone.cl',
|
|
70
|
+
appDomain: 'zenith.tgtone.cl',
|
|
71
|
+
appKey: 'zenith',
|
|
72
|
+
debug: true,
|
|
73
|
+
allowedRedirectHosts: ['tgtone.cl', 'app.tgtone.cl'],
|
|
74
|
+
heartbeatIntervalMs: 5 * 60 * 1000,
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Authentication
|
|
81
|
+
|
|
82
|
+
### signup()
|
|
83
|
+
|
|
84
|
+
Creates a new user account and tenant.
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
signup(data: SignupData): Promise<AuthResponse>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Parameters (`SignupData`):**
|
|
91
|
+
|
|
92
|
+
| Field | Type | Required | Description |
|
|
93
|
+
|-------|------|----------|-------------|
|
|
94
|
+
| `email` | `string` | Yes | User email |
|
|
95
|
+
| `password` | `string` | No | If not provided, backend generates a temporary one |
|
|
96
|
+
| `firstName` | `string` | Yes | First name |
|
|
97
|
+
| `lastName` | `string` | Yes | Last name |
|
|
98
|
+
| `tenantName` | `string` | Yes | Name of the new tenant |
|
|
99
|
+
|
|
100
|
+
**Returns:** `Promise<AuthResponse>`
|
|
101
|
+
|
|
102
|
+
**Example:**
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
const result = await auth.signup({
|
|
106
|
+
email: 'user@empresa.cl',
|
|
107
|
+
password: 'Pass123!',
|
|
108
|
+
firstName: 'María',
|
|
109
|
+
lastName: 'García',
|
|
110
|
+
tenantName: 'Empresa XYZ',
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
if (result.mustChangePassword) {
|
|
114
|
+
// Show password change form
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
### login()
|
|
121
|
+
|
|
122
|
+
Authenticates a user with email and password. Supports MFA flow.
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
login(data: LoginData): Promise<AuthResponse>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Parameters (`LoginData`):**
|
|
129
|
+
|
|
130
|
+
| Field | Type | Required | Description |
|
|
131
|
+
|-------|------|----------|-------------|
|
|
132
|
+
| `email` | `string` | Yes | User email |
|
|
133
|
+
| `password` | `string` | Yes | User password |
|
|
134
|
+
| `targetApp` | `string` | No | Target app key for subscription validation |
|
|
135
|
+
|
|
136
|
+
**Returns:** `Promise<AuthResponse>`
|
|
137
|
+
|
|
138
|
+
When `requiresMfa` is `true`, the response includes a `tempToken` that must be used with `verifyMfa()`.
|
|
139
|
+
|
|
140
|
+
**Example:**
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
const result = await auth.login({
|
|
144
|
+
email: 'user@empresa.cl',
|
|
145
|
+
password: 'Pass123!',
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
if (result.requiresMfa) {
|
|
149
|
+
const code = prompt('Enter Google Authenticator code:');
|
|
150
|
+
const session = await auth.verifyMfa(result.tempToken, code);
|
|
151
|
+
} else {
|
|
152
|
+
console.log('Login successful:', result.user.email);
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### verifyMfa()
|
|
159
|
+
|
|
160
|
+
Completes MFA verification after login returns `requiresMfa: true`.
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
verifyMfa(tempToken: string, code: string): Promise<TGTSession | null>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Parameters:**
|
|
167
|
+
|
|
168
|
+
| Parameter | Type | Description |
|
|
169
|
+
|-----------|------|-------------|
|
|
170
|
+
| `tempToken` | `string` | Temporary token from login response |
|
|
171
|
+
| `code` | `string` | 6-digit code from Google Authenticator |
|
|
172
|
+
|
|
173
|
+
**Returns:** `Promise<TGTSession | null>`
|
|
174
|
+
|
|
175
|
+
**Example:**
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
const session = await auth.verifyMfa('temp-token-abc', '123456');
|
|
179
|
+
if (session) {
|
|
180
|
+
console.log('MFA verified, user:', session.user.email);
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
### logout()
|
|
187
|
+
|
|
188
|
+
Invalidates the token on the backend, clears localStorage, and redirects to login.
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
logout(): Promise<void>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Example:**
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
await auth.logout();
|
|
198
|
+
// User is redirected to Identity login
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Session
|
|
204
|
+
|
|
205
|
+
### checkSession()
|
|
206
|
+
|
|
207
|
+
Validates the current session. If no valid session exists, **automatically redirects to login**.
|
|
208
|
+
|
|
209
|
+
Process:
|
|
210
|
+
1. Reads token from URL (if redirected from Identity)
|
|
211
|
+
2. Reads token from localStorage
|
|
212
|
+
3. Decodes JWT locally and validates structure
|
|
213
|
+
4. Validates token with backend (`/api/v1/auth/me`)
|
|
214
|
+
5. If invalid, redirects to login or `/blocked` (depending on error type)
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
checkSession(): Promise<TGTSession | null>
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Returns:** `Promise<TGTSession | null>` — Session object if valid, `null` if redirecting.
|
|
221
|
+
|
|
222
|
+
**Example:**
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
const session = await auth.checkSession();
|
|
226
|
+
if (session) {
|
|
227
|
+
console.log('User:', session.user.email);
|
|
228
|
+
console.log('Tenant:', session.tenantId);
|
|
229
|
+
console.log('Roles:', session.user.roles);
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
### checkSessionSilent()
|
|
236
|
+
|
|
237
|
+
Checks session **without redirecting or executing callbacks**. Useful for public pages that show different content based on login status.
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
checkSessionSilent(validateWithServer?: boolean): Promise<TGTSession | null>
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Parameters:**
|
|
244
|
+
|
|
245
|
+
| Parameter | Type | Default | Description |
|
|
246
|
+
|-----------|------|---------|-------------|
|
|
247
|
+
| `validateWithServer` | `boolean` | `true` | If `true`, validates with `/api/v1/auth/me`. If `false`, only validates JWT locally (faster). |
|
|
248
|
+
|
|
249
|
+
**Returns:** `Promise<TGTSession | null>`
|
|
250
|
+
|
|
251
|
+
**Example:**
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
const session = await auth.checkSessionSilent();
|
|
255
|
+
if (session) {
|
|
256
|
+
showButton('Go to Dashboard', '/dashboard');
|
|
257
|
+
} else {
|
|
258
|
+
showButton('Login', () => auth.redirectToLogin());
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Fast check without server validation
|
|
262
|
+
const localSession = await auth.checkSessionSilent(false);
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
### getSession()
|
|
268
|
+
|
|
269
|
+
Returns the current in-memory session without making any network request. Must call `checkSession()` first.
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
getSession(): TGTSession | null
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
### getUser()
|
|
278
|
+
|
|
279
|
+
Returns the current in-memory user without making any network request.
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
getUser(): TGTUser | null
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
### getTenantId()
|
|
288
|
+
|
|
289
|
+
Returns the tenant ID of the current session.
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
getTenantId(): string | null
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
### getToken()
|
|
298
|
+
|
|
299
|
+
Returns the current JWT token from localStorage. Useful for injecting into API request headers.
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
getToken(): string | null
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
### redirectToLogin()
|
|
308
|
+
|
|
309
|
+
Redirects to the Identity Provider login page.
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
redirectToLogin(redirectUrl?: string): void
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
**Parameters:**
|
|
316
|
+
|
|
317
|
+
| Parameter | Type | Description |
|
|
318
|
+
|-----------|------|-------------|
|
|
319
|
+
| `redirectUrl` | `string` | Optional. Full URL to return to after login. Only works if the host is in `allowedRedirectHosts`. |
|
|
320
|
+
|
|
321
|
+
**Example:**
|
|
322
|
+
|
|
323
|
+
```typescript
|
|
324
|
+
// Simple redirect
|
|
325
|
+
auth.redirectToLogin();
|
|
326
|
+
|
|
327
|
+
// With return URL
|
|
328
|
+
auth.redirectToLogin(window.location.href);
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
### isRedirectAllowed()
|
|
334
|
+
|
|
335
|
+
Checks if a URL's host is in the `allowedRedirectHosts` list.
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
isRedirectAllowed(redirectUrl: string): boolean
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**Example:**
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
const url = 'https://tgtone.cl/precios';
|
|
345
|
+
if (auth.isRedirectAllowed(url)) {
|
|
346
|
+
auth.redirectToLogin(url);
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## Authorization
|
|
353
|
+
|
|
354
|
+
### hasRole()
|
|
355
|
+
|
|
356
|
+
Checks if the current user has a specific role in an application.
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
hasRole(appName: string, roleName: string): boolean
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**Parameters:**
|
|
363
|
+
|
|
364
|
+
| Parameter | Type | Description |
|
|
365
|
+
|-----------|------|-------------|
|
|
366
|
+
| `appName` | `string` | Application name (e.g. `'console'`, `'zenith'`, `'baco'`) |
|
|
367
|
+
| `roleName` | `string` | Role name (e.g. `'admin'`, `'owner'`, `'viewer'`) |
|
|
368
|
+
|
|
369
|
+
**Example:**
|
|
370
|
+
|
|
371
|
+
```typescript
|
|
372
|
+
if (auth.hasRole('console', 'admin')) {
|
|
373
|
+
// Show admin panel
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
### getRoles()
|
|
380
|
+
|
|
381
|
+
Returns all roles for the current user in a specific application.
|
|
382
|
+
|
|
383
|
+
```typescript
|
|
384
|
+
getRoles(appName: string): string[]
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
**Example:**
|
|
388
|
+
|
|
389
|
+
```typescript
|
|
390
|
+
const roles = auth.getRoles('console'); // ['owner', 'admin']
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
### hasAccessToApp()
|
|
396
|
+
|
|
397
|
+
Checks if the user has at least one role in the specified application.
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
hasAccessToApp(appName: string): boolean
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**Example:**
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
if (auth.hasAccessToApp('zenith')) {
|
|
407
|
+
// Show link to Zenith
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
## Heartbeat & Session Revocation
|
|
414
|
+
|
|
415
|
+
### startHeartbeat()
|
|
416
|
+
|
|
417
|
+
Starts periodic session validation. If the session is revoked (user deleted, tenant suspended, etc.), executes `onSessionRevoked` callback or redirects to `/blocked`.
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
startHeartbeat(): void
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
**Behavior:**
|
|
424
|
+
- Default interval: 5 minutes (configurable via `heartbeatIntervalMs`)
|
|
425
|
+
- Set `heartbeatIntervalMs: 0` to disable
|
|
426
|
+
- Does nothing if already running
|
|
427
|
+
|
|
428
|
+
**Example:**
|
|
429
|
+
|
|
430
|
+
```typescript
|
|
431
|
+
auth.startHeartbeat();
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
### stopHeartbeat()
|
|
437
|
+
|
|
438
|
+
Stops the periodic session validation.
|
|
439
|
+
|
|
440
|
+
```typescript
|
|
441
|
+
stopHeartbeat(): void
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
### isHeartbeatActive()
|
|
447
|
+
|
|
448
|
+
Returns whether the heartbeat is currently running.
|
|
449
|
+
|
|
450
|
+
```typescript
|
|
451
|
+
isHeartbeatActive(): boolean
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
456
|
+
### getBlockedRedirectUrl()
|
|
457
|
+
|
|
458
|
+
Generates the URL for the blocked page based on the error code.
|
|
459
|
+
|
|
460
|
+
```typescript
|
|
461
|
+
getBlockedRedirectUrl(error: AuthError): string
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
**Error Code to Type Mapping:**
|
|
465
|
+
|
|
466
|
+
| Error Code | Blocked Type |
|
|
467
|
+
|------------|-------------|
|
|
468
|
+
| `USER_INACTIVE` | `user` |
|
|
469
|
+
| `USER_NOT_FOUND` | `user` |
|
|
470
|
+
| `TENANT_INACTIVE` | `tenant` |
|
|
471
|
+
| `APP_SUBSCRIPTION_LOCKED` | `subscription` |
|
|
472
|
+
| `TRIAL_EXPIRED` | `trial` |
|
|
473
|
+
|
|
474
|
+
**Example:**
|
|
475
|
+
|
|
476
|
+
```typescript
|
|
477
|
+
const url = auth.getBlockedRedirectUrl({
|
|
478
|
+
code: 'TENANT_INACTIVE',
|
|
479
|
+
message: 'Tenant suspended',
|
|
480
|
+
});
|
|
481
|
+
// https://identity.tgtone.cl/blocked?type=tenant&message=Tenant%20suspended
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
---
|
|
485
|
+
|
|
486
|
+
## Utilities
|
|
487
|
+
|
|
488
|
+
### isRevocationError()
|
|
489
|
+
|
|
490
|
+
Checks if an error code indicates session revocation.
|
|
491
|
+
|
|
492
|
+
```typescript
|
|
493
|
+
isRevocationError(code: AuthErrorCode): boolean
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
**Example:**
|
|
497
|
+
|
|
498
|
+
```typescript
|
|
499
|
+
import { isRevocationError } from '@tgtone/auth-sdk';
|
|
500
|
+
|
|
501
|
+
try {
|
|
502
|
+
await api.call();
|
|
503
|
+
} catch (error) {
|
|
504
|
+
const code = error.response?.data?.code;
|
|
505
|
+
if (code && isRevocationError(code)) {
|
|
506
|
+
console.log('Session revoked:', code);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
513
|
+
### REVOCATION_ERROR_CODES
|
|
514
|
+
|
|
515
|
+
Array of all revocation error codes.
|
|
516
|
+
|
|
517
|
+
```typescript
|
|
518
|
+
const REVOCATION_ERROR_CODES: AuthErrorCode[]
|
|
519
|
+
// ['TENANT_INACTIVE', 'USER_INACTIVE', 'USER_NOT_FOUND', 'APP_SUBSCRIPTION_LOCKED', 'TRIAL_EXPIRED']
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
## HTTP Interceptors
|
|
525
|
+
|
|
526
|
+
Module: `@tgtone/auth-sdk/interceptor`
|
|
527
|
+
|
|
528
|
+
### createAxiosInterceptor()
|
|
529
|
+
|
|
530
|
+
Attaches a response interceptor to an Axios instance that handles 401 authentication errors and session revocation.
|
|
531
|
+
|
|
532
|
+
```typescript
|
|
533
|
+
createAxiosInterceptor(
|
|
534
|
+
axios: any,
|
|
535
|
+
authClient: TGTAuthClient,
|
|
536
|
+
config?: InterceptorConfig
|
|
537
|
+
): () => void
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
**Parameters:**
|
|
541
|
+
|
|
542
|
+
| Parameter | Type | Description |
|
|
543
|
+
|-----------|------|-------------|
|
|
544
|
+
| `axios` | `any` | Axios instance |
|
|
545
|
+
| `authClient` | `TGTAuthClient` | Auth client instance |
|
|
546
|
+
| `config` | `InterceptorConfig` | Optional configuration |
|
|
547
|
+
|
|
548
|
+
**Returns:** Cleanup function to remove the interceptor.
|
|
549
|
+
|
|
550
|
+
**Example:**
|
|
551
|
+
|
|
552
|
+
```typescript
|
|
553
|
+
import { createAxiosInterceptor } from '@tgtone/auth-sdk/interceptor';
|
|
554
|
+
|
|
555
|
+
const api = axios.create({ baseURL: '/api' });
|
|
556
|
+
const removeInterceptor = createAxiosInterceptor(api, authClient, {
|
|
557
|
+
handleRevoked: true,
|
|
558
|
+
excludeUrls: ['/public/health'],
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
// To remove:
|
|
562
|
+
// removeInterceptor();
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
---
|
|
566
|
+
|
|
567
|
+
### createAuthFetch()
|
|
568
|
+
|
|
569
|
+
Returns a wrapped `fetch` function that automatically injects the `Authorization` header and handles 401 revocation errors.
|
|
570
|
+
|
|
571
|
+
```typescript
|
|
572
|
+
createAuthFetch(
|
|
573
|
+
authClient: TGTAuthClient,
|
|
574
|
+
config?: InterceptorConfig
|
|
575
|
+
): (url: string | URL, init?: RequestInit) => Promise<Response>
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
**Example:**
|
|
579
|
+
|
|
580
|
+
```typescript
|
|
581
|
+
import { createAuthFetch } from '@tgtone/auth-sdk/interceptor';
|
|
582
|
+
|
|
583
|
+
const authFetch = createAuthFetch(authClient, {
|
|
584
|
+
handleRevoked: true,
|
|
585
|
+
excludeUrls: ['/public/'],
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
// Use like native fetch — Authorization header is auto-injected
|
|
589
|
+
const response = await authFetch('/api/users');
|
|
590
|
+
const data = await response.json();
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
---
|
|
594
|
+
|
|
595
|
+
### handleAuthError()
|
|
596
|
+
|
|
597
|
+
Manual error handler for custom error handling scenarios.
|
|
598
|
+
|
|
599
|
+
```typescript
|
|
600
|
+
handleAuthError(
|
|
601
|
+
error: { response?: { status?: number; data?: { code?: string; message?: string } } },
|
|
602
|
+
authClient: TGTAuthClient,
|
|
603
|
+
options?: { onRevoked?: (error: AuthError) => void }
|
|
604
|
+
): boolean
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
**Returns:** `true` if the error was a revocation error and was handled, `false` otherwise.
|
|
608
|
+
|
|
609
|
+
**Example:**
|
|
610
|
+
|
|
611
|
+
```typescript
|
|
612
|
+
import { handleAuthError } from '@tgtone/auth-sdk/interceptor';
|
|
613
|
+
|
|
614
|
+
try {
|
|
615
|
+
await api.call();
|
|
616
|
+
} catch (error) {
|
|
617
|
+
if (handleAuthError(error, authClient)) {
|
|
618
|
+
return; // Error was handled
|
|
619
|
+
}
|
|
620
|
+
throw error; // Not an auth error
|
|
621
|
+
}
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
---
|
|
625
|
+
|
|
626
|
+
## React Hook
|
|
627
|
+
|
|
628
|
+
### useTGTAuth()
|
|
629
|
+
|
|
630
|
+
React hook for SSO authentication with automatic session management.
|
|
631
|
+
|
|
632
|
+
```typescript
|
|
633
|
+
useTGTAuth(config: UseTGTAuthConfig): UseTGTAuthResult
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
**Parameters (`UseTGTAuthConfig`):**
|
|
637
|
+
|
|
638
|
+
Extends `TGTAuthConfig` with:
|
|
639
|
+
|
|
640
|
+
| Field | Type | Default | Description |
|
|
641
|
+
|-------|------|---------|-------------|
|
|
642
|
+
| `enableHeartbeat` | `boolean` | `true` | Start heartbeat automatically after login |
|
|
643
|
+
| `showRevokedState` | `boolean` | `false` | Show revoked error in UI instead of redirecting |
|
|
644
|
+
|
|
645
|
+
**Returns (`UseTGTAuthResult`):**
|
|
646
|
+
|
|
647
|
+
| Field | Type | Description |
|
|
648
|
+
|-------|------|-------------|
|
|
649
|
+
| `session` | `TGTSession \| null` | Current session |
|
|
650
|
+
| `loading` | `boolean` | True while checking session |
|
|
651
|
+
| `logout` | `() => Promise<void>` | Logout function |
|
|
652
|
+
| `hasRole` | `(app, role) => boolean` | Role check |
|
|
653
|
+
| `getRoles` | `(app) => string[]` | Get all roles |
|
|
654
|
+
| `hasAccessToApp` | `(app) => boolean` | Access check |
|
|
655
|
+
| `tenantId` | `string \| null` | Current tenant ID |
|
|
656
|
+
| `authClient` | `TGTAuthClient` | Underlying client instance |
|
|
657
|
+
| `revokedError` | `AuthError \| null` | Revocation error (when `showRevokedState: true`) |
|
|
658
|
+
| `isHeartbeatActive` | `boolean` | Heartbeat running status |
|
|
659
|
+
| `startHeartbeat` | `() => void` | Start heartbeat manually |
|
|
660
|
+
| `stopHeartbeat` | `() => void` | Stop heartbeat manually |
|
|
661
|
+
|
|
662
|
+
**Example:**
|
|
663
|
+
|
|
664
|
+
```tsx
|
|
665
|
+
import { useTGTAuth } from '@tgtone/auth-sdk/react';
|
|
666
|
+
|
|
667
|
+
function App() {
|
|
668
|
+
const { session, loading, logout, hasRole, revokedError } = useTGTAuth({
|
|
669
|
+
identityUrl: 'https://identity.tgtone.cl',
|
|
670
|
+
appDomain: 'zenith.tgtone.cl',
|
|
671
|
+
appKey: 'zenith',
|
|
672
|
+
enableHeartbeat: true,
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
if (loading) return <Spinner />;
|
|
676
|
+
if (revokedError) return <RevokedPage error={revokedError} />;
|
|
677
|
+
if (!session) return null; // Redirecting to login
|
|
678
|
+
|
|
679
|
+
return (
|
|
680
|
+
<Dashboard user={session.user}>
|
|
681
|
+
{hasRole('zenith', 'admin') && <AdminPanel />}
|
|
682
|
+
<button onClick={logout}>Logout</button>
|
|
683
|
+
</Dashboard>
|
|
684
|
+
);
|
|
685
|
+
}
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
---
|
|
689
|
+
|
|
690
|
+
## TypeScript Types
|
|
691
|
+
|
|
692
|
+
### TGTAuthConfig
|
|
693
|
+
|
|
694
|
+
```typescript
|
|
695
|
+
interface TGTAuthConfig {
|
|
696
|
+
identityUrl: string;
|
|
697
|
+
appDomain: string;
|
|
698
|
+
appKey?: string;
|
|
699
|
+
onAuthSuccess?: (session: TGTSession) => void;
|
|
700
|
+
onAuthFailure?: (error?: AuthError) => void;
|
|
701
|
+
onSessionRevoked?: (error: AuthError) => void;
|
|
702
|
+
debug?: boolean;
|
|
703
|
+
allowedRedirectHosts?: string[];
|
|
704
|
+
heartbeatIntervalMs?: number;
|
|
705
|
+
}
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
### TGTSession
|
|
709
|
+
|
|
710
|
+
```typescript
|
|
711
|
+
interface TGTSession {
|
|
712
|
+
user: TGTUser;
|
|
713
|
+
tenantId: string;
|
|
714
|
+
tenantName: string;
|
|
715
|
+
expiresAt: Date;
|
|
716
|
+
}
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
### TGTUser
|
|
720
|
+
|
|
721
|
+
```typescript
|
|
722
|
+
interface TGTUser {
|
|
723
|
+
sub: string;
|
|
724
|
+
email: string;
|
|
725
|
+
email_verified: boolean;
|
|
726
|
+
name: string;
|
|
727
|
+
tenant_id: string;
|
|
728
|
+
tenant_name: string;
|
|
729
|
+
roles: Record<string, string[]>;
|
|
730
|
+
}
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
### AuthError
|
|
734
|
+
|
|
735
|
+
```typescript
|
|
736
|
+
interface AuthError {
|
|
737
|
+
code: AuthErrorCode;
|
|
738
|
+
message: string;
|
|
739
|
+
}
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
### AuthErrorCode
|
|
743
|
+
|
|
744
|
+
```typescript
|
|
745
|
+
type AuthErrorCode =
|
|
746
|
+
| 'TENANT_INACTIVE'
|
|
747
|
+
| 'USER_INACTIVE'
|
|
748
|
+
| 'USER_NOT_FOUND'
|
|
749
|
+
| 'APP_SUBSCRIPTION_LOCKED'
|
|
750
|
+
| 'TRIAL_EXPIRED';
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
### SignupData
|
|
754
|
+
|
|
755
|
+
```typescript
|
|
756
|
+
interface SignupData {
|
|
757
|
+
email: string;
|
|
758
|
+
password?: string;
|
|
759
|
+
firstName: string;
|
|
760
|
+
lastName: string;
|
|
761
|
+
tenantName: string;
|
|
762
|
+
}
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
### LoginData
|
|
766
|
+
|
|
767
|
+
```typescript
|
|
768
|
+
interface LoginData {
|
|
769
|
+
email: string;
|
|
770
|
+
password: string;
|
|
771
|
+
targetApp?: string;
|
|
772
|
+
}
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
### AuthResponse
|
|
776
|
+
|
|
777
|
+
```typescript
|
|
778
|
+
interface AuthResponse {
|
|
779
|
+
token: string;
|
|
780
|
+
accessToken: string;
|
|
781
|
+
expiresIn: number;
|
|
782
|
+
user: {
|
|
783
|
+
id: string;
|
|
784
|
+
email: string;
|
|
785
|
+
firstName?: string;
|
|
786
|
+
lastName?: string;
|
|
787
|
+
};
|
|
788
|
+
mustChangePassword?: boolean;
|
|
789
|
+
requiresMfa?: boolean;
|
|
790
|
+
tempToken?: string;
|
|
791
|
+
message?: string;
|
|
792
|
+
}
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
### SessionResponse
|
|
796
|
+
|
|
797
|
+
```typescript
|
|
798
|
+
interface SessionResponse {
|
|
799
|
+
user: TGTUser;
|
|
800
|
+
}
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
### InterceptorConfig
|
|
804
|
+
|
|
805
|
+
```typescript
|
|
806
|
+
interface InterceptorConfig {
|
|
807
|
+
handleRevoked?: boolean;
|
|
808
|
+
onAuthError?: (error: AuthError) => void;
|
|
809
|
+
excludeUrls?: string[];
|
|
810
|
+
}
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
### UseTGTAuthConfig
|
|
814
|
+
|
|
815
|
+
```typescript
|
|
816
|
+
interface UseTGTAuthConfig extends TGTAuthConfig {
|
|
817
|
+
enableHeartbeat?: boolean;
|
|
818
|
+
showRevokedState?: boolean;
|
|
819
|
+
}
|
|
820
|
+
```
|
|
821
|
+
|
|
822
|
+
### UseTGTAuthResult
|
|
823
|
+
|
|
824
|
+
```typescript
|
|
825
|
+
interface UseTGTAuthResult {
|
|
826
|
+
session: TGTSession | null;
|
|
827
|
+
loading: boolean;
|
|
828
|
+
logout: () => Promise<void>;
|
|
829
|
+
hasRole: (appName: string, roleName: string) => boolean;
|
|
830
|
+
getRoles: (appName: string) => string[];
|
|
831
|
+
hasAccessToApp: (appName: string) => boolean;
|
|
832
|
+
tenantId: string | null;
|
|
833
|
+
authClient: TGTAuthClient;
|
|
834
|
+
revokedError: AuthError | null;
|
|
835
|
+
isHeartbeatActive: boolean;
|
|
836
|
+
startHeartbeat: () => void;
|
|
837
|
+
stopHeartbeat: () => void;
|
|
838
|
+
}
|
|
839
|
+
```
|
|
840
|
+
|
|
841
|
+
---
|
|
842
|
+
|
|
843
|
+
**Version:** 1.4.4
|
|
844
|
+
**Last updated:** 2026-04-14
|