@iqauth/sdk 2.0.5 → 2.2.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 (38) hide show
  1. package/README.md +19 -3
  2. package/dist/browser.d.mts +2 -2
  3. package/dist/browser.d.ts +2 -2
  4. package/dist/browser.js +57 -6
  5. package/dist/browser.mjs +2 -2
  6. package/dist/{chunk-ZESHDJDU.mjs → chunk-D72UL5HL.mjs} +3 -6
  7. package/dist/{chunk-JQRTY5MY.mjs → chunk-M4J6BPK7.mjs} +3 -8
  8. package/dist/chunk-QEJB7WEQ.mjs +119 -0
  9. package/dist/{chunk-S3M2IXCE.mjs → chunk-QZB745C2.mjs} +3 -8
  10. package/dist/cli/index.js +21 -0
  11. package/dist/cli/index.mjs +1 -1
  12. package/dist/{doctor-OHJRZBBT.mjs → doctor-XCI77BQS.mjs} +2 -1
  13. package/dist/express.js +54 -25
  14. package/dist/express.mjs +5 -8
  15. package/dist/fastify.js +53 -19
  16. package/dist/fastify.mjs +4 -5
  17. package/dist/hono.js +53 -19
  18. package/dist/hono.mjs +4 -5
  19. package/dist/index.d.mts +1 -1
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.js +59 -4
  22. package/dist/index.mjs +4 -2
  23. package/dist/next.js +66 -34
  24. package/dist/next.mjs +6 -9
  25. package/dist/{publishableKey-B5DIK81A.d.mts → publishableKey-BaR0HoAH.d.mts} +10 -1
  26. package/dist/{publishableKey-B5DIK81A.d.ts → publishableKey-BaR0HoAH.d.ts} +10 -1
  27. package/dist/react.d.mts +91 -4
  28. package/dist/react.d.ts +91 -4
  29. package/dist/react.js +466 -162
  30. package/dist/react.mjs +411 -147
  31. package/dist/server/handlers.js +63 -17
  32. package/dist/server/handlers.mjs +3 -2
  33. package/dist/server.js +53 -21
  34. package/dist/server.mjs +3 -3
  35. package/dist/{signIn-VRNzlNyG.d.ts → signIn-BVDTIA_t.d.ts} +1 -1
  36. package/dist/{signIn-CEMdUAwd.d.mts → signIn-D_kP3v-c.d.mts} +1 -1
  37. package/package.json +1 -1
  38. package/dist/chunk-5WFR6Y33.mjs +0 -59
package/dist/fastify.mjs CHANGED
@@ -3,10 +3,10 @@ import {
3
3
  handleRefresh,
4
4
  handleSignout,
5
5
  serializeCookie
6
- } from "./chunk-JQRTY5MY.mjs";
6
+ } from "./chunk-M4J6BPK7.mjs";
7
7
  import {
8
- parsePublishableKey
9
- } from "./chunk-5WFR6Y33.mjs";
8
+ assertPublishableKey
9
+ } from "./chunk-QEJB7WEQ.mjs";
10
10
  import {
11
11
  IQAuthClient
12
12
  } from "./chunk-MDUHPQMM.mjs";
@@ -52,8 +52,7 @@ function readCookie(req, name) {
52
52
  return void 0;
53
53
  }
