@iqauth/sdk 2.2.0 → 2.3.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.
Files changed (60) hide show
  1. package/README.md +24 -0
  2. package/dist/browser-session.d.mts +1 -2
  3. package/dist/browser-session.d.ts +1 -2
  4. package/dist/browser-session.js +89 -68
  5. package/dist/browser-session.mjs +2 -1
  6. package/dist/browser.d.mts +1 -1
  7. package/dist/browser.d.ts +1 -1
  8. package/dist/browser.js +13 -2
  9. package/dist/browser.mjs +2 -2
  10. package/dist/{chunk-D72UL5HL.mjs → chunk-EKTNEZIH.mjs} +4 -4
  11. package/dist/{chunk-M4J6BPK7.mjs → chunk-KGEPDXHU.mjs} +10 -1
  12. package/dist/{chunk-QZB745C2.mjs → chunk-RACIPVLD.mjs} +13 -2
  13. package/dist/chunk-UNYDG2L4.mjs +209 -0
  14. package/dist/{chunk-MDUHPQMM.mjs → chunk-W3F4JYGP.mjs} +8 -180
  15. package/dist/{chunk-QEJB7WEQ.mjs → chunk-WQWBJSSS.mjs} +1 -1
  16. package/dist/cli/index.mjs +1 -1
  17. package/dist/{client-DXbHb2ul.d.ts → client-DTX4hNdS.d.ts} +16 -21
  18. package/dist/{client-Dv4v92Mj.d.mts → client-vdh2a9fJ.d.mts} +16 -21
  19. package/dist/{doctor-XCI77BQS.mjs → doctor-A5E7LSFW.mjs} +1 -1
  20. package/dist/{express-BZmF1llh.d.mts → express-A0-dWEMy.d.mts} +1 -1
  21. package/dist/{express-B4o3P8vK.d.ts → express-Bo_pJKHN.d.ts} +1 -1
  22. package/dist/express.d.mts +75 -5
  23. package/dist/express.d.ts +75 -5
  24. package/dist/express.js +300 -70
  25. package/dist/express.mjs +208 -7
  26. package/dist/fastify.js +101 -70
  27. package/dist/fastify.mjs +8 -6
  28. package/dist/hono.js +100 -70
  29. package/dist/hono.mjs +7 -6
  30. package/dist/index.d.mts +2 -3
  31. package/dist/index.d.ts +2 -3
  32. package/dist/index.js +90 -69
  33. package/dist/index.mjs +15 -13
  34. package/dist/mobile.d.mts +1 -2
  35. package/dist/mobile.d.ts +1 -2
  36. package/dist/mobile.js +89 -68
  37. package/dist/mobile.mjs +2 -1
  38. package/dist/next.d.mts +9 -0
  39. package/dist/next.d.ts +9 -0
  40. package/dist/next.js +99 -1616
  41. package/dist/next.mjs +9 -9
  42. package/dist/react.d.mts +1 -1
  43. package/dist/react.d.ts +1 -1
  44. package/dist/react.js +13 -2
  45. package/dist/react.mjs +2 -2
  46. package/dist/server/handlers.d.mts +2 -0
  47. package/dist/server/handlers.d.ts +2 -0
  48. package/dist/server/handlers.js +10 -1
  49. package/dist/server/handlers.mjs +2 -2
  50. package/dist/server.d.mts +2 -3
  51. package/dist/server.d.ts +2 -3
  52. package/dist/server.js +99 -69
  53. package/dist/server.mjs +7 -6
  54. package/dist/service.d.mts +1 -2
  55. package/dist/service.d.ts +1 -2
  56. package/dist/service.js +89 -68
  57. package/dist/service.mjs +2 -1
  58. package/dist/{signIn-D_kP3v-c.d.mts → signIn-Cd0P4y9d.d.mts} +8 -0
  59. package/dist/{signIn-BVDTIA_t.d.ts → signIn-DKakyzeu.d.ts} +8 -0
  60. package/package.json +3 -2
package/dist/next.js CHANGED
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // src/next.ts
@@ -105,7 +95,7 @@ function assertPublishableKey(raw, opts) {
105
95
  if (!isValidIssuerUrl(decoded.iss)) {
106
96
  throw new IQAuthError(
107
97
  "CONFIG_INVALID",
108
- `${ctx}IQAuth publishable key encodes an invalid issuer (iss=${JSON.stringify(decoded.iss)}). Expected a fully-qualified URL like "https://auth.example.com" (scheme required). Regenerate the key from the IQAuth admin console, or set IQAUTH_ISSUER to the correct issuer URL as a temporary workaround.`
98
+ `${ctx}IQAuth publishable key encodes an invalid issuer (iss=${JSON.stringify(decoded.iss)}). Expected a fully-qualified URL like "https://auth.example.com" (scheme required). Regenerate the key from the IQAuth admin console \u2014 the new key will encode a valid issuer URL.`
109
99
  );
110
100
  }
111
101
  return { mode: shapeMatch[1], iss: decoded.iss, appId: decoded.appId, tenantId: decoded.tenantId, kid: decoded.kid, raw };
@@ -307,6 +297,15 @@ async function handleSignout(config, input) {
307
297
  } catch {
308
298
  }
309
299
  }
300
+ if (input.endSsoSession !== false && input.ssoCookieHeader) {
301
+ try {
302
+ await cfg.fetchImpl(`${cfg.issuer}/oidc/sso-logout`, {
303
+ method: "POST",
304
+ headers: { Cookie: input.ssoCookieHeader }
305
+ });
306
+ } catch {
307
+ }
308
+ }
310
309
  return {
311
310
  status: 200,
312
311
  body: { success: true, data: { signedOut: true } },
@@ -314,369 +313,8 @@ async function handleSignout(config, input) {
314
313
  };
315
314
  }
316
315
 
