@iqauth/sdk 2.6.4 → 2.8.1

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 (117) hide show
  1. package/README.md +173 -1
  2. package/dist/browser-session.d.mts +4 -4
  3. package/dist/browser-session.d.ts +4 -4
  4. package/dist/browser-session.js +212 -46
  5. package/dist/browser-session.mjs +3 -3
  6. package/dist/browser.d.mts +5 -5
  7. package/dist/browser.d.ts +5 -5
  8. package/dist/browser.js +293 -34
  9. package/dist/browser.mjs +5 -5
  10. package/dist/{chunk-BVV54LPI.mjs → chunk-25SSYDIP.mjs} +10 -4
  11. package/dist/{chunk-XAWYUPMO.mjs → chunk-4V7FKOTG.mjs} +242 -22
  12. package/dist/{chunk-6I6RM4MN.mjs → chunk-6PJRLRB4.mjs} +33 -3
  13. package/dist/{chunk-SL3KRS4W.mjs → chunk-CIJORODR.mjs} +23 -1
  14. package/dist/{chunk-LIZYFXH7.mjs → chunk-DFWHSDYQ.mjs} +1 -1
  15. package/dist/chunk-GLXSIGVS.mjs +66 -0
  16. package/dist/{chunk-DJIBN2N7.mjs → chunk-GN37E64I.mjs} +29 -7
  17. package/dist/{chunk-WQWBJSSS.mjs → chunk-HVHNYPDC.mjs} +6 -6
  18. package/dist/chunk-JRDVUWAL.mjs +46 -0
  19. package/dist/{chunk-UNYDG2L4.mjs → chunk-NUO2I65G.mjs} +56 -23
  20. package/dist/{chunk-5T7GHBX6.mjs → chunk-TLET552H.mjs} +36 -0
  21. package/dist/chunk-VYQ3ETCK.mjs +244 -0
  22. package/dist/{chunk-3JULWS6F.mjs → chunk-WCELYTJ3.mjs} +3 -3
  23. package/dist/chunk-WHT6WKTY.mjs +3180 -0
  24. package/dist/{chunk-MKKZULZR.mjs → chunk-WIFG74IK.mjs} +1 -1
  25. package/dist/chunk-WSH4SW7F.mjs +490 -0
  26. package/dist/{chunk-W3F4JYGP.mjs → chunk-ZLJPABB7.mjs} +139 -23
  27. package/dist/cli/index.js +2 -2
  28. package/dist/cli/index.mjs +2 -2
  29. package/dist/{client-BNQe3AgF.d.ts → client-D8L-PaWr.d.mts} +59 -6
  30. package/dist/{client-kYlJFgPv.d.mts → client-DkPL0EPZ.d.ts} +59 -6
  31. package/dist/{doctor-YYNHNMLD.mjs → doctor-JAFXWU3X.mjs} +2 -2
  32. package/dist/errors-Jl1Jtm-6.d.mts +107 -0
  33. package/dist/errors-Jl1Jtm-6.d.ts +107 -0
  34. package/dist/{express-CHpfa7D_.d.ts → express-Budysq4h.d.ts} +2 -2
  35. package/dist/{express-B6_1vBYZ.d.mts → express-DDTA3qV1.d.mts} +2 -2
  36. package/dist/express.d.mts +7 -6
  37. package/dist/express.d.ts +7 -6
  38. package/dist/express.js +563 -85
  39. package/dist/express.mjs +73 -34
  40. package/dist/fastify.d.mts +10 -0
  41. package/dist/fastify.d.ts +10 -0
  42. package/dist/fastify.js +589 -65
  43. package/dist/fastify.mjs +101 -11
  44. package/dist/hono.d.mts +10 -0
  45. package/dist/hono.d.ts +10 -0
  46. package/dist/hono.js +566 -65
  47. package/dist/hono.mjs +78 -11
  48. package/dist/index-Cko-d5po.d.mts +1848 -0
  49. package/dist/index-RNqwEcmY.d.ts +1848 -0
  50. package/dist/index.d.mts +56 -8
  51. package/dist/index.d.ts +56 -8
  52. package/dist/index.js +694 -75
  53. package/dist/index.mjs +30 -10
  54. package/dist/{keys-NLWFAOEM.mjs → keys-6Y776TG2.mjs} +2 -2
  55. package/dist/locales.d.mts +1 -1
  56. package/dist/locales.d.ts +1 -1
  57. package/dist/locales.js +36 -0
  58. package/dist/locales.mjs +1 -1
  59. package/dist/mobile.d.mts +77 -7
  60. package/dist/mobile.d.ts +77 -7
  61. package/dist/mobile.js +307 -46
  62. package/dist/mobile.mjs +98 -3
  63. package/dist/next.d.mts +10 -1
  64. package/dist/next.d.ts +10 -1
  65. package/dist/next.js +596 -205
  66. package/dist/next.mjs +83 -10
  67. package/dist/{provisioningBridge-88xjOS2n.d.mts → provisioningBridge-BXPMZCLe.d.ts} +30 -2
  68. package/dist/{provisioningBridge-DnTfzdZK.d.ts → provisioningBridge-IEycmsgb.d.mts} +30 -2
  69. package/dist/{publishableKey-BaR0HoAH.d.ts → publishableKey-f2kq-rKw.d.mts} +1 -1
  70. package/dist/{publishableKey-BaR0HoAH.d.mts → publishableKey-f2kq-rKw.d.ts} +1 -1
  71. package/dist/react-permissions.d.mts +52 -0
  72. package/dist/react-permissions.d.ts +52 -0
  73. package/dist/react-permissions.js +239 -0
  74. package/dist/react-permissions.mjs +98 -0
  75. package/dist/react.d.mts +9 -1624
  76. package/dist/react.d.ts +9 -1624
  77. package/dist/react.js +882 -73
  78. package/dist/react.mjs +71 -2631
  79. package/dist/{reverify-4UEJXUS6.mjs → reverify-C64QXKJO.mjs} +2 -2
  80. package/dist/server/handlers.d.mts +200 -4
  81. package/dist/server/handlers.d.ts +200 -4
  82. package/dist/server/handlers.js +530 -16
  83. package/dist/server/handlers.mjs +14 -3
  84. package/dist/server.d.mts +171 -8
  85. package/dist/server.d.ts +171 -8
  86. package/dist/server.js +579 -61
  87. package/dist/server.mjs +99 -12
  88. package/dist/service.d.mts +4 -4
  89. package/dist/service.d.ts +4 -4
  90. package/dist/service.js +212 -46
  91. package/dist/service.mjs +3 -3
  92. package/dist/{signIn-CiIBTJIh.d.mts → signIn-CReqfXsh.d.mts} +95 -3
  93. package/dist/{signIn-OCr88Zf8.d.ts → signIn-Cfa1GTpO.d.ts} +95 -3
  94. package/dist/{signIn-4OKLDEIH.mjs → signIn-SHBW6Z4T.mjs} +1 -1
  95. package/dist/test.mjs +3 -3
  96. package/dist/{tokens-DCyzzn8L.d.mts → tokens-9F6ETrzk.d.ts} +9 -2
  97. package/dist/{tokens-aHiGFr_E.d.ts → tokens-B06VtvUi.d.mts} +9 -2
  98. package/dist/{types-DZAflmmq.d.mts → types-Bn8O-OEd.d.mts} +164 -11
  99. package/dist/{types-DZAflmmq.d.ts → types-Bn8O-OEd.d.ts} +164 -11
  100. package/dist/{types-6bNdxesb.d.ts → types-DnU2LhXR.d.mts} +7 -1
  101. package/dist/{types-6bNdxesb.d.mts → types-DnU2LhXR.d.ts} +7 -1
  102. package/dist/webhooks.d.mts +113 -17
  103. package/dist/webhooks.d.ts +113 -17
  104. package/dist/webhooks.js +179 -15
  105. package/dist/webhooks.mjs +7 -1
  106. package/dist/ws.d.mts +2 -2
  107. package/dist/ws.d.ts +2 -2
  108. package/dist/ws.js +80 -30
  109. package/dist/ws.mjs +4 -4
  110. package/docs/error-handling.md +101 -0
  111. package/docs/guides/effective-permissions.md +171 -0
  112. package/docs/guides/invitations.md +65 -0
  113. package/package.json +19 -4
  114. package/dist/chunk-6TDJJER7.mjs +0 -217
  115. package/dist/chunk-UKZLOHZG.mjs +0 -83
  116. package/dist/errors-CDdl24MP.d.mts +0 -52
  117. package/dist/errors-CDdl24MP.d.ts +0 -52