54
54
  async function iqAuth(fastify, options) {
55
- const parsed = parsePublishableKey(options.publishableKey);
56
- if (!parsed) throw new Error("@iqauth/sdk/fastify: invalid publishable key");
55
+ const parsed = assertPublishableKey(options.publishableKey, { context: "@iqauth/sdk/fastify" });
57
56
  const issuer = (options.issuer ?? (parsed.iss.startsWith("http") ? parsed.iss : `https://${parsed.iss}`)).replace(/\/+$/, "");
58
57
  const helperConfig = { ...options, issuer };
59
58
  const client = new IQAuthClient({
package/dist/hono.js CHANGED
@@ -1766,20 +1766,60 @@ function b64urlDecode(input) {
1766
1766
  const { Buffer: Buffer2 } = require("buffer");
1767
1767
  return Buffer2.from(normalized, "base64").toString("utf8");
1768
1768
  }
1769
- function parsePublishableKey(raw) {
1770
- if (typeof raw !== "string") return null;
1771
- const m = raw.match(/^pk_(test|live)_([A-Za-z0-9_-]+)$/);
1772
- if (!m) return null;
1769
+ function isValidIssuerUrl(iss) {
1770
+ if (typeof iss !== "string" || iss.length === 0) return false;
1771
+ if (!iss.startsWith("http://") && !iss.startsWith("https://")) return false;
1773
1772
  try {
1774
- const json = JSON.parse(b64urlDecode(m[2]));
1775
- if (!json || typeof json !== "object") return null;
1776
- if (typeof json.iss !== "string" || typeof json.appId !== "string" || typeof json.tenantId !== "string" || typeof json.kid !== "string") {
1777
- return null;
1778
- }
1779
- return { mode: m[1], iss: json.iss, appId: json.appId, tenantId: json.tenantId, kid: json.kid, raw };
1773
+ const u = new URL(iss);
1774
+ if (u.protocol !== "http:" && u.protocol !== "https:") return false;
1775
+ if (!u.hostname) return false;
1776
+ return true;
1780
1777
  } catch {
1781
- return null;
1778
+ return false;
1779
+ }
1780
+ }
1781
+ function assertPublishableKey(raw, opts) {
1782
+ const ctx = opts?.context ? `${opts.context}: ` : "";
1783
+ if (typeof raw !== "string" || raw.length === 0) {
1784
+ throw new IQAuthError(
1785
+ "CONFIG_INVALID",
1786
+ `${ctx}IQAuth publishable key is missing. Set IQAUTH_PUBLISHABLE_KEY (or pass publishableKey) to a pk_test_\u2026 or pk_live_\u2026 value from the IQAuth admin console.`
1787
+ );
1788
+ }
1789
+ const shapeMatch = raw.match(/^pk_(test|live)_([A-Za-z0-9_-]+)$/);
1790
+ if (!shapeMatch) {
1791
+ throw new IQAuthError(
1792
+ "CONFIG_INVALID",
1793
+ `${ctx}IQAuth publishable key is malformed (got ${raw.slice(0, 12)}\u2026). Expected pk_test_\u2026 or pk_live_\u2026; regenerate the key from the IQAuth admin console.`
1794
+ );
1795
+ }
1796
+ let decoded;
1797
+ try {
1798
+ decoded = JSON.parse(b64urlDecode(shapeMatch[2]));
1799
+ } catch {
1800
+ throw new IQAuthError(
1801
+ "CONFIG_INVALID",
1802
+ `${ctx}IQAuth publishable key payload is not valid base64url JSON. Regenerate the key from the IQAuth admin console.`
1803
+ );
1804
+ }
1805
+ if (!isPublishableKeyPayload(decoded)) {
1806
+ throw new IQAuthError(
1807
+ "CONFIG_INVALID",
1808
+ `${ctx}IQAuth publishable key payload is missing required fields {iss, appId, tenantId, kid}. Regenerate the key from the IQAuth admin console.`
1809
+ );
1782
1810
  }
1811
+ if (!isValidIssuerUrl(decoded.iss)) {
1812
+ throw new IQAuthError(
1813
+ "CONFIG_INVALID",
1814
+ `${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.`
1815
+ );
1816
+ }
1817
+ return { mode: shapeMatch[1], iss: decoded.iss, appId: decoded.appId, tenantId: decoded.tenantId, kid: decoded.kid, raw };
1818
+ }
1819
+ function isPublishableKeyPayload(value) {
1820
+ if (!value || typeof value !== "object") return false;
1821
+ const v = value;
1822
+ return typeof v.iss === "string" && typeof v.appId === "string" && typeof v.tenantId === "string" && typeof v.kid === "string";
1783
1823
  }
1784
1824
 
1785
1825
  // src/server/handlers.ts
@@ -1802,12 +1842,7 @@ function shouldClearCookiesOnFailure(policy, status, errorCode) {
1802
1842
  var ACCESS_TOKEN_TTL_SECONDS = 60 * 15;
1803
1843
  var REFRESH_TOKEN_TTL_SECONDS = 60 * 60 * 24 * 30;
1804
1844
  function resolve(config) {
1805
- const parsed = parsePublishableKey(config.publishableKey);
1806
- if (!parsed) {
1807
- throw new Error(
1808
- "@iqauth/sdk: invalid publishable key passed to iqAuth helpers (expected pk_test_\u2026 or pk_live_\u2026)"
1809
- );
1810
- }
1845
+ const parsed = assertPublishableKey(config.publishableKey, { context: "@iqauth/sdk helpers" });
1811
1846
  const inferredIssuer = parsed.iss.startsWith("http") ? parsed.iss : `https://${parsed.iss}`;
1812
1847
  return {
1813
1848
  publishableKey: config.publishableKey,
@@ -2015,8 +2050,7 @@ function honoResponse(hr) {
2015
2050
  return new Response(JSON.stringify(hr.body), { status: hr.status, headers });
2016
2051
  }
2017
2052
  function iqAuth(options) {
2018
- const parsed = parsePublishableKey(options.publishableKey);
2019
- if (!parsed) throw new Error("@iqauth/sdk/hono: invalid publishable key");
2053
+ const parsed = assertPublishableKey(options.publishableKey, { context: "@iqauth/sdk/hono" });
2020
2054
  const issuer = (options.issuer ?? (parsed.iss.startsWith("http") ? parsed.iss : `https://${parsed.iss}`)).replace(/\/+$/, "");
2021
2055
  const helperConfig = { ...options, issuer };
2022
2056
  const client = new IQAuthClient({ baseUrl: issuer, environment: "server" });
package/dist/hono.mjs CHANGED
@@ -3,10 +3,10 @@ import {
3
3
  handleRefresh,
4
4
  handleSignout,
5
5
  serializeCookie
6
- } from "./chunk-JQRTY5MY.mjs";
6
+ } from "./chunk-M4J6BPK7.mjs";
7
7
  import {
8
- parsePublishableKey
9
- } from "./chunk-5WFR6Y33.mjs";
8
+ assertPublishableKey
9
+ } from "./chunk-QEJB7WEQ.mjs";
10
10
  import {
11
11
  IQAuthClient
12
12
  } from "./chunk-MDUHPQMM.mjs";
@@ -45,8 +45,7 @@ function honoResponse(hr) {
45
45
  return new Response(JSON.stringify(hr.body), { status: hr.status, headers });
46
46
  }
47
47
  function iqAuth(options) {
48
- const parsed = parsePublishableKey(options.publishableKey);
49
- if (!parsed) throw new Error("@iqauth/sdk/hono: invalid publishable key");
48
+ const parsed = assertPublishableKey(options.publishableKey, { context: "@iqauth/sdk/hono" });
50
49
  const issuer = (options.issuer ?? (parsed.iss.startsWith("http") ? parsed.iss : `https://${parsed.iss}`)).replace(/\/+$/, "");
51
50
  const helperConfig = { ...options, issuer };
52
51
  const client = new IQAuthClient({ baseUrl: issuer, environment: "server" });
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { o as ApiKeysModule, l as AppsModule, A as AuthModule, B as BrandingModule, r as ClientsModule, C as CreateAppRequest, m as CreateAppResponse, h as DEFAULT_CLOCK_TOLERANCE_SECONDS, g as DEFAULT_TOKEN_AUDIENCE, D as DEFAULT_TOKEN_ISSUER, E as EntitlementsModule, G as GdprModule, H as HierarchyModule, I as IQAuthClient, a as InMemoryOidcStateStore, p as InvitesModule, M as MembershipsModule, u as MfaModule, d as OidcAuthRequest, e as OidcCallbackResult, O as OidcModule, f as OidcModuleOptions, b as OidcStateStore, c as OidcStoredRequest, n as PermissionGroupsModule, P as PermissionsModule, t as PinModule, R as RolesModule, s as ScopeModule, S as SessionsModule, q as SourcesModule, k as TenantsModule, i as TokenVerifyOptions, T as TokensModule, j as TokensModuleOptions, U as UsersModule, V as VendorsModule, W as WebhooksModule } from './client-Dv4v92Mj.mjs';
2
2
  export { a as ErrorCode, E as ErrorCodes, I as IQAuthError } from './errors-CDdl24MP.mjs';
3
3
  export { i as iqAuthMiddleware } from './express-BZmF1llh.mjs';
4
- export { K as KeyMode, b as ParsedPublishableKey, P as PublishableKeyPayload, e as encodePublishableKey, i as isPublishableKey, a as isSecretKey, p as parsePublishableKey } from './publishableKey-B5DIK81A.mjs';
4
+ export { K as KeyMode, c as ParsedPublishableKey, P as PublishableKeyPayload, a as assertPublishableKey, e as encodePublishableKey, i as isPublishableKey, b as isSecretKey, p as parsePublishableKey } from './publishableKey-BaR0HoAH.mjs';
5
5
  export { an as AcceptInviteRequest, aa as AddGroupPermissionRequest, ad as AddUserOverrideRequest, v as ApiErrorResponse, ag as ApiKeyInfo, aj as ApiKeyIntrospection, w as ApiResponse, A as ApiSuccessResponse, _ as AppInfo, Z as AppManifest, a0 as AppSyncResult, a4 as AssignRoleRequest, aM as AvailableScopesTree, a_ as BackupCodeCountResult, aZ as BackupCodesResult, p as BrandingAsset, B as BrandingConfig, r as BrandingDomainMapping, aB as Client, ah as CreateApiKeyRequest, ai as CreateApiKeyResult, aC as CreateClientRequest, al as CreateInviteRequest, aJ as CreateMembershipRequest, a2 as CreateRoleRequest, az as CreateSourceRequest, C as CreateTenantRequest, aw as CreateVendorRequest, ap as CreateWebhookRequest, aq as CreateWebhookResult, ae as EffectivePermission, aY as EmailEnrollResult, at as Entitlement, N as ExpressMiddlewareOptions, aR as GdprExportData, au as GrantEntitlementRequest, a9 as GroupPermission, aG as HierarchyClient, aH as HierarchyLink, aF as HierarchySource, aE as HierarchyVendor, c as IQAuthBrowserSessionClientConfig, a as IQAuthClientConfig, I as IQAuthEnvironment, V as IQAuthNextFunction, Q as IQAuthRequestLike, R as IQAuthResponseLike, W as IQAuthRetryConfig, b as IQAuthTokenClientConfig, X as IQAuthVerifyConfig, ab as InheritanceRelation, ak as Invitation, l as InviteTenantUserRequest, m as InviteTenantUserResult, am as InviteValidation, s as JwksKey, t as JwksResponse, J as JwtClaims, L as LoginResult, aI as Membership, aL as MembershipWithDetails, aU as MfaAvailableMethods, y as MfaEnrollment, x as MfaMethod, F as MfaPolicy, D as MfaVerifyResult, M as MigrateUserRequest, O as OidcDiscovery, u as OidcTokenResponse, E as PasswordPolicy, af as PermissionCheckResult, a8 as PermissionGroup, $ as PermissionNodeInfo, Y as PermissionNodeManifest, aT as PinLoginResult, aS as PinStatus, P as PromoteToVendorRequest, k as PromoteToVendorResult, H as ProvisionUserRequest, K as ProvisionUserResponse, a1 as Role, S as ScopeContext, aQ as ScopeSwitchResult, aN as ScopeTreeClient, aO as ScopeTreeSource, aP as ScopeTreeVendor, h as Session, g as SessionAuthenticatedLoginResult, d as SessionUser, aX as SmsEnrollResult, ay as Source, e as Tenant, i as TenantInfo, a7 as TenantUser, n as TenantUserRoleUpdate, f as TokenAuthenticatedLoginResult, T as TokenPair, aV as TotpEnrollResult, z as TotpEnrollmentResult, aW as TotpVerifyResult, o as UpdateBrandingRequest, aD as UpdateClientRequest, aK as UpdateMembershipRequest, a3 as UpdateRoleRequest, aA as UpdateSourceRequest, j as UpdateTenantRequest, ax as UpdateVendorRequest, q as UploadAssetRequest, a6 as UserGroupAssignment, ac as UserPermissionOverride, G as UserPermissions, U as UserProfile, a5 as UserRoleAssignment, av as Vendor, ar as WebhookDelivery, ao as WebhookEndpoint, as as WebhookTestResult } from './types-Cxl3bQHt.mjs';
6
6
  import 'jsonwebtoken';
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { o as ApiKeysModule, l as AppsModule, A as AuthModule, B as BrandingModule, r as ClientsModule, C as CreateAppRequest, m as CreateAppResponse, h as DEFAULT_CLOCK_TOLERANCE_SECONDS, g as DEFAULT_TOKEN_AUDIENCE, D as DEFAULT_TOKEN_ISSUER, E as EntitlementsModule, G as GdprModule, H as HierarchyModule, I as IQAuthClient, a as InMemoryOidcStateStore, p as InvitesModule, M as MembershipsModule, u as MfaModule, d as OidcAuthRequest, e as OidcCallbackResult, O as OidcModule, f as OidcModuleOptions, b as OidcStateStore, c as OidcStoredRequest, n as PermissionGroupsModule, P as PermissionsModule, t as PinModule, R as RolesModule, s as ScopeModule, S as SessionsModule, q as SourcesModule, k as TenantsModule, i as TokenVerifyOptions, T as TokensModule, j as TokensModuleOptions, U as UsersModule, V as VendorsModule, W as WebhooksModule } from './client-DXbHb2ul.js';
2
2
  export { a as ErrorCode, E as ErrorCodes, I as IQAuthError } from './errors-CDdl24MP.js';
3
3
  export { i as iqAuthMiddleware } from './express-B4o3P8vK.js';
4
- export { K as KeyMode, b as ParsedPublishableKey, P as PublishableKeyPayload, e as encodePublishableKey, i as isPublishableKey, a as isSecretKey, p as parsePublishableKey } from './publishableKey-B5DIK81A.js';
4
+ export { K as KeyMode, c as ParsedPublishableKey, P as PublishableKeyPayload, a as assertPublishableKey, e as encodePublishableKey, i as isPublishableKey, b as isSecretKey, p as parsePublishableKey } from './publishableKey-BaR0HoAH.js';
5
5
  export { an as AcceptInviteRequest, aa as AddGroupPermissionRequest, ad as AddUserOverrideRequest, v as ApiErrorResponse, ag as ApiKeyInfo, aj as ApiKeyIntrospection, w as ApiResponse, A as ApiSuccessResponse, _ as AppInfo, Z as AppManifest, a0 as AppSyncResult, a4 as AssignRoleRequest, aM as AvailableScopesTree, a_ as BackupCodeCountResult, aZ as BackupCodesResult, p as BrandingAsset, B as BrandingConfig, r as BrandingDomainMapping, aB as Client, ah as CreateApiKeyRequest, ai as CreateApiKeyResult, aC as CreateClientRequest, al as CreateInviteRequest, aJ as CreateMembershipRequest, a2 as CreateRoleRequest, az as CreateSourceRequest, C as CreateTenantRequest, aw as CreateVendorRequest, ap as CreateWebhookRequest, aq as CreateWebhookResult, ae as EffectivePermission, aY as EmailEnrollResult, at as Entitlement, N as ExpressMiddlewareOptions, aR as GdprExportData, au as GrantEntitlementRequest, a9 as GroupPermission, aG as HierarchyClient, aH as HierarchyLink, aF as HierarchySource, aE as HierarchyVendor, c as IQAuthBrowserSessionClientConfig, a as IQAuthClientConfig, I as IQAuthEnvironment, V as IQAuthNextFunction, Q as IQAuthRequestLike, R as IQAuthResponseLike, W as IQAuthRetryConfig, b as IQAuthTokenClientConfig, X as IQAuthVerifyConfig, ab as InheritanceRelation, ak as Invitation, l as InviteTenantUserRequest, m as InviteTenantUserResult, am as InviteValidation, s as JwksKey, t as JwksResponse, J as JwtClaims, L as LoginResult, aI as Membership, aL as MembershipWithDetails, aU as MfaAvailableMethods, y as MfaEnrollment, x as MfaMethod, F as MfaPolicy, D as MfaVerifyResult, M as MigrateUserRequest, O as OidcDiscovery, u as OidcTokenResponse, E as PasswordPolicy, af as PermissionCheckResult, a8 as PermissionGroup, $ as PermissionNodeInfo, Y as PermissionNodeManifest, aT as PinLoginResult, aS as PinStatus, P as PromoteToVendorRequest, k as PromoteToVendorResult, H as ProvisionUserRequest, K as ProvisionUserResponse, a1 as Role, S as ScopeContext, aQ as ScopeSwitchResult, aN as ScopeTreeClient, aO as ScopeTreeSource, aP as ScopeTreeVendor, h as Session, g as SessionAuthenticatedLoginResult, d as SessionUser, aX as SmsEnrollResult, ay as Source, e as Tenant, i as TenantInfo, a7 as TenantUser, n as TenantUserRoleUpdate, f as TokenAuthenticatedLoginResult, T as TokenPair, aV as TotpEnrollResult, z as TotpEnrollmentResult, aW as TotpVerifyResult, o as UpdateBrandingRequest, aD as UpdateClientRequest, aK as UpdateMembershipRequest, a3 as UpdateRoleRequest, aA as UpdateSourceRequest, j as UpdateTenantRequest, ax as UpdateVendorRequest, q as UploadAssetRequest, a6 as UserGroupAssignment, ac as UserPermissionOverride, G as UserPermissions, U as UserProfile, a5 as UserRoleAssignment, av as Vendor, ar as WebhookDelivery, ao as WebhookEndpoint, as as WebhookTestResult } from './types-Cxl3bQHt.js';
6
6
  import 'jsonwebtoken';
package/dist/index.js CHANGED
@@ -61,6 +61,7 @@ __export(index_exports, {
61
61
  UsersModule: () => UsersModule,
62
62
  VendorsModule: () => VendorsModule,
63
63
  WebhooksModule: () => WebhooksModule,
64
+ assertPublishableKey: () => assertPublishableKey,
64
65
  encodePublishableKey: () => encodePublishableKey,
65
66
  iqAuthMiddleware: () => iqAuthMiddleware,
66
67
  isPublishableKey: () => isPublishableKey,
@@ -1851,6 +1852,18 @@ function encodePublishableKey(mode, payload) {
1851
1852
  if (mode !== "test" && mode !== "live") throw new Error(`Invalid mode: ${mode}`);
1852
1853
  return `pk_${mode}_${b64urlEncode(JSON.stringify(payload))}`;
1853
1854
  }
1855
+ function isValidIssuerUrl(iss) {
1856
+ if (typeof iss !== "string" || iss.length === 0) return false;
1857
+ if (!iss.startsWith("http://") && !iss.startsWith("https://")) return false;
1858
+ try {
1859
+ const u = new URL(iss);
1860
+ if (u.protocol !== "http:" && u.protocol !== "https:") return false;
1861
+ if (!u.hostname) return false;
1862
+ return true;
1863
+ } catch {
1864
+ return false;
1865
+ }
1866
+ }
1854
1867
  function parsePublishableKey(raw) {
1855
1868
  if (typeof raw !== "string") return null;
1856
1869
  const m = raw.match(/^pk_(test|live)_([A-Za-z0-9_-]+)$/);
@@ -1861,11 +1874,55 @@ function parsePublishableKey(raw) {
1861
1874
  if (typeof json.iss !== "string" || typeof json.appId !== "string" || typeof json.tenantId !== "string" || typeof json.kid !== "string") {
1862
1875
  return null;
1863
1876
  }
1877
+ if (!isValidIssuerUrl(json.iss)) return null;
1864
1878
  return { mode: m[1], iss: json.iss, appId: json.appId, tenantId: json.tenantId, kid: json.kid, raw };
1865
1879
  } catch {
1866
1880
  return null;
1867
1881
  }
1868
1882
  }
1883
+ function assertPublishableKey(raw, opts) {
1884
+ const ctx = opts?.context ? `${opts.context}: ` : "";
1885
+ if (typeof raw !== "string" || raw.length === 0) {
1886
+ throw new IQAuthError(
1887
+ "CONFIG_INVALID",
1888
+ `${ctx}IQAuth publishable key is missing. Set IQAUTH_PUBLISHABLE_KEY (or pass publishableKey) to a pk_test_\u2026 or pk_live_\u2026 value from the IQAuth admin console.`
1889
+ );
1890
+ }
1891
+ const shapeMatch = raw.match(/^pk_(test|live)_([A-Za-z0-9_-]+)$/);
1892
+ if (!shapeMatch) {
1893
+ throw new IQAuthError(
1894
+ "CONFIG_INVALID",
1895
+ `${ctx}IQAuth publishable key is malformed (got ${raw.slice(0, 12)}\u2026). Expected pk_test_\u2026 or pk_live_\u2026; regenerate the key from the IQAuth admin console.`
1896
+ );
1897
+ }
1898
+ let decoded;
1899
+ try {
1900
+ decoded = JSON.parse(b64urlDecode(shapeMatch[2]));
1901
+ } catch {
1902
+ throw new IQAuthError(
1903
+ "CONFIG_INVALID",
1904
+ `${ctx}IQAuth publishable key payload is not valid base64url JSON. Regenerate the key from the IQAuth admin console.`
1905
+ );
1906
+ }
1907
+ if (!isPublishableKeyPayload(decoded)) {
1908
+ throw new IQAuthError(
1909
+ "CONFIG_INVALID",
1910
+ `${ctx}IQAuth publishable key payload is missing required fields {iss, appId, tenantId, kid}. Regenerate the key from the IQAuth admin console.`
1911
+ );
1912
+ }
1913
+ if (!isValidIssuerUrl(decoded.iss)) {
1914
+ throw new IQAuthError(
1915
+ "CONFIG_INVALID",
1916
+ `${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.`
1917
+ );
1918
+ }
1919
+ return { mode: shapeMatch[1], iss: decoded.iss, appId: decoded.appId, tenantId: decoded.tenantId, kid: decoded.kid, raw };
1920
+ }
1921
+ function isPublishableKeyPayload(value) {
1922
+ if (!value || typeof value !== "object") return false;
1923
+ const v = value;
1924
+ return typeof v.iss === "string" && typeof v.appId === "string" && typeof v.tenantId === "string" && typeof v.kid === "string";
1925
+ }
1869
1926
  function isPublishableKey(raw) {
1870
1927
  return typeof raw === "string" && /^pk_(test|live)_/.test(raw);
1871
1928
  }
@@ -1908,10 +1965,7 @@ function readCookie(req, name) {
1908
1965
  return void 0;
1909
1966
  }
1910
1967
  function clientFromPublishableKey(opts) {
1911
- const parsed = parsePublishableKey(opts.publishableKey);
1912
- if (!parsed) {
1913
- throw new Error("iqAuthMiddleware: invalid publishable key");
1914
- }
1968
+ const parsed = assertPublishableKey(opts.publishableKey, { context: "iqAuthMiddleware" });
1915
1969
  const issuer = (opts.issuer ?? (parsed.iss.startsWith("http") ? parsed.iss : `https://${parsed.iss}`)).replace(/\/+$/, "");
1916
1970
  return new IQAuthClient({ baseUrl: issuer, environment: "server" });
1917
1971
  }
@@ -2065,6 +2119,7 @@ function iqAuthMiddleware(clientOrOptions, options = {}) {
2065
2119
  UsersModule,
2066
2120
  VendorsModule,
2067
2121
  WebhooksModule,
2122
+ assertPublishableKey,
2068
2123
  encodePublishableKey,
2069
2124
  iqAuthMiddleware,
2070
2125
  isPublishableKey,
package/dist/index.mjs CHANGED
@@ -1,12 +1,13 @@
1
1
  import {
2
2
  iqAuthMiddleware
3
- } from "./chunk-ZESHDJDU.mjs";
3
+ } from "./chunk-D72UL5HL.mjs";
4
4
  import {
5
+ assertPublishableKey,
5
6
  encodePublishableKey,
6
7
  isPublishableKey,
7
8
  isSecretKey,
8
9
  parsePublishableKey
9
- } from "./chunk-5WFR6Y33.mjs";
10
+ } from "./chunk-QEJB7WEQ.mjs";
10
11
  import {
11
12
  ApiKeysModule,
12
13
  AppsModule,
@@ -75,6 +76,7 @@ export {
75
76
  UsersModule,
76
77
  VendorsModule,
77
78
  WebhooksModule,
79
+ assertPublishableKey,
78
80
  encodePublishableKey,
79
81
  iqAuthMiddleware,
80
82
  isPublishableKey,
package/dist/next.js CHANGED
@@ -36,6 +36,17 @@ __export(next_exports, {
36
36
  });
37
37
  module.exports = __toCommonJS(next_exports);
38
38
 
39
+ // src/errors.ts
40
+ var IQAuthError = class extends Error {
41
+ constructor(code, message, status, raw) {
42
+ super(message);
43
+ this.name = "IQAuthError";
44
+ this.code = code;
45
+ this.status = status;
46
+ this.raw = raw;
47
+ }
48
+ };
49
+
39
50
  // src/publishableKey.ts
40
51
  function b64urlDecode(input) {
41
52
  const pad = input.length % 4 === 0 ? "" : "=".repeat(4 - input.length % 4);
@@ -49,21 +60,61 @@ function b64urlDecode(input) {
49
60
  const { Buffer: Buffer2 } = require("buffer");
50
61
  return Buffer2.from(normalized, "base64").toString("utf8");
51
62
  }
52
- function parsePublishableKey(raw) {
53
- if (typeof raw !== "string") return null;
54
- const m = raw.match(/^pk_(test|live)_([A-Za-z0-9_-]+)$/);
55
- if (!m) return null;
63
+ function isValidIssuerUrl(iss) {
64
+ if (typeof iss !== "string" || iss.length === 0) return false;
65
+ if (!iss.startsWith("http://") && !iss.startsWith("https://")) return false;
56
66
  try {
57
- const json = JSON.parse(b64urlDecode(m[2]));
58
- if (!json || typeof json !== "object") return null;
59
- if (typeof json.iss !== "string" || typeof json.appId !== "string" || typeof json.tenantId !== "string" || typeof json.kid !== "string") {
60
- return null;
61
- }
62
- return { mode: m[1], iss: json.iss, appId: json.appId, tenantId: json.tenantId, kid: json.kid, raw };
67
+ const u = new URL(iss);
68
+ if (u.protocol !== "http:" && u.protocol !== "https:") return false;
69
+ if (!u.hostname) return false;
70
+ return true;
63
71
  } catch {
64
- return null;
72
+ return false;
65
73
  }
66
74
  }
75
+ function assertPublishableKey(raw, opts) {
76
+ const ctx = opts?.context ? `${opts.context}: ` : "";
77
+ if (typeof raw !== "string" || raw.length === 0) {
78
+ throw new IQAuthError(
79
+ "CONFIG_INVALID",
80
+ `${ctx}IQAuth publishable key is missing. Set IQAUTH_PUBLISHABLE_KEY (or pass publishableKey) to a pk_test_\u2026 or pk_live_\u2026 value from the IQAuth admin console.`
81
+ );
82
+ }
83
+ const shapeMatch = raw.match(/^pk_(test|live)_([A-Za-z0-9_-]+)$/);
84
+ if (!shapeMatch) {
85
+ throw new IQAuthError(
86
+ "CONFIG_INVALID",
87
+ `${ctx}IQAuth publishable key is malformed (got ${raw.slice(0, 12)}\u2026). Expected pk_test_\u2026 or pk_live_\u2026; regenerate the key from the IQAuth admin console.`
88
+ );
89
+ }
90
+ let decoded;
91
+ try {
92
+ decoded = JSON.parse(b64urlDecode(shapeMatch[2]));
93
+ } catch {
94
+ throw new IQAuthError(
95
+ "CONFIG_INVALID",
96
+ `${ctx}IQAuth publishable key payload is not valid base64url JSON. Regenerate the key from the IQAuth admin console.`
97
+ );
98
+ }
99
+ if (!isPublishableKeyPayload(decoded)) {
100
+ throw new IQAuthError(
101
+ "CONFIG_INVALID",
102
+ `${ctx}IQAuth publishable key payload is missing required fields {iss, appId, tenantId, kid}. Regenerate the key from the IQAuth admin console.`
103
+ );
104
+ }
105
+ if (!isValidIssuerUrl(decoded.iss)) {
106
+ throw new IQAuthError(
107
+ "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.`
109
+ );
110
+ }
111
+ return { mode: shapeMatch[1], iss: decoded.iss, appId: decoded.appId, tenantId: decoded.tenantId, kid: decoded.kid, raw };
112
+ }
113
+ function isPublishableKeyPayload(value) {
114
+ if (!value || typeof value !== "object") return false;
115
+ const v = value;
116
+ return typeof v.iss === "string" && typeof v.appId === "string" && typeof v.tenantId === "string" && typeof v.kid === "string";
117
+ }
67
118
 
68
119
  // src/server/handlers.ts
69
120
  var TERMINAL_REFRESH_ERROR_CODES = /* @__PURE__ */ new Set([
@@ -85,12 +136,7 @@ function shouldClearCookiesOnFailure(policy, status, errorCode) {
85
136
  var ACCESS_TOKEN_TTL_SECONDS = 60 * 15;
86
137
  var REFRESH_TOKEN_TTL_SECONDS = 60 * 60 * 24 * 30;
87
138
  function resolve(config) {
88
- const parsed = parsePublishableKey(config.publishableKey);
89
- if (!parsed) {
90
- throw new Error(
91
- "@iqauth/sdk: invalid publishable key passed to iqAuth helpers (expected pk_test_\u2026 or pk_live_\u2026)"
92
- );
93
- }
139
+ const parsed = assertPublishableKey(config.publishableKey, { context: "@iqauth/sdk helpers" });
94
140
  const inferredIssuer = parsed.iss.startsWith("http") ? parsed.iss : `https://${parsed.iss}`;
95
141
  return {
96
142
  publishableKey: config.publishableKey,
@@ -268,17 +314,6 @@ async function handleSignout(config, input) {
268
314
  };
269
315
  }
270
316
 
271
- // src/errors.ts
272
- var IQAuthError = class extends Error {
273
- constructor(code, message, status, raw) {
274
- super(message);
275
- this.name = "IQAuthError";
276
- this.code = code;
277
- this.status = status;
278
- this.raw = raw;
279
- }
280
- };
281
-
282
317
  // src/http.ts
283
318
  var DEFAULT_RETRY = {
284
319
  maxAttempts: 3,
@@ -2009,8 +2044,7 @@ function toResponse(hr) {
2009
2044
  return new Response(JSON.stringify(hr.body), { status: hr.status, headers });
2010
2045
  }
2011
2046
  function handler(options) {
2012
- const parsed = parsePublishableKey(options.publishableKey);
2013
- if (!parsed) throw new Error("@iqauth/sdk/next: invalid publishable key");
2047
+ const parsed = assertPublishableKey(options.publishableKey, { context: "@iqauth/sdk/next handler" });
2014
2048
  const issuer = (options.issuer ?? (parsed.iss.startsWith("http") ? parsed.iss : `https://${parsed.iss}`)).replace(/\/+$/, "");
2015
2049
  const helperConfig = { ...options, issuer };
2016
2050
  const accessCookie = options.accessCookieName ?? "iqauth_at";
@@ -2043,8 +2077,7 @@ function handler(options) {
2043
2077
  };
2044
2078
  }
2045
2079
  function createMiddleware(options) {
2046
- const parsed = parsePublishableKey(options.publishableKey);
2047
- if (!parsed) throw new Error("@iqauth/sdk/next: invalid publishable key");
2080
+ const parsed = assertPublishableKey(options.publishableKey, { context: "@iqauth/sdk/next createMiddleware" });
2048
2081
  const issuer = (options.issuer ?? (parsed.iss.startsWith("http") ? parsed.iss : `https://${parsed.iss}`)).replace(/\/+$/, "");
2049
2082
  const accessCookie = options.accessCookieName ?? "iqauth_at";
2050
2083
  const client = new IQAuthClient({ baseUrl: issuer, environment: "server" });
@@ -2072,8 +2105,7 @@ function createMiddleware(options) {
2072
2105
  };
2073
2106
  }
2074
2107
  async function getAuth(options) {
2075
- const parsed = parsePublishableKey(options.publishableKey);
2076
- if (!parsed) throw new Error("@iqauth/sdk/next: invalid publishable key");
2108
+ const parsed = assertPublishableKey(options.publishableKey, { context: "@iqauth/sdk/next getAuth" });
2077
2109
  const issuer = (options.issuer ?? (parsed.iss.startsWith("http") ? parsed.iss : `https://${parsed.iss}`)).replace(/\/+$/, "");
2078
2110
  const accessCookie = options.accessCookieName ?? "iqauth_at";
2079
2111
  let cookieJar = null;
package/dist/next.mjs CHANGED
@@ -3,10 +3,10 @@ import {
3
3
  handleRefresh,
4
4
  handleSignout,
5
5
  serializeCookie
6
- } from "./chunk-JQRTY5MY.mjs";
6
+ } from "./chunk-M4J6BPK7.mjs";
7
7
  import {
8
- parsePublishableKey
9
- } from "./chunk-5WFR6Y33.mjs";
8
+ assertPublishableKey
9
+ } from "./chunk-QEJB7WEQ.mjs";
10
10
  import {
11
11
  IQAuthClient
12
12
  } from "./chunk-MDUHPQMM.mjs";
@@ -35,8 +35,7 @@ function toResponse(hr) {
35
35
  return new Response(JSON.stringify(hr.body), { status: hr.status, headers });
36
36
  }
37
37
  function handler(options) {
38
- const parsed = parsePublishableKey(options.publishableKey);
39
- if (!parsed) throw new Error("@iqauth/sdk/next: invalid publishable key");
38
+ const parsed = assertPublishableKey(options.publishableKey, { context: "@iqauth/sdk/next handler" });
40
39
  const issuer = (options.issuer ?? (parsed.iss.startsWith("http") ? parsed.iss : `https://${parsed.iss}`)).replace(/\/+$/, "");
41
40
  const helperConfig = { ...options, issuer };
42
41
  const accessCookie = options.accessCookieName ?? "iqauth_at";
@@ -69,8 +68,7 @@ function handler(options) {
69
68
  };
70
69
  }
71
70
  function createMiddleware(options) {
72
- const parsed = parsePublishableKey(options.publishableKey);
73
- if (!parsed) throw new Error("@iqauth/sdk/next: invalid publishable key");
71
+ const parsed = assertPublishableKey(options.publishableKey, { context: "@iqauth/sdk/next createMiddleware" });
74
72
  const issuer = (options.issuer ?? (parsed.iss.startsWith("http") ? parsed.iss : `https://${parsed.iss}`)).replace(/\/+$/, "");
75
73
  const accessCookie = options.accessCookieName ?? "iqauth_at";
76
74
  const client = new IQAuthClient({ baseUrl: issuer, environment: "server" });
@@ -98,8 +96,7 @@ function createMiddleware(options) {
98
96
  };
99
97
  }
100
98
  async function getAuth(options) {
101
- const parsed = parsePublishableKey(options.publishableKey);
102
- if (!parsed) throw new Error("@iqauth/sdk/next: invalid publishable key");
99
+ const parsed = assertPublishableKey(options.publishableKey, { context: "@iqauth/sdk/next getAuth" });
103
100
  const issuer = (options.issuer ?? (parsed.iss.startsWith("http") ? parsed.iss : `https://${parsed.iss}`)).replace(/\/+$/, "");
104
101
  const accessCookie = options.accessCookieName ?? "iqauth_at";
105
102
  let cookieJar = null;
@@ -18,7 +18,16 @@ interface ParsedPublishableKey extends PublishableKeyPayload {
18
18
  }
19
19
  declare function encodePublishableKey(mode: KeyMode, payload: PublishableKeyPayload): string;
20
20
  declare function parsePublishableKey(raw: string): ParsedPublishableKey | null;
21
+ /**
22
+ * Strict counterpart to `parsePublishableKey` — throws a typed `IQAuthError`
23
+ * (`code: "CONFIG_INVALID"`) with an actionable message when the key is
24
+ * missing, malformed, or encodes a non-URL `iss`. Use this at SDK init so a
25
+ * bad key fails loudly at boot instead of cryptically at first verify.
26
+ */
27
+ declare function assertPublishableKey(raw: string | undefined | null, opts?: {
28
+ context?: string;
29
+ }): ParsedPublishableKey;
21
30
  declare function isPublishableKey(raw: string): boolean;
22
31
  declare function isSecretKey(raw: string): boolean;
23
32
 
24
- export { type KeyMode as K, type PublishableKeyPayload as P, isSecretKey as a, type ParsedPublishableKey as b, encodePublishableKey as e, isPublishableKey as i, parsePublishableKey as p };
33
+ export { type KeyMode as K, type PublishableKeyPayload as P, assertPublishableKey as a, isSecretKey as b, type ParsedPublishableKey as c, encodePublishableKey as e, isPublishableKey as i, parsePublishableKey as p };
@@ -18,7 +18,16 @@ interface ParsedPublishableKey extends PublishableKeyPayload {
18
18
  }
19
19
  declare function encodePublishableKey(mode: KeyMode, payload: PublishableKeyPayload): string;
20
20
  declare function parsePublishableKey(raw: string): ParsedPublishableKey | null;
21
+ /**
22
+ * Strict counterpart to `parsePublishableKey` — throws a typed `IQAuthError`
23
+ * (`code: "CONFIG_INVALID"`) with an actionable message when the key is
24
+ * missing, malformed, or encodes a non-URL `iss`. Use this at SDK init so a
25
+ * bad key fails loudly at boot instead of cryptically at first verify.
26
+ */
27
+ declare function assertPublishableKey(raw: string | undefined | null, opts?: {
28
+ context?: string;
29
+ }): ParsedPublishableKey;
21
30
  declare function isPublishableKey(raw: string): boolean;
22
31
  declare function isSecretKey(raw: string): boolean;
23
32
 
24
- export { type KeyMode as K, type PublishableKeyPayload as P, isSecretKey as a, type ParsedPublishableKey as b, encodePublishableKey as e, isPublishableKey as i, parsePublishableKey as p };
33
+ export { type KeyMode as K, type PublishableKeyPayload as P, assertPublishableKey as a, isSecretKey as b, type ParsedPublishableKey as c, encodePublishableKey as e, isPublishableKey as i, parsePublishableKey as p };