317
- // src/http.ts
318
- var DEFAULT_RETRY = {
319
- maxAttempts: 3,
320
- baseDelayMs: 100,
321
- maxDelayMs: 2e3
322
- };
323
- function resolveRetry(cfg) {
324
- return {
325
- maxAttempts: Math.max(1, cfg?.maxAttempts ?? DEFAULT_RETRY.maxAttempts),
326
- baseDelayMs: Math.max(0, cfg?.baseDelayMs ?? DEFAULT_RETRY.baseDelayMs),
327
- maxDelayMs: Math.max(0, cfg?.maxDelayMs ?? DEFAULT_RETRY.maxDelayMs)
328
- };
329
- }
330
- function sleep(ms) {
331
- if (ms <= 0) return Promise.resolve();
332
- return new Promise((resolve2) => setTimeout(resolve2, ms));
333
- }
334
- var HttpClient = class {
335
- constructor(config) {
336
- this.refreshPromise = null;
337
- this.config = config;
338
- this.retryConfig = resolveRetry(config.retry);
339
- }
340
- computeBackoffDelay(attempt) {
341
- const exp = Math.min(this.retryConfig.maxDelayMs, this.retryConfig.baseDelayMs * 2 ** (attempt - 1));
342
- return Math.floor(Math.random() * exp);
343
- }
344
- isRetryableStatus(status) {
345
- return status === 429 || status >= 500 && status <= 599;
346
- }
347
- async fetchWithRetry(url, init) {
348
- const { maxAttempts } = this.retryConfig;
349
- let lastError;
350
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
351
- try {
352
- const res = await fetch(url, init);
353
- if (this.isRetryableStatus(res.status) && attempt < maxAttempts) {
354
- await sleep(this.computeBackoffDelay(attempt));
355
- continue;
356
- }
357
- return res;
358
- } catch (err) {
359
- lastError = err;
360
- if (attempt >= maxAttempts) break;
361
- await sleep(this.computeBackoffDelay(attempt));
362
- }
363
- }
364
- throw lastError instanceof Error ? lastError : new IQAuthError("INTERNAL_ERROR", "Network request failed");
365
- }
366
- get baseUrl() {
367
- return this.config.baseUrl;
368
- }
369
- get environment() {
370
- return this.config.environment;
371
- }
372
- isBrowserSession() {
373
- return this.config.environment === "browser_session";
374
- }
375
- hasCredentials() {
376
- return this.isBrowserSession() || !!(this.config.getApiKey() || this.config.getAccessToken());
377
- }
378
- buildHeaders(overrideAuth) {
379
- const headers = {
380
- "Content-Type": "application/json"
381
- };
382
- if (this.isBrowserSession()) {
383
- const headerName = this.config.sessionHeaderName || "x-iqauth-session";
384
- headers[headerName] = this.config.sessionHeaderValue || "cookie";
385
- return headers;
386
- }
387
- const authMode = overrideAuth || (this.config.getApiKey() ? "apikey" : "bearer");
388
- if (authMode === "apikey") {
389
- const apiKey = this.config.getApiKey();
390
- if (apiKey) {
391
- headers["X-API-Key"] = apiKey;
392
- }
393
- } else {
394
- const token = this.config.getAccessToken();
395
- if (token) {
396
- headers["Authorization"] = `Bearer ${token}`;
397
- }
398
- }
399
- return headers;
400
- }
401
- isTokenExpiringSoon() {
402
- const token = this.config.getAccessToken();
403
- if (!token) return false;
404
- try {
405
- const parts = token.split(".");
406
- if (parts.length !== 3) return false;
407
- const payload = JSON.parse(
408
- typeof atob === "function" ? atob(parts[1].replace(/-/g, "+").replace(/_/g, "/")) : Buffer.from(parts[1], "base64url").toString("utf8")
409
- );
410
- if (!payload.exp) return false;
411
- const now = Math.floor(Date.now() / 1e3);
412
- return payload.exp - now < 60;
413
- } catch {
414
- return false;
415
- }
416
- }
417
- async attemptRefresh() {
418
- if (this.refreshPromise) {
419
- return this.refreshPromise;
420
- }
421
- this.refreshPromise = (async () => {
422
- try {
423
- const res = await this.fetchWithRetry(`${this.config.baseUrl}/api/v1/auth/refresh`, {
424
- method: "POST",
425
- headers: this.buildHeaders(),
426
- ...this.isBrowserSession() ? { credentials: "include" } : (() => {
427
- const refreshToken = this.config.getRefreshToken();
428
- if (!refreshToken) throw new IQAuthError("TOKEN_INVALID", "No refresh token available");
429
- return { body: JSON.stringify({ refreshToken }) };
430
- })()
431
- });
432
- const body = await res.json();
433
- if (!body.success) {
434
- throw new IQAuthError(
435
- body.error.code,
436
- body.error.message,
437
- res.status,
438
- body
439
- );
440
- }
441
- if (this.isBrowserSession()) {
442
- return;
443
- }
444
- if (!body.data.accessToken || !body.data.refreshToken) {
445
- throw new IQAuthError("TOKEN_INVALID", "Refresh response did not include a token pair");
446
- }
447
- const tokens = {
448
- accessToken: body.data.accessToken,
449
- refreshToken: body.data.refreshToken
450
- };
451
- this.config.setTokens(tokens);
452
- this.config.onTokenRefresh?.(tokens);
453
- } finally {
454
- this.refreshPromise = null;
455
- }
456
- })();
457
- return this.refreshPromise;
458
- }
459
- async request(method, path, body, options) {
460
- return this.requestWithRetry(method, path, body, options, false);
461
- }
462
- async requestWithRetry(method, path, body, options, hasRetried) {
463
- if (this.config.autoRefresh && !options?.skipAutoRefresh && !this.isBrowserSession() && this.config.getRefreshToken() && this.isTokenExpiringSoon()) {
464
- await this.attemptRefresh();
465
- }
466
- const url = `${this.config.baseUrl}${path}`;
467
- const headers = this.buildHeaders(options?.authMode);
468
- const fetchOptions = {
469
- method,
470
- headers,
471
- ...this.isBrowserSession() ? { credentials: "include" } : {}
472
- };
473
- if (body !== void 0 && method !== "GET") {
474
- fetchOptions.body = JSON.stringify(body);
475
- }
476
- const res = await this.fetchWithRetry(url, fetchOptions);
477
- if (res.status === 204) {
478
- return void 0;
479
- }
480
- const responseBody = await res.json();
481
- if (!responseBody.success) {
482
- const shouldRetryRefresh = !hasRetried && this.config.autoRefresh && !options?.skipAutoRefresh && responseBody.error.code === "TOKEN_EXPIRED" && (this.isBrowserSession() || !!this.config.getRefreshToken());
483
- if (shouldRetryRefresh) {
484
- await this.attemptRefresh();
485
- return this.requestWithRetry(method, path, body, options, true);
486
- }
487
- throw new IQAuthError(
488
- responseBody.error.code,
489
- responseBody.error.message,
490
- res.status,
491
- responseBody
492
- );
493
- }
494
- return responseBody.data;
495
- }
496
- async requestRaw(method, path, body) {
497
- const url = `${this.config.baseUrl}${path}`;
498
- const headers = { "Content-Type": "application/json" };
499
- if (this.isBrowserSession()) {
500
- const headerName = this.config.sessionHeaderName || "x-iqauth-session";
501
- headers[headerName] = this.config.sessionHeaderValue || "cookie";
502
- }
503
- const token = this.config.getAccessToken();
504
- if (token) {
505
- headers["Authorization"] = `Bearer ${token}`;
506
- }
507
- const fetchOptions = { method, headers };
508
- if (this.isBrowserSession()) {
509
- fetchOptions.credentials = "include";
510
- }
511
- if (body !== void 0 && method !== "GET") {
512
- fetchOptions.body = JSON.stringify(body);
513
- }
514
- const res = await fetch(url, fetchOptions);
515
- return await res.json();
516
- }
517
- };
518
-
519
- // src/modules/auth.ts
520
- function parseLoginResponse(data, browserSessionMode) {
521
- if (data.accessToken && data.refreshToken && data.user) {
522
- return {
523
- status: "authenticated",
524
- authMode: "token",
525
- tokens: { accessToken: data.accessToken, refreshToken: data.refreshToken },
526
- user: data.user
527
- };
528
- }
529
- if (browserSessionMode && data.user) {
530
- return {
531
- status: "authenticated",
532
- authMode: "session",
533
- user: data.user
534
- };
535
- }
536
- if (data.mfaChallengeToken && !data.tenantSelectionToken) {
537
- return {
538
- status: "mfa_required",
539
- mfaChallengeToken: data.mfaChallengeToken,
540
- availableMethods: data.availableMethods ?? []
541
- };
542
- }
543
- if (data.tenantSelectionToken && data.tenants) {
544
- return {
545
- status: "tenant_selection",
546
- tenantSelectionToken: data.tenantSelectionToken,
547
- tenants: data.tenants
548
- };
549
- }
550
- throw new Error("Unexpected login response shape");
551
- }
552
- var AuthModule = class {
553
- constructor(http) {
554
- this.http = http;
555
- }
556
- async login(email, password) {
557
- const data = await this.http.request(
558
- "POST",
559
- "/api/v1/auth/login",
560
- { email, password },
561
- { skipAutoRefresh: true }
562
- );
563
- return parseLoginResponse(data, this.http.isBrowserSession());
564
- }
565
- async signup(input) {
566
- const data = await this.http.request(
567
- "POST",
568
- "/api/v1/auth/signup",
569
- input,
570
- { skipAutoRefresh: true }
571
- );
572
- return parseLoginResponse(data, this.http.isBrowserSession());
573
- }
574
- async completeMfa(mfaChallengeToken, code, method) {
575
- const data = await this.http.request(
576
- "POST",
577
- "/api/v1/mfa/verify",
578
- { mfaChallengeToken, code, method },
579
- { skipAutoRefresh: true }
580
- );
581
- return parseMfaResponse(data, this.http.isBrowserSession());
582
- }
583
- async completeMfaWithBackup(mfaChallengeToken, backupCode) {
584
- const data = await this.http.request(
585
- "POST",
586
- "/api/v1/mfa/verify-backup",
587
- { mfaChallengeToken, backupCode },
588
- { skipAutoRefresh: true }
589
- );
590
- return parseMfaResponse(data, this.http.isBrowserSession());
591
- }
592
- async sendMfaChallenge(mfaChallengeToken, method) {
593
- return this.http.request("POST", "/api/v1/mfa/challenge", {
594
- mfaChallengeToken,
595
- method
596
- }, { skipAutoRefresh: true });
597
- }
598
- async selectTenant(tenantSelectionToken, tenantId) {
599
- const data = await this.http.request(
600
- "POST",
601
- "/api/v1/auth/select-tenant",
602
- {
603
- tenantSelectionToken,
604
- tenantId
605
- },
606
- { skipAutoRefresh: true }
607
- );
608
- return parseLoginResponse(data, this.http.isBrowserSession());
609
- }
610
- async logout() {
611
- return this.http.request("POST", "/api/v1/auth/logout");
612
- }
613
- async logoutAll() {
614
- return this.http.request("POST", "/api/v1/auth/logout-all");
615
- }
616
- async refreshTokens(refreshToken) {
617
- if (this.http.isBrowserSession()) {
618
- throw new Error("refreshTokens(refreshToken) is not used in browser_session mode; the backend session should own refresh.");
619
- }
620
- const data = await this.http.request(
621
- "POST",
622
- "/api/v1/auth/refresh",
623
- { refreshToken },
624
- { skipAutoRefresh: true }
625
- );
626
- return { accessToken: data.accessToken, refreshToken: data.refreshToken };
627
- }
628
- async forgotPassword(email) {
629
- return this.http.request("POST", "/api/v1/auth/password/reset/request", { email }, { skipAutoRefresh: true });
630
- }
631
- async resetPassword(token, newPassword) {
632
- return this.http.request("POST", "/api/v1/auth/password/reset/confirm", { token, newPassword }, { skipAutoRefresh: true });
633
- }
634
- async changePassword(currentPassword, newPassword) {
635
- return this.http.request("POST", "/api/v1/auth/password/change", {
636
- currentPassword,
637
- newPassword
638
- });
639
- }
640
- async verifyToken() {
641
- return this.http.request("GET", "/api/v1/auth/verify");
642
- }
643
- async exchangeOAuthCode(code) {
644
- const data = await this.http.request(
645
- "POST",
646
- "/api/v1/auth/oauth/exchange",
647
- { code },
648
- { skipAutoRefresh: true }
649
- );
650
- return parseLoginResponse(data, this.http.isBrowserSession());
651
- }
652
- async getSessionUser() {
653
- return this.http.request("GET", "/api/v1/auth/me");
654
- }
655
- };
656
- function parseMfaResponse(data, browserSessionMode) {
657
- if (data.accessToken && data.refreshToken && data.user) {
658
- return {
659
- authMode: "token",
660
- tokens: { accessToken: data.accessToken, refreshToken: data.refreshToken },
661
- user: data.user,
662
- ...data.remainingBackupCodes !== void 0 ? { remainingBackupCodes: data.remainingBackupCodes } : {},
663
- ...data.warning ? { warning: data.warning } : {}
664
- };
665
- }
666
- if (browserSessionMode && data.user) {
667
- return {
668
- authMode: "session",
669
- user: data.user,
670
- ...data.remainingBackupCodes !== void 0 ? { remainingBackupCodes: data.remainingBackupCodes } : {},
671
- ...data.warning ? { warning: data.warning } : {}
672
- };
673
- }
674
- throw new Error("Unexpected MFA response shape");
675
- }
676
-
677
316
  // src/modules/tokens.ts
678
- var import_crypto = __toESM(require("crypto"));
679
- var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
317
+ var import_jose = require("jose");
680
318
  var JWKS_CACHE_TTL_MS = 60 * 60 * 1e3;
