@zskj-idaas/sdk 1.0.1 → 1.0.3

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/dist/index.d.mts CHANGED
@@ -18,6 +18,11 @@ interface TokenSet {
18
18
  refresh_token?: string;
19
19
  scope: string;
20
20
  }
21
+ interface ServiceTokenState {
22
+ accessToken: string;
23
+ expiresAt: number;
24
+ scope: string;
25
+ }
21
26
  interface UserInfo {
22
27
  sub: string;
23
28
  preferred_username?: string;
@@ -35,6 +40,10 @@ interface AuthState {
35
40
  idToken: string | null;
36
41
  expiresAt: number | null;
37
42
  }
43
+ interface SessionLogoutOptions {
44
+ /** Redirect after the server-side session and local tokens are cleared. */
45
+ redirectTo?: string;
46
+ }
38
47
  interface PKCEPair {
39
48
  codeVerifier: string;
40
49
  codeChallenge: string;
@@ -45,6 +54,7 @@ declare class IdaasClient {
45
54
  private endpoints;
46
55
  private storage;
47
56
  private userInfo;
57
+ private serviceTokens;
48
58
  constructor(config: IdaasConfig);
49
59
  init(): Promise<AuthState>;
50
60
  private discover;
@@ -53,13 +63,16 @@ declare class IdaasClient {
53
63
  refreshToken(): Promise<TokenSet | null>;
54
64
  getUserInfo(forceRefresh?: boolean): Promise<UserInfo | null>;
55
65
  getAccessToken(): Promise<string | null>;
66
+ getServiceToken(serviceKey: string): Promise<string | null>;
56
67
  getIdToken(): string | null;
57
68
  getAuthState(): AuthState;
58
69
  isAuthenticated(): boolean;
59
70
  logout(): Promise<void>;
71
+ logoutSession(options?: SessionLogoutOptions): Promise<void>;
60
72
  revokeToken(): Promise<void>;
61
73
  /** Create an authenticated fetch wrapper */
62
74
  fetch(url: string, init?: RequestInit): Promise<Response>;
75
+ fetchService(serviceKey: string, url: string, init?: RequestInit): Promise<Response>;
63
76
  }
64
77
 
65
78
  declare function createPKCE(): Promise<PKCEPair>;
@@ -86,4 +99,4 @@ declare class TokenStorage {
86
99
  clearAuthState(): void;
87
100
  }
88
101
 
89
- export { type AuthState, IdaasClient, type IdaasConfig, type TokenSet, TokenStorage, type UserInfo, createPKCE, generateNonce, generateState };
102
+ export { type AuthState, IdaasClient, type IdaasConfig, type ServiceTokenState, type SessionLogoutOptions, type TokenSet, TokenStorage, type UserInfo, createPKCE, generateNonce, generateState };
package/dist/index.d.ts CHANGED
@@ -18,6 +18,11 @@ interface TokenSet {
18
18
  refresh_token?: string;
19
19
  scope: string;
20
20
  }
21
+ interface ServiceTokenState {
22
+ accessToken: string;
23
+ expiresAt: number;
24
+ scope: string;
25
+ }
21
26
  interface UserInfo {
22
27
  sub: string;
23
28
  preferred_username?: string;
@@ -35,6 +40,10 @@ interface AuthState {
35
40
  idToken: string | null;
36
41
  expiresAt: number | null;
37
42
  }
43
+ interface SessionLogoutOptions {
44
+ /** Redirect after the server-side session and local tokens are cleared. */
45
+ redirectTo?: string;
46
+ }
38
47
  interface PKCEPair {
39
48
  codeVerifier: string;
40
49
  codeChallenge: string;
@@ -45,6 +54,7 @@ declare class IdaasClient {
45
54
  private endpoints;
46
55
  private storage;
47
56
  private userInfo;
57
+ private serviceTokens;
48
58
  constructor(config: IdaasConfig);
49
59
  init(): Promise<AuthState>;
50
60
  private discover;
@@ -53,13 +63,16 @@ declare class IdaasClient {
53
63
  refreshToken(): Promise<TokenSet | null>;
54
64
  getUserInfo(forceRefresh?: boolean): Promise<UserInfo | null>;
55
65
  getAccessToken(): Promise<string | null>;
66
+ getServiceToken(serviceKey: string): Promise<string | null>;
56
67
  getIdToken(): string | null;
57
68
  getAuthState(): AuthState;
58
69
  isAuthenticated(): boolean;
59
70
  logout(): Promise<void>;
71
+ logoutSession(options?: SessionLogoutOptions): Promise<void>;
60
72
  revokeToken(): Promise<void>;
61
73
  /** Create an authenticated fetch wrapper */
62
74
  fetch(url: string, init?: RequestInit): Promise<Response>;
75
+ fetchService(serviceKey: string, url: string, init?: RequestInit): Promise<Response>;
63
76
  }
64
77
 
65
78
  declare function createPKCE(): Promise<PKCEPair>;
@@ -86,4 +99,4 @@ declare class TokenStorage {
86
99
  clearAuthState(): void;
87
100
  }
88
101
 
89
- export { type AuthState, IdaasClient, type IdaasConfig, type TokenSet, TokenStorage, type UserInfo, createPKCE, generateNonce, generateState };
102
+ export { type AuthState, IdaasClient, type IdaasConfig, type ServiceTokenState, type SessionLogoutOptions, type TokenSet, TokenStorage, type UserInfo, createPKCE, generateNonce, generateState };
package/dist/index.js CHANGED
@@ -254,6 +254,7 @@ var IdaasClient = class {
254
254
  constructor(config) {
255
255
  this.endpoints = null;
256
256
  this.userInfo = null;
257
+ this.serviceTokens = /* @__PURE__ */ new Map();
257
258
  this.config = {
258
259
  scope: "openid profile email",
259
260
  autoDiscovery: true,
@@ -276,6 +277,7 @@ var IdaasClient = class {
276
277
  introspection_endpoint: `${this.config.issuer}/oauth2/introspect`
277
278
  };
278
279
  }
280
+ await this.getAccessToken();
279
281
  return this.getAuthState();
280
282
  }
281
283
  async discover() {
@@ -392,14 +394,40 @@ var IdaasClient = class {
392
394
  return this.userInfo;
393
395
  }
394
396
  async getAccessToken() {
395
- let token = this.storage.getAccessToken();
396
- if (token) return token;
397
- if (this.storage.isTokenExpired()) {
398
- const tokens = await this.refreshToken();
399
- if (tokens) return tokens.access_token;
400
- }
397
+ const token = this.storage.getAccessToken();
398
+ if (token && !this.storage.isTokenExpired()) return token;
399
+ const tokens = await this.refreshToken();
400
+ if (tokens) return tokens.access_token;
401
401
  return null;
402
402
  }
403
+ async getServiceToken(serviceKey) {
404
+ if (!this.endpoints) await this.init();
405
+ const cached = this.serviceTokens.get(serviceKey);
406
+ if (cached && Date.now() < cached.expiresAt - 6e4) {
407
+ return cached.accessToken;
408
+ }
409
+ const baseToken = await this.getAccessToken();
410
+ if (!baseToken) return null;
411
+ const res = await fetch(`${this.config.issuer}/oauth2/business-token`, {
412
+ method: "POST",
413
+ headers: {
414
+ "Content-Type": "application/json",
415
+ Authorization: `Bearer ${baseToken}`
416
+ },
417
+ body: JSON.stringify({ service_key: serviceKey })
418
+ });
419
+ if (!res.ok) {
420
+ this.serviceTokens.delete(serviceKey);
421
+ return null;
422
+ }
423
+ const tokenSet = await res.json();
424
+ this.serviceTokens.set(serviceKey, {
425
+ accessToken: tokenSet.access_token,
426
+ expiresAt: Date.now() + tokenSet.expires_in * 1e3,
427
+ scope: tokenSet.scope
428
+ });
429
+ return tokenSet.access_token;
430
+ }
403
431
  getIdToken() {
404
432
  return this.storage.getIdToken();
405
433
  }
@@ -428,6 +456,17 @@ var IdaasClient = class {
428
456
  }
429
457
  window.location.href = `${this.endpoints.end_session_endpoint}?${params.toString()}`;
430
458
  }
459
+ async logoutSession(options = {}) {
460
+ this.storage.clear();
461
+ this.userInfo = null;
462
+ await fetch(`${this.config.issuer}/auth/logout`, {
463
+ method: "POST",
464
+ credentials: "include"
465
+ }).catch(() => void 0);
466
+ if (options.redirectTo) {
467
+ window.location.href = options.redirectTo;
468
+ }
469
+ }
431
470
  async revokeToken() {
432
471
  if (!this.endpoints) await this.init();
433
472
  const refreshToken = this.storage.getRefreshToken();
@@ -451,6 +490,13 @@ var IdaasClient = class {
451
490
  }
452
491
  return fetch(url, { ...init, headers });
453
492
  }
493
+ async fetchService(serviceKey, url, init) {
494
+ const token = await this.getServiceToken(serviceKey);
495
+ if (!token) throw new Error(`No service token available for ${serviceKey}`);
496
+ const headers = new Headers(init?.headers);
497
+ headers.set("Authorization", `Bearer ${token}`);
498
+ return fetch(url, { ...init, headers });
499
+ }
454
500
  };
455
501
  // Annotate the CommonJS export names for ESM import in node:
456
502
  0 && (module.exports = {
package/dist/index.mjs CHANGED
@@ -224,6 +224,7 @@ var IdaasClient = class {
224
224
  constructor(config) {
225
225
  this.endpoints = null;
226
226
  this.userInfo = null;
227
+ this.serviceTokens = /* @__PURE__ */ new Map();
227
228
  this.config = {
228
229
  scope: "openid profile email",
229
230
  autoDiscovery: true,
@@ -246,6 +247,7 @@ var IdaasClient = class {
246
247
  introspection_endpoint: `${this.config.issuer}/oauth2/introspect`
247
248
  };
248
249
  }
250
+ await this.getAccessToken();
249
251
  return this.getAuthState();
250
252
  }
251
253
  async discover() {
@@ -362,14 +364,40 @@ var IdaasClient = class {
362
364
  return this.userInfo;
363
365
  }
364
366
  async getAccessToken() {
365
- let token = this.storage.getAccessToken();
366
- if (token) return token;
367
- if (this.storage.isTokenExpired()) {
368
- const tokens = await this.refreshToken();
369
- if (tokens) return tokens.access_token;
370
- }
367
+ const token = this.storage.getAccessToken();
368
+ if (token && !this.storage.isTokenExpired()) return token;
369
+ const tokens = await this.refreshToken();
370
+ if (tokens) return tokens.access_token;
371
371
  return null;
372
372
  }
373
+ async getServiceToken(serviceKey) {
374
+ if (!this.endpoints) await this.init();
375
+ const cached = this.serviceTokens.get(serviceKey);
376
+ if (cached && Date.now() < cached.expiresAt - 6e4) {
377
+ return cached.accessToken;
378
+ }
379
+ const baseToken = await this.getAccessToken();
380
+ if (!baseToken) return null;
381
+ const res = await fetch(`${this.config.issuer}/oauth2/business-token`, {
382
+ method: "POST",
383
+ headers: {
384
+ "Content-Type": "application/json",
385
+ Authorization: `Bearer ${baseToken}`
386
+ },
387
+ body: JSON.stringify({ service_key: serviceKey })
388
+ });
389
+ if (!res.ok) {
390
+ this.serviceTokens.delete(serviceKey);
391
+ return null;
392
+ }
393
+ const tokenSet = await res.json();
394
+ this.serviceTokens.set(serviceKey, {
395
+ accessToken: tokenSet.access_token,
396
+ expiresAt: Date.now() + tokenSet.expires_in * 1e3,
397
+ scope: tokenSet.scope
398
+ });
399
+ return tokenSet.access_token;
400
+ }
373
401
  getIdToken() {
374
402
  return this.storage.getIdToken();
375
403
  }
@@ -398,6 +426,17 @@ var IdaasClient = class {
398
426
  }
399
427
  window.location.href = `${this.endpoints.end_session_endpoint}?${params.toString()}`;
400
428
  }
429
+ async logoutSession(options = {}) {
430
+ this.storage.clear();
431
+ this.userInfo = null;
432
+ await fetch(`${this.config.issuer}/auth/logout`, {
433
+ method: "POST",
434
+ credentials: "include"
435
+ }).catch(() => void 0);
436
+ if (options.redirectTo) {
437
+ window.location.href = options.redirectTo;
438
+ }
439
+ }
401
440
  async revokeToken() {
402
441
  if (!this.endpoints) await this.init();
403
442
  const refreshToken = this.storage.getRefreshToken();
@@ -421,6 +460,13 @@ var IdaasClient = class {
421
460
  }
422
461
  return fetch(url, { ...init, headers });
423
462
  }
463
+ async fetchService(serviceKey, url, init) {
464
+ const token = await this.getServiceToken(serviceKey);
465
+ if (!token) throw new Error(`No service token available for ${serviceKey}`);
466
+ const headers = new Headers(init?.headers);
467
+ headers.set("Authorization", `Bearer ${token}`);
468
+ return fetch(url, { ...init, headers });
469
+ }
424
470
  };
425
471
  export {
426
472
  IdaasClient,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zskj-idaas/sdk",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "IDaaS OIDC Client SDK for browser applications — supports Authorization Code Flow with PKCE, token management, and authenticated fetch.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -26,6 +26,7 @@
26
26
  "scripts": {
27
27
  "build": "tsup src/index.ts --format cjs,esm --dts --clean",
28
28
  "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
29
+ "test": "vitest run",
29
30
  "prepublishOnly": "npm run build"
30
31
  },
31
32
  "keywords": [
@@ -57,9 +58,9 @@
57
58
  "not dead",
58
59
  "not ie 11"
59
60
  ],
60
- "dependencies": {},
61
61
  "devDependencies": {
62
62
  "tsup": "^8.2.0",
63
- "typescript": "^5.6.0"
63
+ "typescript": "^5.6.0",
64
+ "vitest": "^4.1.7"
64
65
  }
65
66
  }