package/dist/express.mjs CHANGED
@@ -1,27 +1,32 @@
1
1
  import {
2
- handleCallback,
3
- handleRefresh,
4
- handleSignout
5
- } from "./chunk-6TDJJER7.mjs";
2
+ sanitizeReturnTo
3
+ } from "./chunk-JRDVUWAL.mjs";
6
4
  import {
7
5
  DEFAULT_REFRESH_COOKIE,
8
6
  iqAuthMiddleware
9
- } from "./chunk-BVV54LPI.mjs";
7
+ } from "./chunk-25SSYDIP.mjs";
8
+ import {
9
+ handleCallback,
10
+ handleRefresh,
11
+ handleSignout,
12
+ handleUserinfo
13
+ } from "./chunk-WSH4SW7F.mjs";
10
14
  import {
11
15
  assertPublishableKey
12
- } from "./chunk-WQWBJSSS.mjs";
16
+ } from "./chunk-HVHNYPDC.mjs";
13
17
  import {
14
18
  IQAuthClient
15
- } from "./chunk-W3F4JYGP.mjs";
16
- import "./chunk-UNYDG2L4.mjs";
19
+ } from "./chunk-ZLJPABB7.mjs";
20
+ import "./chunk-NUO2I65G.mjs";
17
21
  import {
18
22
  ErrorCodes,
19
23
  IQAuthError
20
- } from "./chunk-6I6RM4MN.mjs";
24
+ } from "./chunk-6PJRLRB4.mjs";
21
25
  import "./chunk-Y6FXYEAI.mjs";