681
319
  var DEFAULT_TOKEN_ISSUER = [
682
320
  "https://auth.dispositioniq.com",
@@ -689,6 +327,24 @@ var DEFAULT_TOKEN_AUDIENCE = [
689
327
  "iqvalidate"
690
328
  ];
691
329
  var DEFAULT_CLOCK_TOLERANCE_SECONDS = 30;
330
+ function decodeProtectedHeader(token) {
331
+ const parts = token.split(".");
332
+ if (parts.length < 2) return null;
333
+ try {
334
+ const padded = parts[0] + "=".repeat((4 - parts[0].length % 4) % 4);
335
+ const b64 = padded.replace(/-/g, "+").replace(/_/g, "/");
336
+ let json;
337
+ if (typeof atob === "function") {
338
+ json = atob(b64);
339
+ } else {
340
+ const { Buffer: Buffer2 } = require("buffer");
341
+ json = Buffer2.from(b64, "base64").toString("utf8");
342
+ }
343
+ return JSON.parse(json);
344
+ } catch {
345
+ return null;
346
+ }
347
+ }
692
348
  var TokensModule = class {
693
349
  constructor(baseUrl, options = {}) {
694
350
  this.jwksCache = null;
@@ -699,49 +355,49 @@ var TokensModule = class {
699
355
  this.defaultClockTolerance = options.clockTolerance ?? DEFAULT_CLOCK_TOLERANCE_SECONDS;
700
356
  }
701
357
  /**
702
- * Verify a JWT access token using RS256 via JWKS from /.well-known/jwks.json.
703
- * Caches JWKS keys for 1 hour. Retries once on unknown `kid`.
704
- *
705
- * @remarks Validates against /.well-known/jwks.json. Issuer, audience, and
706
- * clock tolerance default to client config but can be overridden per call.
358
+ * Verify a JWT access token using RS256/ES256 via JWKS from
359
+ * `/.well-known/jwks.json`. Backed by `jose` (Web Crypto) so it runs on
360
+ * Node, browser, and edge runtimes alike — no `node:crypto` dependency.
361
+ * Caches JWKS for 1 hour and refetches once on unknown `kid`.
707
362
  */
708
363
  async verify(token, options = {}) {
709
- const decoded = import_jsonwebtoken.default.decode(token, { complete: true });
710
- if (!decoded || typeof decoded === "string") {
364
+ const header = decodeProtectedHeader(token);
365
+ if (!header) {
711
366
  throw new IQAuthError("TOKEN_INVALID", "Unable to decode token");
712
367
  }
713
- const kid = decoded.header.kid;
368
+ const kid = header.kid;
714
369
  if (!kid) {
715
370
  throw new IQAuthError("TOKEN_INVALID", "Token missing kid header");
716
371
  }
717
- let publicKey = await this.getPublicKey(kid);
718
- if (!publicKey) {
719
- await this.refreshJwks();
720
- publicKey = await this.getPublicKey(kid);
372
+ let cache = await this.ensureCache();
373
+ if (!cache.byKid.has(kid)) {
374
+ this.jwksCache = null;
375
+ cache = await this.ensureCache();
721
376
  }
722
- if (!publicKey) {
377
+ if (!cache.byKid.has(kid)) {
723
378
  throw new IQAuthError("TOKEN_INVALID", `Unknown key ID: ${kid}`);
724
379
  }
725
380
  const issuer = options.issuer ?? this.defaultIssuer;
726
381
  const audience = options.audience ?? this.defaultAudience;
727
382
  const clockTolerance = options.clockTolerance ?? this.defaultClockTolerance;
728
- const algorithms = options.algorithms ?? ["RS256"];
383
+ const algorithms = options.algorithms ?? ["RS256", "ES256"];
384
+ const verifyOptions = {
385
+ algorithms,
386
+ clockTolerance,
387
+ issuer,
388
+ audience
389
+ };
729
390
  try {
730
- const verifyOptions = {
731
- algorithms,
732
- clockTolerance,
733
- // The jsonwebtoken types insist on tuple types for arrays; runtime
734
- // accepts plain string[] so we cast to satisfy the compiler.
735
- issuer,
736
- audience
737
- };
738
- const verified = import_jsonwebtoken.default.verify(token, publicKey, verifyOptions);
739
- return verified;
391
+ const { payload } = await (0, import_jose.jwtVerify)(token, cache.verifier, verifyOptions);
392
+ return payload;
740
393
  } catch (err) {
394
+ if (err instanceof import_jose.errors.JWTExpired) {
395
+ throw new IQAuthError("TOKEN_EXPIRED", "Token has expired");
396
+ }
397
+ if (err instanceof import_jose.errors.JOSEError) {
398
+ throw new IQAuthError("TOKEN_INVALID", err.message);
399
+ }
741
400
  if (err instanceof Error) {
742
- if (err.name === "TokenExpiredError") {
743
- throw new IQAuthError("TOKEN_EXPIRED", "Token has expired");
744
- }
745
401
  throw new IQAuthError("TOKEN_INVALID", err.message);
746
402
  }
747
403
  throw new IQAuthError("TOKEN_INVALID", "Token verification failed");
@@ -749,29 +405,40 @@ var TokensModule = class {
749
405
  }
750
406
  /**
751
407
  * Decode a JWT without verification. Returns null if malformed.
752
- *
753
- * @remarks Local decode only — no network call
754
408
  */
755
409
  decode(token) {
756
- const decoded = import_jsonwebtoken.default.decode(token);
757
- return decoded;
410
+ try {
411
+ const parts = token.split(".");
412
+ if (parts.length < 2) return null;
413
+ const payload = parts[1];
414
+ const padded = payload + "=".repeat((4 - payload.length % 4) % 4);
415
+ const b64 = padded.replace(/-/g, "+").replace(/_/g, "/");
416
+ let json;
417
+ if (typeof atob === "function") {
418
+ json = atob(b64);
419
+ } else {
420
+ const { Buffer: Buffer2 } = require("buffer");
421
+ json = Buffer2.from(b64, "base64").toString("utf8");
422
+ }
423
+ try {
424
+ json = decodeURIComponent(escape(json));
425
+ } catch {
426
+ }
427
+ const claims = JSON.parse(json);
428
+ if (!claims || typeof claims !== "object") return null;
429
+ return claims;
430
+ } catch {
431
+ return null;
432
+ }
758
433
  }
759
- /**
760
- * Check if a token is expired based on the `exp` claim.
761
- *
762
- * @remarks Local check only — no network call
763
- */
434
+ /** Check if a token is expired based on the `exp` claim. */
764
435
  isExpired(token) {
765
436
  const claims = this.decode(token);
766
437
  if (!claims?.exp) return true;
767
438
  const now = Math.floor(Date.now() / 1e3);
768
439
  return claims.exp <= now;
769
440
  }
770
- /**
771
- * Get the claims from a token without verification.
772
- *
773
- * @remarks Local decode only — no network call
774
- */
441
+ /** Get the claims from a token without verification. */
775
442
  getClaims(token) {
776
443
  const claims = this.decode(token);
777
444
  if (!claims) {
@@ -779,11 +446,15 @@ var TokensModule = class {
779
446
  }
780
447
  return claims;
781
448
  }
782
- async getPublicKey(kid) {
783
- if (!this.jwksCache || Date.now() - this.jwksCache.fetchedAt > JWKS_CACHE_TTL_MS) {
784
- await this.refreshJwks();
449
+ async ensureCache() {
450
+ if (this.jwksCache && Date.now() - this.jwksCache.fetchedAt <= JWKS_CACHE_TTL_MS) {
451
+ return this.jwksCache;
452
+ }
453
+ await this.refreshJwks();
454
+ if (!this.jwksCache) {
455
+ throw new IQAuthError("INTERNAL_ERROR", "JWKS cache unavailable after refresh");
785
456
  }
786
- return this.jwksCache?.keys.get(kid) ?? null;
457
+ return this.jwksCache;
787
458
  }
788
459
  async refreshJwks() {
789
460
  if (this.inFlightRefresh) {
@@ -810,1218 +481,30 @@ var TokensModule = class {
810
481
  "Malformed JWKS response: expected { keys: [...] }"
811
482
  );
812
483
  }
813
- const keys = /* @__PURE__ */ new Map();
484
+ const byKid = /* @__PURE__ */ new Set();
814
485
  for (const key of jwks.keys) {
815
- if (!key || typeof key.kid !== "string" || typeof key.n !== "string" || typeof key.e !== "string") {
486
+ if (!key || typeof key.kid !== "string" || typeof key.n !== "string" && typeof key.x !== "string" || key.kty === "RSA" && (typeof key.n !== "string" || typeof key.e !== "string")) {
816
487
  throw new IQAuthError(
817
488
  "INTERNAL_ERROR",
818
489
  "Malformed JWKS response: key missing required fields"
819
490
  );
820
491
  }
821
- const pem = this.jwkToPem(key);
822
- keys.set(key.kid, pem);
492
+ byKid.add(key.kid);
823
493
  }
824
- this.jwksCache = { keys, fetchedAt: Date.now() };
494
+ const verifier = (0, import_jose.createLocalJWKSet)({ keys: jwks.keys });
495
+ this.jwksCache = { raw: jwks.keys, byKid, verifier, fetchedAt: Date.now() };
825
496
  } finally {
826
497
  this.inFlightRefresh = null;
827
498
  }
828
499
  })();
829
500
  return this.inFlightRefresh;
830
501
  }
831
- jwkToPem(jwk) {
832
- const keyObject = import_crypto.default.createPublicKey({
833
- key: {
834
- kty: jwk.kty,
835
- n: jwk.n,
836
- e: jwk.e
837
- },
838
- format: "jwk"
839
- });
840
- return keyObject.export({ type: "spki", format: "pem" });
841
- }
842
502
  /** @internal Exposed for testing — clears JWKS cache */
843
503
  clearCache() {
844
504
  this.jwksCache = null;
845
505
  }
846
506
  };
847
507
 
848
- // src/modules/sessions.ts
849
- var SessionsModule = class {
850
- constructor(http) {
851
- this.http = http;
852
- }
853
- /**
854
- * List all active sessions for the current user.
855
- *
856
- * @remarks Wraps GET /api/v1/sessions
857
- */
858
- async list() {
859
- return this.http.request("GET", "/api/v1/sessions");
860
- }
861
- /**
862
- * Revoke (terminate) a specific session by ID.
863
- *
864
- * @remarks Wraps DELETE /api/v1/sessions/:sessionId
865
- */
866
- async revoke(sessionId) {
867
- return this.http.request("DELETE", `/api/v1/sessions/${sessionId}`);
868
- }
869
- /**
870
- * Revoke all sessions for the current user.
871
- *
872
- * @remarks Wraps POST /api/v1/auth/logout-all
873
- */
874
- async revokeAll() {
875
- return this.http.request("POST", "/api/v1/auth/logout-all");
876
- }
877
- };
878
-
879
- // src/modules/users.ts
880
- var UsersModule = class {
881
- constructor(http) {
882
- this.http = http;
883
- }
884
- /**
885
- * Get the currently authenticated user's profile.
886
- *
887
- * @remarks Wraps GET /api/v1/users/me
888
- */
889
- async getCurrent() {
890
- return this.http.request("GET", "/api/v1/users/me");
891
- }
892
- /**
893
- * Get a user by ID.
894
- *
895
- * @remarks Wraps GET /api/v1/users/:id
896
- */
897
- async getById(userId) {
898
- return this.http.request("GET", `/api/v1/users/${userId}`);
899
- }
900
- /**
901
- * List users in the current tenant. Requires tenant_admin role.
902
- *
903
- * @remarks Wraps GET /api/v1/users
904
- */
905
- async list(params) {
906
- const query = new URLSearchParams();
907
- if (params?.email) query.set("email", params.email);
908
- if (params?.tenantId) query.set("tenantId", params.tenantId);
909
- const qs = query.toString();
910
- return this.http.request("GET", `/api/v1/users${qs ? `?${qs}` : ""}`);
911
- }
912
- /**
913
- * Provision (create) a new user in a tenant. Requires platform_admin or tenant-scoped API key with admin role.
914
- *
915
- * @remarks Wraps POST /api/v1/tenants/:tenantId/users/provision
916
- */
917
- async create(tenantId, data) {
918
- return this.http.request("POST", `/api/v1/tenants/${tenantId}/users/provision`, data);
919
- }
920
- /**
921
- * Update the current user's profile (name, picture).
922
- *
923
- * @remarks Wraps PATCH /api/v1/users/me
924
- */
925
- async update(data) {
926
- return this.http.request("PATCH", "/api/v1/users/me", data);
927
- }
928
- /**
929
- * Deactivate a user in the current tenant. Requires tenant_admin role.
930
- *
931
- * @remarks Wraps PATCH /api/v1/users/:id/deactivate
932
- */
933
- async deactivate(userId) {
934
- return this.http.request("PATCH", `/api/v1/users/${userId}/deactivate`);
935
- }
936
- /**
937
- * Reactivate a user in the current tenant. Requires tenant_admin role.
938
- *
939
- * @remarks Wraps PATCH /api/v1/users/:id/reactivate
940
- */
941
- async reactivate(userId) {
942
- return this.http.request("PATCH", `/api/v1/users/${userId}/reactivate`);
943
- }
944
- /**
945
- * Unlock a locked user account in the current tenant. Requires tenant_admin role.
946
- *
947
- * @remarks Wraps PATCH /api/v1/users/:id/unlock
948
- */
949
- async unlock(userId) {
950
- return this.http.request("PATCH", `/api/v1/users/${userId}/unlock`);
951
- }
952
- /**
953
- * Get effective permissions for a user for a specific product.
954
- *
955
- * @remarks Wraps GET /api/v1/users/:id/permissions?product=...
956
- */
957
- async getPermissions(userId, product) {
958
- return this.http.request("GET", `/api/v1/users/${userId}/permissions?product=${encodeURIComponent(product)}`);
959
- }
960
- /**
961
- * Change the current user's password.
962
- *
963
- * @remarks Wraps POST /api/v1/auth/password/change
964
- */
965
- async updatePassword(currentPassword, newPassword) {
966
- return this.http.request("POST", "/api/v1/auth/password/change", {
967
- currentPassword,
968
- newPassword
969
- });
970
- }
971
- };
972
-
973
- // src/modules/permissions.ts
974
- var PermissionsModule = class {
975
- constructor(claimsProvider) {
976
- this.getClaims = claimsProvider;
977
- }
978
- /**
979
- * Get the roles from the current JWT claims.
980
- *
981
- * @remarks Extracted from JWT claim `roles` (string[])
982
- */
983
- getRoles() {
984
- return this.getClaims()?.roles ?? [];
985
- }
986
- /**
987
- * Get the entitlements from the current JWT claims.
988
- *
989
- * @remarks Extracted from JWT claim `entitlements` (string[])
990
- */
991
- getEntitlements() {
992
- return this.getClaims()?.entitlements ?? [];
993
- }
994
- /**
995
- * Check if the current user has a specific role.
996
- *
997
- * @remarks Checks against JWT claim `roles`
998
- */
999
- hasRole(role) {
1000
- return this.getRoles().includes(role);
1001
- }
1002
- /**
1003
- * Check if the current user has a specific entitlement.
1004
- *
1005
- * @remarks Checks against JWT claim `entitlements`
1006
- */
1007
- hasEntitlement(entitlement) {
1008
- return this.getEntitlements().includes(entitlement);
1009
- }
1010
- /**
1011
- * Check if the current user has all of the specified roles.
1012
- *
1013
- * @remarks Checks against JWT claim `roles`
1014
- */
1015
- hasAllRoles(roles) {
1016
- const userRoles = this.getRoles();
1017
- return roles.every((r) => userRoles.includes(r));
1018
- }
1019
- /**
1020
- * Check if the current user has any of the specified roles.
1021
- *
1022
- * @remarks Checks against JWT claim `roles`
1023
- */
1024
- hasAnyRole(roles) {
1025
- const userRoles = this.getRoles();
1026
- return roles.some((r) => userRoles.includes(r));
1027
- }
1028
- /**
1029
- * Check if the current user has all of the specified entitlements.
1030
- *
1031
- * @remarks Checks against JWT claim `entitlements`
1032
- */
1033
- hasAllEntitlements(entitlements) {
1034
- const userEntitlements = this.getEntitlements();
1035
- return entitlements.every((e) => userEntitlements.includes(e));
1036
- }
1037
- /**
1038
- * Check if the current user has any of the specified entitlements.
1039
- *
1040
- * @remarks Checks against JWT claim `entitlements`
1041
- */
1042
- hasAnyEntitlement(entitlements) {
1043
- const userEntitlements = this.getEntitlements();
1044
- return entitlements.some((e) => userEntitlements.includes(e));
1045
- }
1046
- };
1047
-
1048
- // src/modules/oidc.ts
1049
- var import_crypto2 = __toESM(require("crypto"));
1050
- var InMemoryOidcStateStore = class {
1051
- constructor() {
1052
- this.map = /* @__PURE__ */ new Map();
1053
- }
1054
- set(state, value) {
1055
- this.map.set(state, value);
1056
- }
1057
- get(state) {
1058
- const entry = this.map.get(state);
1059
- if (!entry) return null;
1060
- if (entry.expiresAt < Date.now()) {
1061
- this.map.delete(state);
1062
- return null;
1063
- }
1064
- return entry;
1065
- }
1066
- delete(state) {
1067
- this.map.delete(state);
1068
- }
1069
- };
1070
- var DEFAULT_REQUEST_TTL_MS = 10 * 60 * 1e3;
1071
- function base64UrlEncode(buf) {
1072
- return buf.toString("base64").replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
1073
- }
1074
- var OidcModule = class {
1075
- constructor(http, baseUrl, options = {}) {
1076
- this.http = http;
1077
- this.baseUrl = baseUrl;
1078
- this.stateStore = options.stateStore ?? new InMemoryOidcStateStore();
1079
- this.requestTtlMs = options.requestTtlMs ?? DEFAULT_REQUEST_TTL_MS;
1080
- this.tokensModule = options.tokens;
1081
- }
1082
- /** @internal Allow the client to inject its TokensModule after construction. */
1083
- _setTokensModule(tokens) {
1084
- if (!this.tokensModule) this.tokensModule = tokens;
1085
- }
1086
- /**
1087
- * Fetch the OpenID Connect discovery document.
1088
- *
1089
- * @remarks Wraps GET /.well-known/openid-configuration
1090
- */
1091
- async getDiscovery() {
1092
- const res = await fetch(`${this.baseUrl}/.well-known/openid-configuration`);
1093
- if (!res.ok) throw new Error(`Failed to fetch OIDC discovery: ${res.status}`);
1094
- return res.json();
1095
- }
1096
- /**
1097
- * Fetch the JSON Web Key Set.
1098
- *
1099
- * @remarks Wraps GET /.well-known/jwks.json
1100
- */
1101
- async getJwks() {
1102
- const res = await fetch(`${this.baseUrl}/.well-known/jwks.json`);
1103
- if (!res.ok) throw new Error(`Failed to fetch JWKS: ${res.status}`);
1104
- return res.json();
1105
- }
1106
- /**
1107
- * Build an OIDC authorization URL for redirect-based login.
1108
- *
1109
- * @remarks Constructs URL pointing to /oidc/authorize. Prefer
1110
- * {@link createAuthRequest} which also generates and stores PKCE/state/nonce.
1111
- */
1112
- buildAuthorizationUrl(params) {
1113
- const url = new URL("/oidc/authorize", this.baseUrl);
1114
- url.searchParams.set("response_type", "code");
1115
- url.searchParams.set("client_id", params.clientId);
1116
- url.searchParams.set("redirect_uri", params.redirectUri);
1117
- url.searchParams.set("scope", params.scope || "openid");
1118
- url.searchParams.set("state", params.state);
1119
- if (params.nonce) url.searchParams.set("nonce", params.nonce);
1120
- if (params.codeChallenge) url.searchParams.set("code_challenge", params.codeChallenge);
1121
- if (params.codeChallengeMethod) url.searchParams.set("code_challenge_method", params.codeChallengeMethod);
1122
- return url.toString();
1123
- }
1124
- /**
1125
- * Generate `code_verifier`, `code_challenge`, `state`, and `nonce`, persist
1126
- * them via the configured storage adapter, and return an authorization URL
1127
- * ready to redirect the user to.
1128
- */
1129
- async createAuthRequest(params) {
1130
- const codeVerifier = base64UrlEncode(import_crypto2.default.randomBytes(32));
1131
- const codeChallenge = base64UrlEncode(
1132
- import_crypto2.default.createHash("sha256").update(codeVerifier).digest()
1133
- );
1134
- const state = base64UrlEncode(import_crypto2.default.randomBytes(16));
1135
- const nonce = base64UrlEncode(import_crypto2.default.randomBytes(16));
1136
- await this.stateStore.set(state, {
1137
- codeVerifier,
1138
- state,
1139
- nonce,
1140
- redirectUri: params.redirectUri,
1141
- clientId: params.clientId,
1142
- expiresAt: Date.now() + this.requestTtlMs
1143
- });
1144
- const authorizationUrl = this.buildAuthorizationUrl({
1145
- clientId: params.clientId,
1146
- redirectUri: params.redirectUri,
1147
- scope: params.scope,
1148
- state,
1149
- nonce,
1150
- codeChallenge,
1151
- codeChallengeMethod: "S256"
1152
- });
1153
- return {
1154
- authorizationUrl,
1155
- state,
1156
- nonce,
1157
- codeVerifier,
1158
- codeChallenge,
1159
- codeChallengeMethod: "S256"
1160
- };
1161
- }
1162
- /**
1163
- * Validate the callback `state`, exchange the code with the bound PKCE
1164
- * verifier, and verify that the returned `id_token` (if any) carries the
1165
- * stored `nonce` and `aud === clientId`.
1166
- */
1167
- async handleCallback(params) {
1168
- if (!params.state) {
1169
- throw new IQAuthError("VALIDATION_ERROR", "OIDC callback missing state parameter");
1170
- }
1171
- if (!params.code) {
1172
- throw new IQAuthError("VALIDATION_ERROR", "OIDC callback missing code parameter");
1173
- }
1174
- const stored = await this.stateStore.get(params.state);
1175
- if (!stored) {
1176
- throw new IQAuthError("VALIDATION_ERROR", "Unknown or expired OIDC state");
1177
- }
1178
- let tokens;
1179
- try {
1180
- tokens = await this.exchangeCode({
1181
- code: params.code,
1182
- redirectUri: stored.redirectUri,
1183
- clientId: stored.clientId,
1184
- clientSecret: params.clientSecret,
1185
- codeVerifier: stored.codeVerifier
1186
- });
1187
- } finally {
1188
- await this.stateStore.delete(params.state);
1189
- }
1190
- let idTokenClaims = null;
1191
- if (tokens.id_token) {
1192
- if (!this.tokensModule) {
1193
- throw new IQAuthError(
1194
- "INTERNAL_ERROR",
1195
- "OIDC handleCallback received an id_token but no TokensModule is configured for verification"
1196
- );
1197
- }
1198
- idTokenClaims = await this.tokensModule.verify(tokens.id_token, {
1199
- audience: stored.clientId
1200
- });
1201
- const claimsBag = idTokenClaims;
1202
- const tokenNonce = typeof claimsBag.nonce === "string" ? claimsBag.nonce : void 0;
1203
- if (!tokenNonce || tokenNonce !== stored.nonce) {
1204
- throw new IQAuthError(
1205
- "TOKEN_INVALID",
1206
- "OIDC id_token nonce did not match the stored value"
1207
- );
1208
- }
1209
- }
1210
- return { tokens, idTokenClaims };
1211
- }
1212
- /**
1213
- * Exchange an authorization code for tokens at the OIDC token endpoint.
1214
- *
1215
- * @remarks Wraps POST /oidc/token (or /api/v1/oidc/token)
1216
- */
1217
- async exchangeCode(params) {
1218
- const body = {
1219
- grant_type: "authorization_code",
1220
- code: params.code,
1221
- redirect_uri: params.redirectUri,
1222
- client_id: params.clientId
1223
- };
1224
- if (params.clientSecret) body.client_secret = params.clientSecret;
1225
- if (params.codeVerifier) body.code_verifier = params.codeVerifier;
1226
- const res = await fetch(`${this.baseUrl}/oidc/token`, {
1227
- method: "POST",
1228
- headers: { "Content-Type": "application/json" },
1229
- body: JSON.stringify(body)
1230
- });
1231
- if (!res.ok) {
1232
- const err = await res.json().catch(() => ({}));
1233
- throw new Error(
1234
- `OIDC token exchange failed: ${err.error_description || err.error || res.status}`
1235
- );
1236
- }
1237
- return res.json();
1238
- }
1239
- /**
1240
- * Get user info from the OIDC userinfo endpoint.
1241
- *
1242
- * @remarks Wraps GET /oidc/userinfo (requires Bearer token)
1243
- */
1244
- async getUserInfo() {
1245
- if (this.http.isBrowserSession()) {
1246
- throw new Error("oidc.getUserInfo() requires a bearer token and is not supported in browser_session mode.");
1247
- }
1248
- return this.http.requestRaw("GET", "/oidc/userinfo");
1249
- }
1250
- async getClientContext(clientId) {
1251
- const res = await fetch(`${this.baseUrl}/oidc/client-context?client_id=${encodeURIComponent(clientId)}`);
1252
- if (!res.ok) throw new Error(`Failed to fetch OIDC client context: ${res.status}`);
1253
- const payload = await res.json();
1254
- if (!payload.success || !payload.data) {
1255
- throw new Error("OIDC client context response was invalid");
1256
- }
1257
- return payload.data;
1258
- }
1259
- };
1260
-
1261
- // src/modules/tenants.ts
1262
- function normalizeBrandingConfig(config) {
1263
- return {
1264
- ...config,
1265
- brandName: config.brandName ?? config.companyName,
1266
- loginHeadline: config.loginHeadline ?? config.headline ?? null,
1267
- loginSubheadline: config.loginSubheadline ?? config.subheadline ?? null,
1268
- companyName: config.companyName ?? config.brandName,
1269
- headline: config.headline ?? config.loginHeadline ?? null,
1270
- subheadline: config.subheadline ?? config.loginSubheadline ?? null
1271
- };
1272
- }
1273
- var TenantsModule = class {
1274
- constructor(http) {
1275
- this.http = http;
1276
- }
1277
- async getCurrent(tenantId) {
1278
- return this.http.request("GET", `/api/v1/tenants/${tenantId}`);
1279
- }
1280
- async get(tenantId) {
1281
- return this.http.request("GET", `/api/v1/tenants/${tenantId}`);
1282
- }
1283
- async list(params) {
1284
- const query = new URLSearchParams();
1285
- if (params?.vendorId) query.set("vendorId", params.vendorId);
1286
- const qs = query.toString();
1287
- return this.http.request("GET", `/api/v1/tenants${qs ? `?${qs}` : ""}`);
1288
- }
1289
- async create(data) {
1290
- return this.http.request("POST", "/api/v1/tenants", data);
1291
- }
1292
- async update(tenantId, data) {
1293
- return this.http.request("PATCH", `/api/v1/tenants/${tenantId}`, data);
1294
- }
1295
- async delete(tenantId) {
1296
- return this.http.request("DELETE", `/api/v1/tenants/${tenantId}`);
1297
- }
1298
- async promoteToVendor(tenantId, data) {
1299
- return this.http.request("POST", `/api/v1/tenants/${tenantId}/promote-to-vendor`, data);
1300
- }
1301
- async getUsers(tenantId) {
1302
- return this.http.request("GET", `/api/v1/tenants/${tenantId}/users`);
1303
- }
1304
- async inviteUser(tenantId, data) {
1305
- return this.http.request("POST", `/api/v1/tenants/${tenantId}/users/invite`, data);
1306
- }
1307
- async changeUserRole(tenantId, userId, role) {
1308
- return this.http.request("PATCH", `/api/v1/tenants/${tenantId}/users/${userId}/role`, { role });
1309
- }
1310
- async migrateUser(tenantId, userId, data) {
1311
- return this.http.request("POST", `/api/v1/tenants/${tenantId}/users/${userId}/migrate`, data);
1312
- }
1313
- async removeUser(tenantId, userId) {
1314
- return this.http.request("DELETE", `/api/v1/tenants/${tenantId}/users/${userId}`);
1315
- }
1316
- async getPasswordPolicy(tenantId) {
1317
- return this.http.request("GET", `/api/v1/tenants/${tenantId}/password-policy`);
1318
- }
1319
- async updatePasswordPolicy(tenantId, data) {
1320
- return this.http.request("PATCH", `/api/v1/tenants/${tenantId}/password-policy`, data);
1321
- }
1322
- async getMfaPolicies(tenantId) {
1323
- return this.http.request("GET", `/api/v1/tenants/${tenantId}/mfa-policies`);
1324
- }
1325
- async updateMfaPolicy(tenantId, role, data) {
1326
- return this.http.request("PATCH", `/api/v1/tenants/${tenantId}/mfa-policies/${role}`, data);
1327
- }
1328
- async getPublicBranding(params) {
1329
- const query = new URLSearchParams();
1330
- if (params?.vendor) query.set("vendor", params.vendor);
1331
- const qs = query.toString();
1332
- const url = `${this.http.baseUrl}/api/public/branding${qs ? `?${qs}` : ""}`;
1333
- const res = await fetch(url);
1334
- if (!res.ok) return null;
1335
- const body = await res.json();
1336
- if (body.success && body.data) return normalizeBrandingConfig(body.data);
1337
- return null;
1338
- }
1339
- async getPublicBrandingBySlug(vendorSlug) {
1340
- const url = `${this.http.baseUrl}/api/public/branding/by-slug/${encodeURIComponent(vendorSlug)}`;
1341
- const res = await fetch(url);
1342
- if (!res.ok) return null;
1343
- const body = await res.json();
1344
- if (body.success && body.data) return normalizeBrandingConfig(body.data);
1345
- return null;
1346
- }
1347
- };
1348
-
1349
- // src/modules/apps.ts
1350
- var AppsModule = class {
1351
- constructor(http) {
1352
- this.http = http;
1353
- }
1354
- /**
1355
- * Self-service Phase A: provision an app + OIDC client + key pair in one shot.
1356
- * Caller must be authenticated as a tenant_admin (or platform_admin).
1357
- *
1358
- * @remarks Wraps POST /api/v1/apps
1359
- */
1360
- async create(data) {
1361
- return this.http.request("POST", "/api/v1/apps", data);
1362
- }
1363
- async update(id, data) {
1364
- return this.http.request("PATCH", `/api/v1/apps/${encodeURIComponent(id)}`, data);
1365
- }
1366
- async remove(id) {
1367
- return this.http.request("DELETE", `/api/v1/apps/${encodeURIComponent(id)}`);
1368
- }
1369
- async listOrigins(id) {
1370
- return this.http.request("GET", `/api/v1/apps/${encodeURIComponent(id)}/origins`);
1371
- }
1372
- async addOrigin(id, origin) {
1373
- return this.http.request("POST", `/api/v1/apps/${encodeURIComponent(id)}/origins`, { origin });
1374
- }
1375
- async removeOrigin(id, origin) {
1376
- return this.http.request("DELETE", `/api/v1/apps/${encodeURIComponent(id)}/origins/${encodeURIComponent(origin)}`);
1377
- }
1378
- async listKeys(id) {
1379
- return this.http.request("GET", `/api/v1/apps/${encodeURIComponent(id)}/keys`);
1380
- }
1381
- async createKey(id, data) {
1382
- return this.http.request("POST", `/api/v1/apps/${encodeURIComponent(id)}/keys`, data);
1383
- }
1384
- async rotateKey(id, keyId) {
1385
- return this.http.request("POST", `/api/v1/apps/${encodeURIComponent(id)}/keys/${encodeURIComponent(keyId)}/rotate`, {});
1386
- }
1387
- async revokeKey(id, keyId) {
1388
- return this.http.request("DELETE", `/api/v1/apps/${encodeURIComponent(id)}/keys/${encodeURIComponent(keyId)}`);
1389
- }
1390
- /**
1391
- * List all registered applications.
1392
- * Requires `apps.view` permission on the `iqauth-admin` app.
1393
- *
1394
- * @remarks Wraps GET /api/v1/apps
1395
- */
1396
- async list() {
1397
- return this.http.request("GET", "/api/v1/apps");
1398
- }
1399
- /**
1400
- * Get a registered application by its unique key, including its permission nodes.
1401
- * Requires `apps.view` permission on the `iqauth-admin` app.
1402
- *
1403
- * @remarks Wraps GET /api/v1/apps/:appKey
1404
- */
1405
- async get(appKey) {
1406
- return this.http.request("GET", `/api/v1/apps/${encodeURIComponent(appKey)}`);
1407
- }
1408
- /**
1409
- * Register or sync an application manifest. This is an idempotent upsert —
1410
- * it creates the app if it doesn't exist, or updates it if it does.
1411
- * Permission nodes are also upserted (created or updated) from the manifest tree.
1412
- *
1413
- * Requires `platform_admin` role and `apps.manage` permission.
1414
- *
1415
- * @remarks Wraps POST /api/v1/apps/sync
1416
- */
1417
- async register(manifest) {
1418
- if (!this.http.hasCredentials()) {
1419
- throw new IQAuthError(
1420
- "AUTH_REQUIRED",
1421
- "Cannot sync app manifest: no API key or access token configured. Initialize the client with an apiKey or accessToken.",
1422
- 401
1423
- );
1424
- }
1425
- return this.http.request("POST", "/api/v1/apps/sync", manifest);
1426
- }
1427
- /**
1428
- * Check if an application is registered by its key.
1429
- * Returns `true` if the app exists, `false` otherwise.
1430
- *
1431
- * @remarks Uses GET /api/v1/apps/:appKey — catches 404 errors
1432
- */
1433
- async isRegistered(appKey) {
1434
- try {
1435
- await this.get(appKey);
1436
- return true;
1437
- } catch (err) {
1438
- if (err.code === "NOT_FOUND" || err.status === 404) {
1439
- return false;
1440
- }
1441
- throw err;
1442
- }
1443
- }
1444
- };
1445
-
1446
- // src/modules/roles.ts
1447
- var RolesModule = class {
1448
- constructor(http) {
1449
- this.http = http;
1450
- }
1451
- async list(tenantId) {
1452
- return this.http.request("GET", `/api/v1/tenants/${tenantId}/roles`);
1453
- }
1454
- async create(tenantId, data) {
1455
- return this.http.request("POST", `/api/v1/tenants/${tenantId}/roles`, data);
1456
- }
1457
- async update(tenantId, roleId, data) {
1458
- return this.http.request("PATCH", `/api/v1/tenants/${tenantId}/roles/${roleId}`, data);
1459
- }
1460
- async delete(tenantId, roleId) {
1461
- return this.http.request("DELETE", `/api/v1/tenants/${tenantId}/roles/${roleId}`);
1462
- }
1463
- async getUserRoles(tenantId, userId) {
1464
- return this.http.request("GET", `/api/v1/tenants/${tenantId}/users/${userId}/roles`);
1465
- }
1466
- async assignRole(tenantId, userId, data) {
1467
- return this.http.request("POST", `/api/v1/tenants/${tenantId}/users/${userId}/roles`, data);
1468
- }
1469
- async removeRole(tenantId, userId, roleId) {
1470
- return this.http.request("DELETE", `/api/v1/tenants/${tenantId}/users/${userId}/roles/${roleId}`);
1471
- }
1472
- };
1473
-
1474
- // src/modules/permissionGroups.ts
1475
- var PermissionGroupsModule = class {
1476
- constructor(http) {
1477
- this.http = http;
1478
- }
1479
- async list(tenantId) {
1480
- return this.http.request("GET", `/api/v1/tenants/${tenantId}/permission-groups`);
1481
- }
1482
- async create(tenantId, name, description) {
1483
- return this.http.request("POST", `/api/v1/tenants/${tenantId}/permission-groups`, { name, description });
1484
- }
1485
- async update(tenantId, groupId, data) {
1486
- return this.http.request("PATCH", `/api/v1/tenants/${tenantId}/permission-groups/${groupId}`, data);
1487
- }
1488
- async delete(tenantId, groupId) {
1489
- return this.http.request("DELETE", `/api/v1/tenants/${tenantId}/permission-groups/${groupId}`);
1490
- }
1491
- async getPermissions(tenantId, groupId) {
1492
- return this.http.request("GET", `/api/v1/tenants/${tenantId}/permission-groups/${groupId}/permissions`);
1493
- }
1494
- async addPermission(tenantId, groupId, data) {
1495
- return this.http.request("POST", `/api/v1/tenants/${tenantId}/permission-groups/${groupId}/permissions`, data);
1496
- }
1497
- async removePermission(tenantId, groupId, permissionId) {
1498
- return this.http.request("DELETE", `/api/v1/tenants/${tenantId}/permission-groups/${groupId}/permissions/${permissionId}`);
1499
- }
1500
- async addInheritance(tenantId, groupId, inheritsFromGroupId) {
1501
- return this.http.request("POST", `/api/v1/tenants/${tenantId}/permission-groups/${groupId}/inherit`, { inheritsFromGroupId });
1502
- }
1503
- async removeInheritance(tenantId, groupId, inheritedGroupId) {
1504
- return this.http.request("DELETE", `/api/v1/tenants/${tenantId}/permission-groups/${groupId}/inherit/${inheritedGroupId}`);
1505
- }
1506
- async getUserGroups(tenantId, userId) {
1507
- return this.http.request("GET", `/api/v1/tenants/${tenantId}/users/${userId}/groups`);
1508
- }
1509
- async assignUserToGroup(tenantId, userId, groupId) {
1510
- return this.http.request("POST", `/api/v1/tenants/${tenantId}/users/${userId}/groups`, { groupId });
1511
- }
1512
- async removeUserFromGroup(tenantId, userId, groupId) {
1513
- return this.http.request("DELETE", `/api/v1/tenants/${tenantId}/users/${userId}/groups/${groupId}`);
1514
- }
1515
- async getUserOverrides(tenantId, userId) {
1516
- return this.http.request("GET", `/api/v1/tenants/${tenantId}/users/${userId}/permissions/overrides`);
1517
- }
1518
- async addUserOverride(tenantId, userId, data) {
1519
- return this.http.request("POST", `/api/v1/tenants/${tenantId}/users/${userId}/permissions/overrides`, data);
1520
- }
1521
- async removeUserOverride(tenantId, userId, overrideId) {
1522
- return this.http.request("DELETE", `/api/v1/tenants/${tenantId}/users/${userId}/permissions/overrides/${overrideId}`);
1523
- }
1524
- async getEffectivePermissions(tenantId, userId, params) {
1525
- const query = new URLSearchParams();
1526
- if (params.product) query.set("product", params.product);
1527
- if (params.appKey) query.set("appKey", params.appKey);
1528
- const qs = query.toString();
1529
- return this.http.request("GET", `/api/v1/tenants/${tenantId}/users/${userId}/permissions/effective${qs ? `?${qs}` : ""}`);
1530
- }
1531
- async checkPermission(tenantId, userId, appKey, nodeKey) {
1532
- return this.http.request("POST", `/api/v1/tenants/${tenantId}/users/${userId}/permissions/check`, { appKey, nodeKey });
1533
- }
1534
- };
1535
-
1536
- // src/modules/apiKeys.ts
1537
- var ApiKeysModule = class {
1538
- constructor(http) {
1539
- this.http = http;
1540
- }
1541
- async create(data) {
1542
- return this.http.request("POST", "/api/v1/api-keys", data);
1543
- }
1544
- async list(params) {
1545
- const query = new URLSearchParams();
1546
- if (params?.tenantId) query.set("tenantId", params.tenantId);
1547
- const qs = query.toString();
1548
- return this.http.request("GET", `/api/v1/api-keys${qs ? `?${qs}` : ""}`);
1549
- }
1550
- async revoke(id) {
1551
- return this.http.request("DELETE", `/api/v1/api-keys/${id}`);
1552
- }
1553
- async introspect(apiKey) {
1554
- return this.http.request("POST", "/api/v1/api-keys/introspect", { apiKey }, { skipAutoRefresh: true });
1555
- }
1556
- };
1557
-
1558
- // src/modules/invites.ts
1559
- var InvitesModule = class {
1560
- constructor(http) {
1561
- this.http = http;
1562
- }
1563
- async create(data) {
1564
- return this.http.request("POST", "/api/v1/invites", data);
1565
- }
1566
- async validate(token) {
1567
- return this.http.request("GET", `/api/v1/invites/${token}/validate`);
1568
- }
1569
- async accept(token, data) {
1570
- return this.http.request("POST", `/api/v1/invites/${token}/accept`, data, { skipAutoRefresh: true });
1571
- }
1572
- };
1573
-
1574
- // src/modules/webhooks.ts
1575
- function normalizeWebhookDelivery(delivery) {
1576
- return {
1577
- ...delivery,
1578
- endpointId: delivery.endpointId ?? delivery.webhookEndpointId,
1579
- webhookEndpointId: delivery.webhookEndpointId ?? delivery.endpointId,
1580
- event: delivery.event ?? delivery.eventType,
1581
- eventType: delivery.eventType ?? delivery.event,
1582
- statusCode: delivery.statusCode ?? delivery.responseStatus ?? null,
1583
- responseStatus: delivery.responseStatus ?? delivery.statusCode ?? null,
1584
- response: delivery.response ?? delivery.responseBody ?? null,
1585
- responseBody: delivery.responseBody ?? delivery.response ?? null,
1586
- deliveredAt: delivery.deliveredAt ?? delivery.createdAt
1587
- };
1588
- }
1589
- var WebhooksModule = class {
1590
- constructor(http) {
1591
- this.http = http;
1592
- }
1593
- async createEndpoint(data) {
1594
- return this.http.request("POST", "/api/v1/webhooks/endpoints", data);
1595
- }
1596
- async listEndpoints() {
1597
- return this.http.request("GET", "/api/v1/webhooks/endpoints");
1598
- }
1599
- async deleteEndpoint(id) {
1600
- return this.http.request("DELETE", `/api/v1/webhooks/endpoints/${id}`);
1601
- }
1602
- async getDeliveries(endpointId) {
1603
- const deliveries = await this.http.request("GET", `/api/v1/webhooks/deliveries?endpointId=${encodeURIComponent(endpointId)}`);
1604
- return deliveries.map(normalizeWebhookDelivery);
1605
- }
1606
- async testEndpoint(id) {
1607
- return this.http.request("POST", `/api/v1/webhooks/endpoints/${id}/test`);
1608
- }
1609
- async rotateSecret(id) {
1610
- return this.http.request("POST", `/api/v1/webhooks/endpoints/${id}/rotate-secret`);
1611
- }
1612
- };
1613
-
1614
- // src/modules/entitlements.ts
1615
- var EntitlementsModule = class {
1616
- constructor(http) {
1617
- this.http = http;
1618
- }
1619
- async list(tenantId) {
1620
- return this.http.request("GET", `/api/v1/tenants/${tenantId}/entitlements`);
1621
- }
1622
- async grant(tenantId, data) {
1623
- return this.http.request("POST", `/api/v1/tenants/${tenantId}/entitlements`, data);
1624
- }
1625
- async revoke(tenantId, product) {
1626
- return this.http.request("DELETE", `/api/v1/tenants/${tenantId}/entitlements/${encodeURIComponent(product)}`);
1627
- }
1628
- };
1629
-
1630
- // src/modules/vendors.ts
1631
- var VendorsModule = class {
1632
- constructor(http) {
1633
- this.http = http;
1634
- }
1635
- async list() {
1636
- return this.http.request("GET", "/api/v1/vendors");
1637
- }
1638
- async get(vendorId) {
1639
- return this.http.request("GET", `/api/v1/vendors/${vendorId}`);
1640
- }
1641
- async create(data) {
1642
- return this.http.request("POST", "/api/v1/vendors", data);
1643
- }
1644
- async update(vendorId, data) {
1645
- return this.http.request("PATCH", `/api/v1/vendors/${vendorId}`, data);
1646
- }
1647
- async delete(vendorId) {
1648
- return this.http.request("DELETE", `/api/v1/vendors/${vendorId}`);
1649
- }
1650
- };
1651
-
1652
- // src/modules/sources.ts
1653
- var SourcesModule = class {
1654
- constructor(http) {
1655
- this.http = http;
1656
- }
1657
- async create(vendorId, data) {
1658
- return this.http.request("POST", `/api/v1/vendors/${vendorId}/sources`, data);
1659
- }
1660
- async listForVendor(vendorId) {
1661
- return this.http.request("GET", `/api/v1/vendors/${vendorId}/sources`);
1662
- }
1663
- async get(sourceId) {
1664
- return this.http.request("GET", `/api/v1/sources/${sourceId}`);
1665
- }
1666
- async update(sourceId, data) {
1667
- return this.http.request("PATCH", `/api/v1/sources/${sourceId}`, data);
1668
- }
1669
- async delete(sourceId) {
1670
- return this.http.request("DELETE", `/api/v1/sources/${sourceId}`);
1671
- }
1672
- async createClient(sourceId, data) {
1673
- return this.http.request("POST", `/api/v1/sources/${sourceId}/clients`, data);
1674
- }
1675
- async listClients(sourceId) {
1676
- return this.http.request("GET", `/api/v1/sources/${sourceId}/clients`);
1677
- }
1678
- };
1679
-
1680
- // src/modules/clients.ts
1681
- var ClientsModule = class {
1682
- constructor(http) {
1683
- this.http = http;
1684
- }
1685
- async get(clientId) {
1686
- return this.http.request("GET", `/api/v1/clients/${clientId}`);
1687
- }
1688
- async update(clientId, data) {
1689
- return this.http.request("PATCH", `/api/v1/clients/${clientId}`, data);
1690
- }
1691
- async delete(clientId) {
1692
- return this.http.request("DELETE", `/api/v1/clients/${clientId}`);
1693
- }
1694
- };
1695
-
1696
- // src/modules/hierarchy.ts
1697
- var HierarchyModule = class {
1698
- constructor(http) {
1699
- this.http = http;
1700
- }
1701
- async getGraph() {
1702
- return this.http.request("GET", "/api/v1/hierarchy");
1703
- }
1704
- async linkVendorSource(vendorId, sourceId) {
1705
- return this.http.request("POST", "/api/v1/hierarchy/link/vendor-source", { vendorId, sourceId });
1706
- }
1707
- async unlinkVendorSource(vendorId, sourceId) {
1708
- return this.http.request("DELETE", "/api/v1/hierarchy/link/vendor-source", { vendorId, sourceId });
1709
- }
1710
- async linkSourceClient(sourceId, clientId) {
1711
- return this.http.request("POST", "/api/v1/hierarchy/link/source-client", { sourceId, clientId });
1712
- }
1713
- async unlinkSourceClient(sourceId, clientId) {
1714
- return this.http.request("DELETE", "/api/v1/hierarchy/link/source-client", { sourceId, clientId });
1715
- }
1716
- };
1717
-
1718
- // src/modules/memberships.ts
1719
- var MembershipsModule = class {
1720
- constructor(http) {
1721
- this.http = http;
1722
- }
1723
- async listForUser(userId, tenantId) {
1724
- return this.http.request("GET", `/api/v1/users/${userId}/memberships?tenantId=${encodeURIComponent(tenantId)}`);
1725
- }
1726
- async listForScope(scopeType, scopeId) {
1727
- return this.http.request("GET", `/api/v1/memberships/scope/${scopeType}/${scopeId}`);
1728
- }
1729
- async grant(data) {
1730
- return this.http.request("POST", "/api/v1/memberships", data);
1731
- }
1732
- async revoke(id) {
1733
- return this.http.request("DELETE", `/api/v1/memberships/${id}`);
1734
- }
1735
- async update(id, data) {
1736
- return this.http.request("PATCH", `/api/v1/memberships/${id}`, data);
1737
- }
1738
- async listForTenant(params) {
1739
- const query = new URLSearchParams();
1740
- if (params?.scopeType) query.set("scopeType", params.scopeType);
1741
- if (params?.roleName) query.set("roleName", params.roleName);
1742
- const qs = query.toString();
1743
- return this.http.request("GET", `/api/v1/memberships/tenant${qs ? `?${qs}` : ""}`);
1744
- }
1745
- };
1746
-
1747
- // src/modules/scope.ts
1748
- var ScopeModule = class {
1749
- constructor(http) {
1750
- this.http = http;
1751
- }
1752
- async getAvailable() {
1753
- return this.http.request("GET", "/api/v1/auth/available-scopes");
1754
- }
1755
- async switchScope(scopeType, scopeId) {
1756
- return this.http.request("POST", "/api/v1/auth/switch-scope", { scopeType, scopeId });
1757
- }
1758
- };
1759
-
1760
- // src/modules/gdpr.ts
1761
- var GdprModule = class {
1762
- constructor(http) {
1763
- this.http = http;
1764
- }
1765
- async exportData() {
1766
- return this.http.request("GET", "/api/v1/gdpr/export");
1767
- }
1768
- async deleteAccount(confirmEmail) {
1769
- return this.http.request("POST", "/api/v1/gdpr/delete", { confirmEmail });
1770
- }
1771
- };
1772
-
1773
- // src/modules/pin.ts
1774
- var PinModule = class {
1775
- constructor(http) {
1776
- this.http = http;
1777
- }
1778
- async set(pin) {
1779
- return this.http.request("POST", "/api/v1/pin/set", { pin });
1780
- }
1781
- async change(currentPin, newPin) {
1782
- return this.http.request("POST", "/api/v1/pin/change", { currentPin, newPin });
1783
- }
1784
- async remove() {
1785
- return this.http.request("DELETE", "/api/v1/pin");
1786
- }
1787
- async getStatus() {
1788
- return this.http.request("GET", "/api/v1/pin/status");
1789
- }
1790
- async login(email, pin, deviceFingerprint) {
1791
- const data = await this.http.request(
1792
- "POST",
1793
- "/api/v1/pin/login",
1794
- { email, pin, ...deviceFingerprint && { deviceFingerprint } },
1795
- { skipAutoRefresh: true }
1796
- );
1797
- if (data.type === "success" && data.accessToken && data.refreshToken && data.user) {
1798
- return {
1799
- status: "authenticated",
1800
- authMode: "token",
1801
- tokens: { accessToken: data.accessToken, refreshToken: data.refreshToken },
1802
- user: data.user
1803
- };
1804
- }
1805
- if (data.type === "mfa_required" && data.mfaChallengeToken) {
1806
- return {
1807
- status: "mfa_required",
1808
- mfaChallengeToken: data.mfaChallengeToken,
1809
- availableMethods: data.availableMethods || []
1810
- };
1811
- }
1812
- if (data.type === "tenant_selection" && data.tenantSelectionToken && data.tenants) {
1813
- return {
1814
- status: "tenant_selection",
1815
- tenantSelectionToken: data.tenantSelectionToken,
1816
- tenants: data.tenants
1817
- };
1818
- }
1819
- throw new Error("Unexpected PIN login response shape");
1820
- }
1821
- };
1822
-
1823
- // src/modules/mfa.ts
1824
- var MfaModule = class {
1825
- constructor(http) {
1826
- this.http = http;
1827
- }
1828
- async getAvailableMethods() {
1829
- return this.http.request("GET", "/api/v1/mfa/methods");
1830
- }
1831
- async enrollTotp() {
1832
- return this.http.request("POST", "/api/v1/mfa/enroll/totp");
1833
- }
1834
- async verifyTotpEnrollment(code, secret) {
1835
- return this.http.request("POST", "/api/v1/mfa/enroll/totp/verify", { code, secret });
1836
- }
1837
- async enrollSms(phoneNumber) {
1838
- return this.http.request("POST", "/api/v1/mfa/enroll/sms", { phoneNumber });
1839
- }
1840
- async verifySmsEnrollment(code, phoneNumber) {
1841
- return this.http.request("POST", "/api/v1/mfa/enroll/sms/verify", { code, phoneNumber });
1842
- }
1843
- async startEmailEnrollment() {
1844
- return this.http.request("POST", "/api/v1/mfa/enroll/email/start");
1845
- }
1846
- async verifyEmailEnrollment(code) {
1847
- return this.http.request("POST", "/api/v1/mfa/enroll/email/verify", { code });
1848
- }
1849
- async listEnrollments() {
1850
- return this.http.request("GET", "/api/v1/mfa/enrollments");
1851
- }
1852
- async setPrimaryEnrollment(enrollmentId) {
1853
- return this.http.request("PATCH", `/api/v1/mfa/enrollments/${enrollmentId}/primary`);
1854
- }
1855
- async deactivateEnrollment(enrollmentId) {
1856
- return this.http.request("DELETE", `/api/v1/mfa/enrollments/${enrollmentId}`);
1857
- }
1858
- async regenerateBackupCodes() {
1859
- return this.http.request("POST", "/api/v1/mfa/backup-codes/regenerate");
1860
- }
1861
- async getBackupCodeCount() {
1862
- return this.http.request("GET", "/api/v1/mfa/backup-codes/count");
1863
- }
1864
- };
1865
-
1866
- // src/modules/branding.ts
1867
- function normalizeBrandingConfig2(config) {
1868
- return {
1869
- ...config,
1870
- brandName: config.brandName ?? config.companyName,
1871
- loginHeadline: config.loginHeadline ?? config.headline ?? null,
1872
- loginSubheadline: config.loginSubheadline ?? config.subheadline ?? null,
1873
- companyName: config.companyName ?? config.brandName,
1874
- headline: config.headline ?? config.loginHeadline ?? null,
1875
- subheadline: config.subheadline ?? config.loginSubheadline ?? null
1876
- };
1877
- }
1878
- function normalizeBrandingAsset(asset) {
1879
- return {
1880
- ...asset,
1881
- url: asset.url ?? asset.publicUrl,
1882
- publicUrl: asset.publicUrl ?? asset.url
1883
- };
1884
- }
1885
- function normalizeBrandingUpdate(data) {
1886
- return {
1887
- ...data,
1888
- brandName: data.brandName ?? data.companyName,
1889
- loginHeadline: data.loginHeadline ?? data.headline,
1890
- loginSubheadline: data.loginSubheadline ?? data.subheadline
1891
- };
1892
- }
1893
- var BrandingModule = class {
1894
- constructor(http) {
1895
- this.http = http;
1896
- }
1897
- async get(vendorId) {
1898
- const config = await this.http.request("GET", `/api/v1/branding/${vendorId}`);
1899
- return normalizeBrandingConfig2(config);
1900
- }
1901
- async updateBranding(vendorId, data) {
1902
- const config = await this.http.request("PUT", `/api/v1/branding/${vendorId}`, normalizeBrandingUpdate(data));
1903
- return normalizeBrandingConfig2(config);
1904
- }
1905
- async publishBranding(vendorId) {
1906
- const config = await this.http.request("POST", `/api/v1/branding/${vendorId}/publish`);
1907
- return normalizeBrandingConfig2(config);
1908
- }
1909
- async unpublishBranding(vendorId) {
1910
- const config = await this.http.request("POST", `/api/v1/branding/${vendorId}/unpublish`);
1911
- return normalizeBrandingConfig2(config);
1912
- }
1913
- async resetBranding(vendorId) {
1914
- const config = await this.http.request("POST", `/api/v1/branding/${vendorId}/reset`);
1915
- return normalizeBrandingConfig2(config);
1916
- }
1917
- async uploadAsset(vendorId, data) {
1918
- const asset = await this.http.request("POST", `/api/v1/branding/${vendorId}/upload`, data);
1919
- return normalizeBrandingAsset(asset);
1920
- }
1921
- async listAssets(vendorId) {
1922
- const assets = await this.http.request("GET", `/api/v1/branding/${vendorId}/assets`);
1923
- return assets.map(normalizeBrandingAsset);
1924
- }
1925
- async deleteAsset(vendorId, assetId) {
1926
- return this.http.request("DELETE", `/api/v1/branding/${vendorId}/assets/${assetId}`);
1927
- }
1928
- async listDomains(vendorId) {
1929
- return this.http.request("GET", `/api/v1/branding/${vendorId}/domains`);
1930
- }
1931
- async addDomain(vendorId, domain) {
1932
- return this.http.request("POST", `/api/v1/branding/${vendorId}/domains`, { domain });
1933
- }
1934
- async removeDomain(vendorId, domainId) {
1935
- return this.http.request("DELETE", `/api/v1/branding/${vendorId}/domains/${domainId}`);
1936
- }
1937
- };
1938
-
1939
- // src/client.ts
1940
- var IQAuthClient = class _IQAuthClient {
1941
- constructor(config) {
1942
- this.config = config;
1943
- this.environment = _IQAuthClient.resolveEnvironment(config);
1944
- this._accessToken = "accessToken" in config ? config.accessToken : void 0;
1945
- this._refreshToken = "refreshToken" in config ? config.refreshToken : void 0;
1946
- this._apiKey = "apiKey" in config ? config.apiKey : void 0;
1947
- this.httpClient = new HttpClient({
1948
- baseUrl: config.baseUrl,
1949
- environment: this.environment,
1950
- getAccessToken: () => this._accessToken,
1951
- getRefreshToken: () => this._refreshToken,
1952
- getApiKey: () => this._apiKey,
1953
- setTokens: (tokens) => {
1954
- this._accessToken = tokens.accessToken;
1955
- this._refreshToken = tokens.refreshToken;
1956
- },
1957
- autoRefresh: "autoRefresh" in config ? config.autoRefresh !== false : true,
1958
- onTokenRefresh: "onTokenRefresh" in config ? config.onTokenRefresh : void 0,
1959
- sessionHeaderName: config.sessionHeaderName,
1960
- sessionHeaderValue: config.sessionHeaderValue,
1961
- retry: config.retry
1962
- });
1963
- this.auth = new AuthModule(this.httpClient);
1964
- this.tokens = new TokensModule(config.baseUrl, {
1965
- issuer: config.verify?.issuer,
1966
- audience: config.verify?.audience,
1967
- clockTolerance: config.verify?.clockTolerance
1968
- });
1969
- this.sessions = new SessionsModule(this.httpClient);
1970
- this.users = new UsersModule(this.httpClient);
1971
- this.permissions = new PermissionsModule(() => this.getCurrentClaims());
1972
- this.oidc = new OidcModule(this.httpClient, config.baseUrl, { tokens: this.tokens });
1973
- this.tenants = new TenantsModule(this.httpClient);
1974
- this.apps = new AppsModule(this.httpClient);
1975
- this.roles = new RolesModule(this.httpClient);
1976
- this.permissionGroups = new PermissionGroupsModule(this.httpClient);
1977
- this.apiKeys = new ApiKeysModule(this.httpClient);
1978
- this.invites = new InvitesModule(this.httpClient);
1979
- this.webhooks = new WebhooksModule(this.httpClient);
1980
- this.entitlements = new EntitlementsModule(this.httpClient);
1981
- this.vendors = new VendorsModule(this.httpClient);
1982
- this.sources = new SourcesModule(this.httpClient);
1983
- this.clients = new ClientsModule(this.httpClient);
1984
- this.hierarchy = new HierarchyModule(this.httpClient);
1985
- this.memberships = new MembershipsModule(this.httpClient);
1986
- this.scope = new ScopeModule(this.httpClient);
1987
- this.gdpr = new GdprModule(this.httpClient);
1988
- this.pin = new PinModule(this.httpClient);
1989
- this.mfa = new MfaModule(this.httpClient);
1990
- this.branding = new BrandingModule(this.httpClient);
1991
- }
1992
- static forBrowserSession(config) {
1993
- return new _IQAuthClient({ ...config, environment: "browser_session" });
1994
- }
1995
- static forServer(config) {
1996
- return new _IQAuthClient({ ...config, environment: "server" });
1997
- }
1998
- static forMobile(config) {
1999
- return new _IQAuthClient({ ...config, environment: "mobile" });
2000
- }
2001
- static forService(config) {
2002
- return new _IQAuthClient({ ...config, environment: "service" });
2003
- }
2004
- setTokens(tokens) {
2005
- this._accessToken = tokens.accessToken;
2006
- this._refreshToken = tokens.refreshToken;
2007
- }
2008
- getAccessToken() {
2009
- return this._accessToken;
2010
- }
2011
- getRefreshToken() {
2012
- return this._refreshToken;
2013
- }
2014
- getCurrentClaims() {
2015
- if (!this._accessToken) return null;
2016
- return this.tokens.decode(this._accessToken);
2017
- }
2018
- static resolveEnvironment(config) {
2019
- if (config.environment) return config.environment;
2020
- if (config.apiKey) return "service";
2021
- return "server";
2022
- }
2023
- };
2024
-
2025
508
  // src/next.ts
2026
509
  function readCookieFromHeader(header, name) {
2027
510
  if (!header) return void 0;
@@ -2068,7 +551,7 @@ function handler(options) {
2068
551
  if (action === "signout") {
2069
552
  const auth = req.headers.get("authorization");
2070
553
  const accessToken = auth && auth.replace(/^Bearer /i, "") || readCookieFromHeader(cookieHeader, accessCookie);
2071
- return toResponse(await handleSignout(helperConfig, { accessToken }));
554
+ return toResponse(await handleSignout(helperConfig, { accessToken, ssoCookieHeader: cookieHeader ?? void 0 }));
2072
555
  }
2073
556
  return new Response(JSON.stringify({ success: false, error: { code: "NOT_FOUND", message: `Unknown action: ${action}` } }), {
2074
557
  status: 404,
@@ -2080,7 +563,7 @@ function createMiddleware(options) {
2080
563
  const parsed = assertPublishableKey(options.publishableKey, { context: "@iqauth/sdk/next createMiddleware" });
2081
564
  const issuer = (options.issuer ?? (parsed.iss.startsWith("http") ? parsed.iss : `https://${parsed.iss}`)).replace(/\/+$/, "");
2082
565
  const accessCookie = options.accessCookieName ?? "iqauth_at";
2083
- const client = new IQAuthClient({ baseUrl: issuer, environment: "server" });
566
+ const tokens = new TokensModule(issuer);
2084
567
  return async (req) => {
2085
568
  const auth = req.headers.get("authorization");
2086
569
  let token;
@@ -2093,7 +576,7 @@ function createMiddleware(options) {
2093
576
  });
2094
577
  }
2095
578
  try {
2096
- await client.tokens.verify(token);
579
+ await tokens.verify(token);
2097
580
  return void 0;
2098
581
  } catch (err) {
2099
582
  const code = err.code || "TOKEN_INVALID";
@@ -2122,9 +605,9 @@ async function getAuth(options) {
2122
605
  }
2123
606
  const token = cookieJar?.get(accessCookie)?.value;
2124
607
  if (!token) return null;
2125
- const client = new IQAuthClient({ baseUrl: issuer, environment: "server" });
608
+ const tokens = new TokensModule(issuer);
2126
609
  try {
2127
- return await client.tokens.verify(token);
610
+ return await tokens.verify(token);
2128
611
  } catch {
2129
612
  return null;
2130
613
  }