22
26
 
23
27
  // src/express.ts
24
28
  var PKCE_COOKIE = "iqauth_pkce";
29
+ var IDEMPOTENCY_HEADER = "x-iqauth-idempotency";
25
30
  function escapeHtml(s) {
26
31
  return s.replace(/[&<>"']/g, (c) => {
27
32
  switch (c) {
@@ -95,6 +100,17 @@ function defaultBrandedSpinner(args) {
95
100
  }
96
101
  function applyHandlerResponse(res, hr) {
97
102
  for (const c of hr.cookies) {
103
+ if (c.clear && typeof res.clearCookie === "function") {
104
+ const opts = {
105
+ httpOnly: c.httpOnly,
106
+ secure: c.secure,
107
+ sameSite: c.sameSite,
108
+ path: c.path
109
+ };
110
+ if (c.domain) opts.domain = c.domain;
111
+ res.clearCookie(c.name, opts);
112
+ continue;
113
+ }
98
114
  if (typeof res.cookie === "function") {
99
115
  const opts = {
100
116
  httpOnly: c.httpOnly,
@@ -104,11 +120,13 @@ function applyHandlerResponse(res, hr) {
104
120
  maxAge: c.maxAge * 1e3
105
121
  };
106
122
  if (c.domain) opts.domain = c.domain;
123
+ if (c.clear) opts.expires = /* @__PURE__ */ new Date(0);
107
124
  res.cookie(c.name, c.value, opts);
108
125
  } else {
109
126
  const existing = res.getHeader?.("Set-Cookie") || [];
110
127
  const list = Array.isArray(existing) ? existing : [existing];
111
128
  const parts = [`${c.name}=${encodeURIComponent(c.value)}`, `Path=${c.path}`, `Max-Age=${c.maxAge}`, `SameSite=${c.sameSite}`];
129
+ if (c.clear) parts.push("Expires=Thu, 01 Jan 1970 00:00:00 GMT");
112
130
  if (c.secure) parts.push("Secure");
113
131
  if (c.httpOnly) parts.push("HttpOnly");
114
132
  if (c.domain) parts.push(`Domain=${c.domain}`);
@@ -121,6 +139,11 @@ function applyHandlerResponse(res, hr) {
121
139
  function readBody(req) {
122
140
  return req.body && typeof req.body === "object" ? req.body : {};
123
141
  }
142
+ function requestOriginOf(req) {
143
+ const proto = req.headers?.["x-forwarded-proto"]?.split(",")[0]?.trim() || (typeof req.protocol === "string" ? req.protocol : void 0) || "https";
144
+ const host = req.headers?.["x-forwarded-host"]?.split(",")[0]?.trim() || req.headers?.host || "";
145
+ return host ? `${proto}://${host}` : "";
146
+ }
124
147
  function readCookieFromReq(req, name) {
125
148
  if (req.cookies && typeof req.cookies[name] === "string") return req.cookies[name];
126
149
  const header = req.headers?.cookie;
@@ -159,12 +182,19 @@ function iqAuth(options) {
159
182
  const inline = options.inlineCallback === true ? {} : options.inlineCallback && typeof options.inlineCallback === "object" ? options.inlineCallback : null;
160
183
  const inlineBranded = inline?.branded === true ? {} : inline?.branded && typeof inline.branded === "object" ? inline.branded : null;
161
184
  const attachHelpers = (app) => {
185
+ void client.prewarm();
162
186
  app.post(`${mount}/callback`, async (req, res) => {
163
187
  const body = readBody(req);
164
188
  const hr = await handleCallback(helperConfig, {
165
189
  code: body.code,
166
190
  codeVerifier: body.codeVerifier,
167
- redirectUri: body.redirectUri
191
+ redirectUri: body.redirectUri,
192
+ // M-2: bind the callback to this browser. `state` is echoed back by the
193
+ // OAuth redirect (body); `expectedState` is the value the SDK published
194
+ // in a first-party cookie before redirect. handleCallback fails closed
195
+ // on mismatch/missing when requireOAuthState (default) is on.
196
+ state: body.state,
197
+ expectedState: readCookieFromReq(req, helperConfig.stateCookieName ?? "iqauth_state")
168
198
  });
169
199
  applyHandlerResponse(res, hr);
170
200
  });
@@ -213,21 +243,19 @@ function iqAuth(options) {
213
243
  });
214
244
  app.post(exchangePath, async (req, res) => {
215
245
  const body = readBody(req);
216
- const stateFromBody = body.state || void 0;
217
- const stateFromCookie = readCookieFromReq(req, stateCookie);
218
- if (stateFromCookie && stateFromBody !== stateFromCookie) {
219
- clearCookie(res, stateCookie);
220
- res.status(400);
221
- return res.json ? res.json({ success: false, error: { code: "STATE_MISMATCH", message: "OAuth state mismatch" } }) : res.end?.(JSON.stringify({ success: false, error: { code: "STATE_MISMATCH", message: "OAuth state mismatch" } }));
222
- }
223
246
  const hr = await handleCallback(helperConfig, {
224
247
  code: body.code,
225
248
  codeVerifier: body.codeVerifier || readCookieFromReq(req, PKCE_COOKIE) || "",
226
- redirectUri: body.redirectUri
249
+ redirectUri: body.redirectUri,
250
+ state: body.state,
251
+ expectedState: readCookieFromReq(req, stateCookie)
227
252
  });
228
253
  clearCookie(res, stateCookie);
229
254
  clearCookie(res, PKCE_COOKIE);
230
- const returnTo = readCookieFromReq(req, returnToCookie) || hr.body?.returnTo || "/";
255
+ const returnTo = sanitizeReturnTo(
256
+ readCookieFromReq(req, returnToCookie) || hr.body?.returnTo,
257
+ { currentOrigin: requestOriginOf(req), fallback: "/" }
258
+ );
231
259
  if (hr.status < 400) clearCookie(res, returnToCookie);
232
260
  const enriched = {
233
261
  ...hr,
@@ -246,21 +274,17 @@ function iqAuth(options) {
246
274
  else res.end?.("Missing authorization code");
247
275
  });
248
276
  }
249
- const stateFromQuery = q.state;
250
- const stateFromCookie = readCookieFromReq(req, stateCookie);
251
- if (stateFromCookie && stateFromQuery !== stateFromCookie) {
252
- clearCookie(res, stateCookie);
253
- return failPlain(res, "state_mismatch", () => {
254
- res.status(400);
255
- if (res.json) res.json({ success: false, error: { code: "STATE_MISMATCH", message: "OAuth state mismatch" } });
256
- else res.end?.("OAuth state mismatch");
257
- });
258
- }
259
277
  const codeVerifier = readCookieFromReq(req, PKCE_COOKIE) || "";
260
278
  const proto = req.headers?.["x-forwarded-proto"] || req.protocol || "https";
261
279
  const host = req.headers?.["x-forwarded-host"] || req.headers?.host || "";
262
280
  const redirectUri = `${proto}://${host}${callbackPath}`;
263
- const hr = await handleCallback(helperConfig, { code, codeVerifier, redirectUri });
281
+ const hr = await handleCallback(helperConfig, {
282
+ code,
283
+ codeVerifier,
284
+ redirectUri,
285
+ state: q.state,
286
+ expectedState: readCookieFromReq(req, stateCookie)
287
+ });
264
288
  for (const c of hr.cookies) {
265
289
  if (typeof res.cookie === "function") {
266
290
  const opts = {
@@ -277,14 +301,18 @@ function iqAuth(options) {
277
301
  clearCookie(res, stateCookie);
278
302
  clearCookie(res, PKCE_COOKIE);
279
303
  if (hr.status >= 400) {
280
- const code2 = hr.body?.error?.code || "exchange_failed";
304
+ const rawCode = hr.body?.error?.code || "exchange_failed";
305
+ const code2 = rawCode === "STATE_MISMATCH" ? "state_mismatch" : rawCode;
281
306
  return failPlain(res, code2, () => {
282
307
  res.status(hr.status);
283
308
  if (res.json) res.json(hr.body);
284
309
  else res.end?.(JSON.stringify(hr.body));
285
310
  });
286
311
  }
287
- const returnTo = readCookieFromReq(req, returnToCookie) || hr.body?.returnTo || "/";
312
+ const returnTo = sanitizeReturnTo(
313
+ readCookieFromReq(req, returnToCookie) || hr.body?.returnTo,
314
+ { currentOrigin: requestOriginOf(req), fallback: "/" }
315
+ );
288
316
  clearCookie(res, returnToCookie);
289
317
  if (typeof res.redirect === "function") return res.redirect(302, returnTo);
290
318
  res.status(302);
@@ -296,13 +324,23 @@ function iqAuth(options) {
296
324
  app.post(`${mount}/refresh`, async (req, res) => {
297
325
  const body = readBody(req);
298
326
  const refreshToken = body.refreshToken || readCookieFromReq(req, refreshCookie);
299
- const hr = await handleRefresh(helperConfig, { refreshToken });
327
+ const idempotencyToken = req.headers?.[IDEMPOTENCY_HEADER] || body.idempotencyToken;
328
+ const hr = await handleRefresh(helperConfig, { refreshToken, idempotencyToken });
300
329
  applyHandlerResponse(res, hr);
301
330
  });
331
+ if (options.mountUserinfo && typeof app.get === "function") {
332
+ app.get(`${mount}/me`, async (req, res) => {
333
+ const accessToken = req.headers?.authorization?.replace(/^Bearer /i, "") || readCookieFromReq(req, accessCookie);
334
+ const hr = await handleUserinfo(helperConfig, { accessToken, req });
335
+ applyHandlerResponse(res, hr);
336
+ });
337
+ }
302
338
  app.post(`${mount}/signout`, async (req, res) => {
303
339
  const accessToken = req.headers?.authorization?.replace(/^Bearer /i, "") || readCookieFromReq(req, accessCookie);
340
+ const refreshToken = readCookieFromReq(req, refreshCookie);
304
341
  const ssoCookieHeader = req.headers?.cookie;
305
- const hr = await handleSignout(helperConfig, { accessToken, ssoCookieHeader });
342
+ const idempotencyToken = req.headers?.[IDEMPOTENCY_HEADER];
343
+ const hr = await handleSignout(helperConfig, { accessToken, refreshToken, idempotencyToken, ssoCookieHeader });
306
344
  applyHandlerResponse(res, hr);
307
345
  });
308
346
  };
@@ -310,6 +348,7 @@ function iqAuth(options) {
310
348
  composed.middleware = middleware;
311
349
  composed.attachHelpers = attachHelpers;
312
350
  composed.client = client;
351
+ composed.prewarm = () => client.prewarm();
313
352
  return composed;
314
353
  }
315
354
  export {
@@ -1,4 +1,6 @@
1
1
  import { IQAuthHelperConfig } from './server/handlers.mjs';
2
+ import './tokens-B06VtvUi.mjs';
3
+ import './types-Bn8O-OEd.mjs';
2
4
 
3
5
  /**
4
6
  * @iqauth/sdk/fastify — Fastify adapter.
@@ -15,6 +17,14 @@ import { IQAuthHelperConfig } from './server/handlers.mjs';
15
17
  interface IQAuthFastifyOptions extends IQAuthHelperConfig {
16
18
  mountPath?: string;
17
19
  mountHelperRoutes?: boolean;
20
+ /**
21
+ * Cookie name the browser SDK publishes the post-login destination into
22
+ * before redirect. The callback handler reads it, surfaces it as `returnTo`
23
+ * in the JSON response body after a successful exchange, and clears it on
24
+ * success. Mirrors the express inline-callback adapter. Defaults to
25
+ * `iqauth_return_to`.
26
+ */
27
+ returnToCookieName?: string;
18
28
  /** Routes that bypass verification (e.g. health checks). */
19
29
  publicPaths?: string[] | ((path: string) => boolean);
20
30
  /** Override token verification options (issuer / audience / clock tolerance). */
package/dist/fastify.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { IQAuthHelperConfig } from './server/handlers.js';
2
+ import './tokens-9F6ETrzk.js';
3
+ import './types-Bn8O-OEd.js';
2
4
 
3
5
  /**
4
6
  * @iqauth/sdk/fastify — Fastify adapter.
@@ -15,6 +17,14 @@ import { IQAuthHelperConfig } from './server/handlers.js';
15
17
  interface IQAuthFastifyOptions extends IQAuthHelperConfig {
16
18
  mountPath?: string;
17
19
  mountHelperRoutes?: boolean;
20
+ /**
21
+ * Cookie name the browser SDK publishes the post-login destination into
22
+ * before redirect. The callback handler reads it, surfaces it as `returnTo`
23
+ * in the JSON response body after a successful exchange, and clears it on
24
+ * success. Mirrors the express inline-callback adapter. Defaults to
25
+ * `iqauth_return_to`.
26
+ */
27
+ returnToCookieName?: string;
18
28
  /** Routes that bypass verification (e.g. health checks). */
19
29
  publicPaths?: string[] | ((path: string) => boolean);
20
30
  /** Override token verification options (issuer / audience / clock tolerance). */