@alepha/react 0.12.0 → 0.13.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 (85) hide show
  1. package/dist/auth/chunk-DhGyd7sr.js +28 -0
  2. package/dist/auth/index.browser.js +394 -114
  3. package/dist/auth/index.browser.js.map +1 -1
  4. package/dist/auth/index.cjs +80 -1927
  5. package/dist/auth/index.cjs.map +1 -1
  6. package/dist/auth/index.d.cts +1130 -420
  7. package/dist/auth/index.d.ts +1130 -420
  8. package/dist/auth/index.js +72 -1918
  9. package/dist/auth/index.js.map +1 -1
  10. package/dist/core/chunk-DhGyd7sr.js +28 -0
  11. package/dist/core/index.browser.js +79 -79
  12. package/dist/core/index.browser.js.map +1 -1
  13. package/dist/core/index.cjs +89 -85
  14. package/dist/core/index.cjs.map +1 -1
  15. package/dist/core/index.d.cts +1654 -154
  16. package/dist/core/index.d.ts +1654 -154
  17. package/dist/core/index.js +79 -79
  18. package/dist/core/index.js.map +1 -1
  19. package/dist/form/chunk-DhGyd7sr.js +28 -0
  20. package/dist/form/index.cjs +28 -8
  21. package/dist/form/index.cjs.map +1 -1
  22. package/dist/form/index.d.cts +215 -7
  23. package/dist/form/index.d.ts +215 -7
  24. package/dist/form/index.js +18 -3
  25. package/dist/form/index.js.map +1 -1
  26. package/dist/head/chunk-DhGyd7sr.js +28 -0
  27. package/dist/head/index.browser.js +385 -59
  28. package/dist/head/index.browser.js.map +1 -1
  29. package/dist/head/index.cjs +12 -8
  30. package/dist/head/index.cjs.map +1 -1
  31. package/dist/head/index.d.cts +1230 -24
  32. package/dist/head/index.d.ts +1230 -29
  33. package/dist/head/index.js +2 -2
  34. package/dist/head/index.js.map +1 -1
  35. package/dist/i18n/chunk-DhGyd7sr.js +28 -0
  36. package/dist/i18n/index.cjs +33 -20
  37. package/dist/i18n/index.cjs.map +1 -1
  38. package/dist/i18n/index.d.cts +282 -13
  39. package/dist/i18n/index.d.ts +282 -13
  40. package/dist/i18n/index.js +23 -14
  41. package/dist/i18n/index.js.map +1 -1
  42. package/dist/websocket/index.cjs +21 -8
  43. package/dist/websocket/index.cjs.map +1 -1
  44. package/dist/websocket/index.js +11 -2
  45. package/dist/websocket/index.js.map +1 -1
  46. package/package.json +7 -6
  47. package/src/auth/index.browser.ts +3 -6
  48. package/src/auth/index.shared.ts +0 -1
  49. package/src/auth/index.ts +3 -16
  50. package/src/auth/providers/ReactAuthProvider.ts +1 -614
  51. package/src/auth/services/ReactAuth.ts +6 -17
  52. package/src/core/descriptors/$page.ts +1 -1
  53. package/src/core/index.browser.ts +1 -0
  54. package/src/core/index.native.ts +21 -0
  55. package/src/core/index.shared-router.ts +15 -0
  56. package/src/core/index.shared.ts +0 -14
  57. package/src/core/index.ts +1 -0
  58. package/src/core/services/ReactRouter.ts +2 -2
  59. package/src/form/errors/FormValidationError.ts +20 -0
  60. package/src/form/hooks/useForm.ts +1 -1
  61. package/src/form/index.ts +1 -0
  62. package/src/head/providers/BrowserHeadProvider.ts +1 -1
  63. package/src/i18n/descriptors/$dictionary.ts +7 -3
  64. package/src/i18n/providers/I18nProvider.ts +9 -10
  65. package/src/websocket/hooks/useRoom.tsx +21 -2
  66. package/dist/auth/index.d.cts.map +0 -1
  67. package/dist/auth/index.d.ts.map +0 -1
  68. package/dist/core/index.d.cts.map +0 -1
  69. package/dist/core/index.d.ts.map +0 -1
  70. package/dist/form/index.d.cts.map +0 -1
  71. package/dist/form/index.d.ts.map +0 -1
  72. package/dist/head/index.d.cts.map +0 -1
  73. package/dist/head/index.d.ts.map +0 -1
  74. package/dist/i18n/index.d.cts.map +0 -1
  75. package/dist/i18n/index.d.ts.map +0 -1
  76. package/dist/websocket/index.d.cts.map +0 -1
  77. package/dist/websocket/index.d.ts.map +0 -1
  78. package/src/auth/descriptors/$auth.ts +0 -436
  79. package/src/auth/descriptors/$authApple.ts +0 -8
  80. package/src/auth/descriptors/$authGithub.ts +0 -81
  81. package/src/auth/descriptors/$authGoogle.ts +0 -38
  82. package/src/auth/errors/SessionExpiredError.ts +0 -6
  83. package/src/auth/schemas/tokenResponseSchema.ts +0 -11
  84. package/src/auth/schemas/tokensSchema.ts +0 -21
  85. package/src/auth/schemas/userinfoResponseSchema.ts +0 -10
@@ -1,8 +1,8 @@
1
- import { $atom, $context, $env, $hook, $inject, $module, $use, Alepha, AlephaError, Atom, Descriptor, KIND, createDescriptor, t } from "alepha";
1
+ import { $atom, $env, $hook, $inject, $module, $use, Alepha, AlephaError, Atom, Descriptor, KIND, createDescriptor, t } from "alepha";
2
2
  import { AlephaDateTime, DateTimeProvider } from "alepha/datetime";
3
- import { $route, AlephaServer, BadRequestError, HttpClient, ServerProvider, ServerRouterProvider, ServerTimingProvider, UnauthorizedError } from "alepha/server";
3
+ import { AlephaServer, HttpClient, ServerProvider, ServerRouterProvider, ServerTimingProvider } from "alepha/server";
4
4
  import { AlephaServerCache } from "alepha/server/cache";
5
- import { AlephaServerLinks, LinkProvider, ServerLinksProvider, apiLinksResponseSchema } from "alepha/server/links";
5
+ import { AlephaServerLinks, LinkProvider, ServerLinksProvider } from "alepha/server/links";
6
6
  import { $logger } from "alepha/logger";
7
7
  import React, { StrictMode, createContext, createElement, memo, use, useContext, useEffect, useMemo, useRef, useState } from "react";
8
8
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -11,8 +11,7 @@ import { join } from "node:path";
11
11
  import { ServerStaticProvider } from "alepha/server/static";
12
12
  import { renderToString } from "react-dom/server";
13
13
  import { RouterProvider } from "alepha/router";
14
- import { $cookie, AlephaServerCookies, ServerCookiesProvider } from "alepha/server/cookies";
15
- import { SecurityError, SecurityProvider, userAccountInfoSchema } from "alepha/security";
14
+ import { $auth, AlephaServerAuth, alephaServerAuthRoutes, tokenResponseSchema, userinfoResponseSchema } from "alepha/server/auth";
16
15
 
17
16
  //#region src/core/services/ReactPageService.ts
18
17
  var ReactPageService = class {
@@ -72,7 +71,7 @@ var ReactPageService = class {
72
71
  * const userProfile = $page({
73
72
  * path: "/users/:id",
74
73
  * schema: {
75
- * params: t.object({ id: t.int() }),
74
+ * params: t.object({ id: t.integer() }),
76
75
  * query: t.object({ tab: t.optional(t.text()) })
77
76
  * },
78
77
  * resolve: async ({ params }) => {
@@ -161,11 +160,11 @@ $page[KIND] = PageDescriptor;
161
160
  * - you want to avoid server-side rendering for a specific part of your application
162
161
  * - you want to prevent pre-rendering of a component
163
162
  */
164
- const ClientOnly = (props$1) => {
163
+ const ClientOnly = (props) => {
165
164
  const [mounted, setMounted] = useState(false);
166
165
  useEffect(() => setMounted(true), []);
167
- if (props$1.disabled) return props$1.children;
168
- return mounted ? props$1.children : props$1.fallback;
166
+ if (props.disabled) return props.children;
167
+ return mounted ? props.children : props.fallback;
169
168
  };
170
169
  var ClientOnly_default = ClientOnly;
171
170
 
@@ -432,8 +431,8 @@ const useRouterState = () => {
432
431
  * in any part of the React component tree.
433
432
  */
434
433
  var ErrorBoundary = class extends React.Component {
435
- constructor(props$1) {
436
- super(props$1);
434
+ constructor(props) {
435
+ super(props);
437
436
  this.state = {};
438
437
  }
439
438
  /**
@@ -479,7 +478,7 @@ var ErrorBoundary_default = ErrorBoundary;
479
478
  * }
480
479
  * ```
481
480
  */
482
- const NestedView = (props$1) => {
481
+ const NestedView = (props) => {
483
482
  const index = use(RouterLayerContext)?.index ?? 0;
484
483
  const state = useRouterState();
485
484
  const [view, setView] = useState(state.layers[index]?.element);
@@ -517,7 +516,7 @@ const NestedView = (props$1) => {
517
516
  }
518
517
  }
519
518
  }, []);
520
- let element = view ?? props$1.children ?? null;
519
+ let element = view ?? props.children ?? null;
521
520
  if (animation) element = /* @__PURE__ */ jsx("div", {
522
521
  style: {
523
522
  display: "flex",
@@ -537,9 +536,9 @@ const NestedView = (props$1) => {
537
536
  children: element
538
537
  })
539
538
  });
540
- if (props$1.errorBoundary === false) return /* @__PURE__ */ jsx(Fragment, { children: element });
541
- if (props$1.errorBoundary) return /* @__PURE__ */ jsx(ErrorBoundary_default, {
542
- fallback: props$1.errorBoundary,
539
+ if (props.errorBoundary === false) return /* @__PURE__ */ jsx(Fragment, { children: element });
540
+ if (props.errorBoundary) return /* @__PURE__ */ jsx(ErrorBoundary_default, {
541
+ fallback: props.errorBoundary,
543
542
  children: element
544
543
  });
545
544
  return /* @__PURE__ */ jsx(ErrorBoundary_default, {
@@ -580,7 +579,7 @@ function parseAnimation(animationLike, state, type = "enter") {
580
579
 
581
580
  //#endregion
582
581
  //#region src/core/components/NotFound.tsx
583
- function NotFoundPage(props$1) {
582
+ function NotFoundPage(props) {
584
583
  return /* @__PURE__ */ jsx("div", {
585
584
  style: {
586
585
  height: "100vh",
@@ -591,7 +590,7 @@ function NotFoundPage(props$1) {
591
590
  textAlign: "center",
592
591
  fontFamily: "sans-serif",
593
592
  padding: "1rem",
594
- ...props$1.style
593
+ ...props.style
595
594
  },
596
595
  children: /* @__PURE__ */ jsx("h1", {
597
596
  style: {
@@ -671,7 +670,7 @@ var ReactPageProvider = class {
671
670
  if (t.schema.isObject(schema) && typeof value === "object") {
672
671
  for (const key in schema.properties) if (t.schema.isObject(schema.properties[key]) && typeof value[key] === "string") try {
673
672
  value[key] = this.alepha.codec.decode(schema.properties[key], decodeURIComponent(value[key]));
674
- } catch (e$1) {}
673
+ } catch (e) {}
675
674
  }
676
675
  return value;
677
676
  };
@@ -696,14 +695,14 @@ var ReactPageProvider = class {
696
695
  try {
697
696
  this.convertStringObjectToObject(route$1.schema?.query, state.query);
698
697
  config.query = route$1.schema?.query ? this.alepha.codec.decode(route$1.schema.query, state.query) : {};
699
- } catch (e$1) {
700
- it.error = e$1;
698
+ } catch (e) {
699
+ it.error = e;
701
700
  break;
702
701
  }
703
702
  try {
704
703
  config.params = route$1.schema?.params ? this.alepha.codec.decode(route$1.schema.params, state.params) : {};
705
- } catch (e$1) {
706
- it.error = e$1;
704
+ } catch (e) {
705
+ it.error = e;
707
706
  break;
708
707
  }
709
708
  it.config = { ...config };
@@ -731,23 +730,23 @@ var ReactPageProvider = class {
731
730
  try {
732
731
  const args = Object.create(state);
733
732
  Object.assign(args, config, context);
734
- const props$1 = await route$1.resolve?.(args) ?? {};
735
- it.props = { ...props$1 };
733
+ const props = await route$1.resolve?.(args) ?? {};
734
+ it.props = { ...props };
736
735
  context = {
737
736
  ...context,
738
- ...props$1
737
+ ...props
739
738
  };
740
- } catch (e$1) {
741
- if (e$1 instanceof Redirection) return { redirect: e$1.redirect };
742
- this.log.error("Page resolver has failed", e$1);
743
- it.error = e$1;
739
+ } catch (e) {
740
+ if (e instanceof Redirection) return { redirect: e.redirect };
741
+ this.log.error("Page resolver has failed", e);
742
+ it.error = e;
744
743
  break;
745
744
  }
746
745
  }
747
746
  let acc = "";
748
747
  for (let i = 0; i < stack.length; i++) {
749
748
  const it = stack[i];
750
- const props$1 = it.props ?? {};
749
+ const props = it.props ?? {};
751
750
  const params = { ...it.config?.params };
752
751
  for (const key of Object.keys(params)) params[key] = String(params[key]);
753
752
  acc += "/";
@@ -764,12 +763,12 @@ var ReactPageProvider = class {
764
763
  }
765
764
  if (!it.error) try {
766
765
  const element = await this.createElement(it.route, {
767
- ...props$1,
766
+ ...props,
768
767
  ...context
769
768
  });
770
769
  state.layers.push({
771
770
  name: it.route.name,
772
- props: props$1,
771
+ props,
773
772
  part: it.route.path,
774
773
  config: it.config,
775
774
  element: this.renderView(i + 1, path, element, it.route),
@@ -778,8 +777,8 @@ var ReactPageProvider = class {
778
777
  route: it.route,
779
778
  cache: it.cache
780
779
  });
781
- } catch (e$1) {
782
- it.error = e$1;
780
+ } catch (e) {
781
+ it.error = e;
783
782
  }
784
783
  if (it.error) try {
785
784
  let element = await state.onError(it.error, state);
@@ -787,7 +786,7 @@ var ReactPageProvider = class {
787
786
  if (element instanceof Redirection) return { redirect: element.redirect };
788
787
  if (element === null) element = this.renderError(it.error);
789
788
  state.layers.push({
790
- props: props$1,
789
+ props,
791
790
  error: it.error,
792
791
  name: it.route.name,
793
792
  part: it.route.path,
@@ -798,9 +797,9 @@ var ReactPageProvider = class {
798
797
  route: it.route
799
798
  });
800
799
  break;
801
- } catch (e$1) {
802
- if (e$1 instanceof Redirection) return { redirect: e$1.redirect };
803
- throw e$1;
800
+ } catch (e) {
801
+ if (e instanceof Redirection) return { redirect: e.redirect };
802
+ throw e;
804
803
  }
805
804
  }
806
805
  return { state };
@@ -816,10 +815,10 @@ var ReactPageProvider = class {
816
815
  parent = parent.parent;
817
816
  }
818
817
  }
819
- async createElement(page, props$1) {
818
+ async createElement(page, props) {
820
819
  if (page.lazy && page.component) this.log.warn(`Page ${page.name} has both lazy and component options, lazy will be used`);
821
- if (page.lazy) return createElement((await page.lazy()).default, props$1);
822
- if (page.component) return createElement(page.component, props$1);
820
+ if (page.lazy) return createElement((await page.lazy()).default, props);
821
+ if (page.component) return createElement(page.component, props);
823
822
  }
824
823
  renderError(error) {
825
824
  return createElement(ErrorViewer_default, {
@@ -1307,20 +1306,20 @@ var ReactBrowserRouterProvider = class extends RouterProvider {
1307
1306
  });
1308
1307
  await this.alepha.events.emit("react:action:success", { type: "transition" });
1309
1308
  await this.alepha.events.emit("react:transition:success", { state });
1310
- } catch (e$1) {
1311
- this.log.error("Transition has failed", e$1);
1309
+ } catch (e) {
1310
+ this.log.error("Transition has failed", e);
1312
1311
  state.layers = [{
1313
1312
  name: "error",
1314
- element: this.pageApi.renderError(e$1),
1313
+ element: this.pageApi.renderError(e),
1315
1314
  index: 0,
1316
1315
  path: "/"
1317
1316
  }];
1318
1317
  await this.alepha.events.emit("react:action:error", {
1319
1318
  type: "transition",
1320
- error: e$1
1319
+ error: e
1321
1320
  });
1322
1321
  await this.alepha.events.emit("react:transition:error", {
1323
- error: e$1,
1322
+ error: e,
1324
1323
  state
1325
1324
  });
1326
1325
  }
@@ -1401,12 +1400,12 @@ var ReactBrowserProvider = class {
1401
1400
  if (replace) this.history.replaceState({}, "", url);
1402
1401
  else this.history.pushState({}, "", url);
1403
1402
  }
1404
- async invalidate(props$1) {
1403
+ async invalidate(props) {
1405
1404
  const previous = [];
1406
1405
  this.log.trace("Invalidating layers");
1407
- if (props$1) {
1408
- const [key] = Object.keys(props$1);
1409
- const value = props$1[key];
1406
+ if (props) {
1407
+ const [key] = Object.keys(props);
1408
+ const value = props[key];
1410
1409
  for (const layer of this.state.layers) {
1411
1410
  if (layer.props?.[key]) {
1412
1411
  previous.push({
@@ -1528,7 +1527,7 @@ var ReactRouter = class {
1528
1527
  path(name, config = {}) {
1529
1528
  return this.pageApi.pathname(name, {
1530
1529
  params: {
1531
- ...this.state.params,
1530
+ ...this.state?.params,
1532
1531
  ...config.params
1533
1532
  },
1534
1533
  query: config.query
@@ -1570,8 +1569,8 @@ var ReactRouter = class {
1570
1569
  async forward() {
1571
1570
  this.browser?.history.forward();
1572
1571
  }
1573
- async invalidate(props$1) {
1574
- await this.browser?.invalidate(props$1);
1572
+ async invalidate(props) {
1573
+ await this.browser?.invalidate(props);
1575
1574
  }
1576
1575
  async go(path, options) {
1577
1576
  for (const page of this.pages) if (page.name === path) {
@@ -1644,1411 +1643,30 @@ const AlephaReact = $module({
1644
1643
  });
1645
1644
 
1646
1645
  //#endregion
1647
- //#region ../../node_modules/oauth4webapi/build/index.js
1648
- let USER_AGENT$1;
1649
- if (typeof navigator === "undefined" || !navigator.userAgent?.startsWith?.("Mozilla/5.0 ")) USER_AGENT$1 = `oauth4webapi/v3.8.2`;
1650
- function looseInstanceOf(input, expected) {
1651
- if (input == null) return false;
1652
- try {
1653
- return input instanceof expected || Object.getPrototypeOf(input)[Symbol.toStringTag] === expected.prototype[Symbol.toStringTag];
1654
- } catch {
1655
- return false;
1656
- }
1657
- }
1658
- const ERR_INVALID_ARG_VALUE$1 = "ERR_INVALID_ARG_VALUE";
1659
- const ERR_INVALID_ARG_TYPE$1 = "ERR_INVALID_ARG_TYPE";
1660
- function CodedTypeError$1(message, code, cause) {
1661
- const err = new TypeError(message, { cause });
1662
- Object.assign(err, { code });
1663
- return err;
1664
- }
1665
- const allowInsecureRequests$1 = Symbol();
1666
- const clockSkew$1 = Symbol();
1667
- const clockTolerance$1 = Symbol();
1668
- const customFetch$1 = Symbol();
1669
- const modifyAssertion$1 = Symbol();
1670
- const jweDecrypt = Symbol();
1671
- const encoder = new TextEncoder();
1672
- const decoder$1 = new TextDecoder();
1673
- function buf(input) {
1674
- if (typeof input === "string") return encoder.encode(input);
1675
- return decoder$1.decode(input);
1676
- }
1677
- let encodeBase64Url;
1678
- if (Uint8Array.prototype.toBase64) encodeBase64Url = (input) => {
1679
- if (input instanceof ArrayBuffer) input = new Uint8Array(input);
1680
- return input.toBase64({
1681
- alphabet: "base64url",
1682
- omitPadding: true
1683
- });
1684
- };
1685
- else {
1686
- const CHUNK_SIZE = 32768;
1687
- encodeBase64Url = (input) => {
1688
- if (input instanceof ArrayBuffer) input = new Uint8Array(input);
1689
- const arr = [];
1690
- for (let i = 0; i < input.byteLength; i += CHUNK_SIZE) arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));
1691
- return btoa(arr.join("")).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
1692
- };
1693
- }
1694
- let decodeBase64Url;
1695
- if (Uint8Array.fromBase64) decodeBase64Url = (input) => {
1696
- try {
1697
- return Uint8Array.fromBase64(input, { alphabet: "base64url" });
1698
- } catch (cause) {
1699
- throw CodedTypeError$1("The input to be decoded is not correctly encoded.", ERR_INVALID_ARG_VALUE$1, cause);
1700
- }
1701
- };
1702
- else decodeBase64Url = (input) => {
1703
- try {
1704
- const binary = atob(input.replace(/-/g, "+").replace(/_/g, "/").replace(/\s/g, ""));
1705
- const bytes = new Uint8Array(binary.length);
1706
- for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
1707
- return bytes;
1708
- } catch (cause) {
1709
- throw CodedTypeError$1("The input to be decoded is not correctly encoded.", ERR_INVALID_ARG_VALUE$1, cause);
1710
- }
1711
- };
1712
- function b64u(input) {
1713
- if (typeof input === "string") return decodeBase64Url(input);
1714
- return encodeBase64Url(input);
1715
- }
1716
- var UnsupportedOperationError = class extends Error {
1717
- code;
1718
- constructor(message, options) {
1719
- super(message, options);
1720
- this.name = this.constructor.name;
1721
- this.code = UNSUPPORTED_OPERATION;
1722
- Error.captureStackTrace?.(this, this.constructor);
1723
- }
1724
- };
1725
- var OperationProcessingError = class extends Error {
1726
- code;
1727
- constructor(message, options) {
1728
- super(message, options);
1729
- this.name = this.constructor.name;
1730
- if (options?.code) this.code = options?.code;
1731
- Error.captureStackTrace?.(this, this.constructor);
1732
- }
1733
- };
1734
- function OPE(message, code, cause) {
1735
- return new OperationProcessingError(message, {
1736
- code,
1737
- cause
1738
- });
1739
- }
1740
- function isJsonObject(input) {
1741
- if (input === null || typeof input !== "object" || Array.isArray(input)) return false;
1742
- return true;
1743
- }
1744
- function prepareHeaders(input) {
1745
- if (looseInstanceOf(input, Headers)) input = Object.fromEntries(input.entries());
1746
- const headers$1 = new Headers(input ?? {});
1747
- if (USER_AGENT$1 && !headers$1.has("user-agent")) headers$1.set("user-agent", USER_AGENT$1);
1748
- if (headers$1.has("authorization")) throw CodedTypeError$1("\"options.headers\" must not include the \"authorization\" header name", ERR_INVALID_ARG_VALUE$1);
1749
- return headers$1;
1750
- }
1751
- function signal$1(url, value) {
1752
- if (value !== void 0) {
1753
- if (typeof value === "function") value = value(url.href);
1754
- if (!(value instanceof AbortSignal)) throw CodedTypeError$1("\"options.signal\" must return or be an instance of AbortSignal", ERR_INVALID_ARG_TYPE$1);
1755
- return value;
1756
- }
1757
- }
1758
- function replaceDoubleSlash(pathname) {
1759
- if (pathname.includes("//")) return pathname.replace("//", "/");
1760
- return pathname;
1761
- }
1762
- function prependWellKnown(url, wellKnown, allowTerminatingSlash = false) {
1763
- if (url.pathname === "/") url.pathname = wellKnown;
1764
- else url.pathname = replaceDoubleSlash(`${wellKnown}/${allowTerminatingSlash ? url.pathname : url.pathname.replace(/(\/)$/, "")}`);
1765
- return url;
1766
- }
1767
- function appendWellKnown(url, wellKnown) {
1768
- url.pathname = replaceDoubleSlash(`${url.pathname}/${wellKnown}`);
1769
- return url;
1770
- }
1771
- async function performDiscovery$1(input, urlName, transform, options) {
1772
- if (!(input instanceof URL)) throw CodedTypeError$1(`"${urlName}" must be an instance of URL`, ERR_INVALID_ARG_TYPE$1);
1773
- checkProtocol(input, options?.[allowInsecureRequests$1] !== true);
1774
- const url = transform(new URL(input.href));
1775
- const headers$1 = prepareHeaders(options?.headers);
1776
- headers$1.set("accept", "application/json");
1777
- return (options?.[customFetch$1] || fetch)(url.href, {
1778
- body: void 0,
1779
- headers: Object.fromEntries(headers$1.entries()),
1780
- method: "GET",
1781
- redirect: "manual",
1782
- signal: signal$1(url, options?.signal)
1783
- });
1784
- }
1785
- async function discoveryRequest(issuerIdentifier, options) {
1786
- return performDiscovery$1(issuerIdentifier, "issuerIdentifier", (url) => {
1787
- switch (options?.algorithm) {
1788
- case void 0:
1789
- case "oidc":
1790
- appendWellKnown(url, ".well-known/openid-configuration");
1791
- break;
1792
- case "oauth2":
1793
- prependWellKnown(url, ".well-known/oauth-authorization-server");
1794
- break;
1795
- default: throw CodedTypeError$1("\"options.algorithm\" must be \"oidc\" (default), or \"oauth2\"", ERR_INVALID_ARG_VALUE$1);
1796
- }
1797
- return url;
1798
- }, options);
1799
- }
1800
- function assertNumber(input, allow0, it, code, cause) {
1801
- try {
1802
- if (typeof input !== "number" || !Number.isFinite(input)) throw CodedTypeError$1(`${it} must be a number`, ERR_INVALID_ARG_TYPE$1, cause);
1803
- if (input > 0) return;
1804
- if (allow0) {
1805
- if (input !== 0) throw CodedTypeError$1(`${it} must be a non-negative number`, ERR_INVALID_ARG_VALUE$1, cause);
1806
- return;
1807
- }
1808
- throw CodedTypeError$1(`${it} must be a positive number`, ERR_INVALID_ARG_VALUE$1, cause);
1809
- } catch (err) {
1810
- if (code) throw OPE(err.message, code, cause);
1811
- throw err;
1812
- }
1813
- }
1814
- function assertString$1(input, it, code, cause) {
1815
- try {
1816
- if (typeof input !== "string") throw CodedTypeError$1(`${it} must be a string`, ERR_INVALID_ARG_TYPE$1, cause);
1817
- if (input.length === 0) throw CodedTypeError$1(`${it} must not be empty`, ERR_INVALID_ARG_VALUE$1, cause);
1818
- } catch (err) {
1819
- if (code) throw OPE(err.message, code, cause);
1820
- throw err;
1821
- }
1822
- }
1823
- async function processDiscoveryResponse(expectedIssuerIdentifier, response) {
1824
- const expected = expectedIssuerIdentifier;
1825
- if (!(expected instanceof URL) && expected !== _nodiscoverycheck) throw CodedTypeError$1("\"expectedIssuerIdentifier\" must be an instance of URL", ERR_INVALID_ARG_TYPE$1);
1826
- if (!looseInstanceOf(response, Response)) throw CodedTypeError$1("\"response\" must be an instance of Response", ERR_INVALID_ARG_TYPE$1);
1827
- if (response.status !== 200) throw OPE("\"response\" is not a conform Authorization Server Metadata response (unexpected HTTP status code)", RESPONSE_IS_NOT_CONFORM, response);
1828
- assertReadableResponse(response);
1829
- const json = await getResponseJsonBody(response);
1830
- assertString$1(json.issuer, "\"response\" body \"issuer\" property", INVALID_RESPONSE, { body: json });
1831
- if (expected !== _nodiscoverycheck && new URL(json.issuer).href !== expected.href) throw OPE("\"response\" body \"issuer\" property does not match the expected value", JSON_ATTRIBUTE_COMPARISON, {
1832
- expected: expected.href,
1833
- body: json,
1834
- attribute: "issuer"
1835
- });
1836
- return json;
1837
- }
1838
- function assertApplicationJson(response) {
1839
- assertContentType(response, "application/json");
1840
- }
1841
- function notJson(response, ...types) {
1842
- let msg = "\"response\" content-type must be ";
1843
- if (types.length > 2) {
1844
- const last = types.pop();
1845
- msg += `${types.join(", ")}, or ${last}`;
1846
- } else if (types.length === 2) msg += `${types[0]} or ${types[1]}`;
1847
- else msg += types[0];
1848
- return OPE(msg, RESPONSE_IS_NOT_JSON, response);
1849
- }
1850
- function assertContentType(response, contentType) {
1851
- if (getContentType(response) !== contentType) throw notJson(response, contentType);
1852
- }
1853
- function randomBytes() {
1854
- return b64u(crypto.getRandomValues(new Uint8Array(32)));
1855
- }
1856
- function generateRandomCodeVerifier() {
1857
- return randomBytes();
1858
- }
1859
- function generateRandomState() {
1860
- return randomBytes();
1861
- }
1862
- async function calculatePKCECodeChallenge$1(codeVerifier) {
1863
- assertString$1(codeVerifier, "codeVerifier");
1864
- return b64u(await crypto.subtle.digest("SHA-256", buf(codeVerifier)));
1865
- }
1866
- function getClockSkew(client) {
1867
- const skew = client?.[clockSkew$1];
1868
- return typeof skew === "number" && Number.isFinite(skew) ? skew : 0;
1869
- }
1870
- function getClockTolerance(client) {
1871
- const tolerance = client?.[clockTolerance$1];
1872
- return typeof tolerance === "number" && Number.isFinite(tolerance) && Math.sign(tolerance) !== -1 ? tolerance : 30;
1873
- }
1874
- function epochTime() {
1875
- return Math.floor(Date.now() / 1e3);
1876
- }
1877
- function assertAs(as) {
1878
- if (typeof as !== "object" || as === null) throw CodedTypeError$1("\"as\" must be an object", ERR_INVALID_ARG_TYPE$1);
1879
- assertString$1(as.issuer, "\"as.issuer\"");
1880
- }
1881
- function assertClient(client) {
1882
- if (typeof client !== "object" || client === null) throw CodedTypeError$1("\"client\" must be an object", ERR_INVALID_ARG_TYPE$1);
1883
- assertString$1(client.client_id, "\"client.client_id\"");
1884
- }
1885
- function ClientSecretPost$1(clientSecret) {
1886
- assertString$1(clientSecret, "\"clientSecret\"");
1887
- return (_as, client, body, _headers) => {
1888
- body.set("client_id", client.client_id);
1889
- body.set("client_secret", clientSecret);
1890
- };
1891
- }
1892
- function None$1() {
1893
- return (_as, client, body, _headers) => {
1894
- body.set("client_id", client.client_id);
1895
- };
1896
- }
1897
- const URLParse = URL.parse ? (url, base) => URL.parse(url, base) : (url, base) => {
1898
- try {
1899
- return new URL(url, base);
1900
- } catch {
1901
- return null;
1902
- }
1903
- };
1904
- function checkProtocol(url, enforceHttps) {
1905
- if (enforceHttps && url.protocol !== "https:") throw OPE("only requests to HTTPS are allowed", HTTP_REQUEST_FORBIDDEN, url);
1906
- if (url.protocol !== "https:" && url.protocol !== "http:") throw OPE("only HTTP and HTTPS requests are allowed", REQUEST_PROTOCOL_FORBIDDEN, url);
1907
- }
1908
- function validateEndpoint(value, endpoint, useMtlsAlias, enforceHttps) {
1909
- let url;
1910
- if (typeof value !== "string" || !(url = URLParse(value))) throw OPE(`authorization server metadata does not contain a valid ${useMtlsAlias ? `"as.mtls_endpoint_aliases.${endpoint}"` : `"as.${endpoint}"`}`, value === void 0 ? MISSING_SERVER_METADATA : INVALID_SERVER_METADATA, { attribute: useMtlsAlias ? `mtls_endpoint_aliases.${endpoint}` : endpoint });
1911
- checkProtocol(url, enforceHttps);
1912
- return url;
1913
- }
1914
- function resolveEndpoint(as, endpoint, useMtlsAlias, enforceHttps) {
1915
- if (useMtlsAlias && as.mtls_endpoint_aliases && endpoint in as.mtls_endpoint_aliases) return validateEndpoint(as.mtls_endpoint_aliases[endpoint], endpoint, useMtlsAlias, enforceHttps);
1916
- return validateEndpoint(as[endpoint], endpoint, useMtlsAlias, enforceHttps);
1917
- }
1918
- function isDPoPNonceError(err) {
1919
- if (err instanceof WWWAuthenticateChallengeError) {
1920
- const { 0: challenge, length } = err.cause;
1921
- return length === 1 && challenge.scheme === "dpop" && challenge.parameters.error === "use_dpop_nonce";
1922
- }
1923
- if (err instanceof ResponseBodyError) return err.error === "use_dpop_nonce";
1924
- return false;
1925
- }
1926
- var ResponseBodyError = class extends Error {
1927
- cause;
1928
- code;
1929
- error;
1930
- status;
1931
- error_description;
1932
- response;
1933
- constructor(message, options) {
1934
- super(message, options);
1935
- this.name = this.constructor.name;
1936
- this.code = RESPONSE_BODY_ERROR;
1937
- this.cause = options.cause;
1938
- this.error = options.cause.error;
1939
- this.status = options.response.status;
1940
- this.error_description = options.cause.error_description;
1941
- Object.defineProperty(this, "response", {
1942
- enumerable: false,
1943
- value: options.response
1944
- });
1945
- Error.captureStackTrace?.(this, this.constructor);
1946
- }
1947
- };
1948
- var AuthorizationResponseError = class extends Error {
1949
- cause;
1950
- code;
1951
- error;
1952
- error_description;
1953
- constructor(message, options) {
1954
- super(message, options);
1955
- this.name = this.constructor.name;
1956
- this.code = AUTHORIZATION_RESPONSE_ERROR;
1957
- this.cause = options.cause;
1958
- this.error = options.cause.get("error");
1959
- this.error_description = options.cause.get("error_description") ?? void 0;
1960
- Error.captureStackTrace?.(this, this.constructor);
1961
- }
1962
- };
1963
- var WWWAuthenticateChallengeError = class extends Error {
1964
- cause;
1965
- code;
1966
- response;
1967
- status;
1968
- constructor(message, options) {
1969
- super(message, options);
1970
- this.name = this.constructor.name;
1971
- this.code = WWW_AUTHENTICATE_CHALLENGE;
1972
- this.cause = options.cause;
1973
- this.status = options.response.status;
1974
- this.response = options.response;
1975
- Object.defineProperty(this, "response", { enumerable: false });
1976
- Error.captureStackTrace?.(this, this.constructor);
1977
- }
1978
- };
1979
- const tokenMatch = "[a-zA-Z0-9!#$%&\\'\\*\\+\\-\\.\\^_`\\|~]+";
1980
- const token68Match = "[a-zA-Z0-9\\-\\._\\~\\+\\/]+[=]{0,2}";
1981
- const quotedParamMatcher = "(" + tokenMatch + ")\\s*=\\s*\"((?:[^\"\\\\]|\\\\.)*)\"";
1982
- const paramMatcher = "(" + tokenMatch + ")\\s*=\\s*([a-zA-Z0-9!#$%&\\'\\*\\+\\-\\.\\^_`\\|~]+)";
1983
- const schemeRE = /* @__PURE__ */ new RegExp("^[,\\s]*(" + tokenMatch + ")\\s(.*)");
1984
- const quotedParamRE = /* @__PURE__ */ new RegExp("^[,\\s]*" + quotedParamMatcher + "[,\\s]*(.*)");
1985
- const unquotedParamRE = /* @__PURE__ */ new RegExp("^[,\\s]*" + paramMatcher + "[,\\s]*(.*)");
1986
- const token68ParamRE = /* @__PURE__ */ new RegExp("^(" + token68Match + ")(?:$|[,\\s])(.*)");
1987
- function parseWwwAuthenticateChallenges(response) {
1988
- if (!looseInstanceOf(response, Response)) throw CodedTypeError$1("\"response\" must be an instance of Response", ERR_INVALID_ARG_TYPE$1);
1989
- const header = response.headers.get("www-authenticate");
1990
- if (header === null) return;
1991
- const challenges = [];
1992
- let rest = header;
1993
- while (rest) {
1994
- let match = rest.match(schemeRE);
1995
- const scheme = match?.["1"].toLowerCase();
1996
- rest = match?.["2"];
1997
- if (!scheme) return;
1998
- const parameters = {};
1999
- let token68;
2000
- while (rest) {
2001
- let key;
2002
- let value;
2003
- if (match = rest.match(quotedParamRE)) {
2004
- [, key, value, rest] = match;
2005
- if (value.includes("\\")) try {
2006
- value = JSON.parse(`"${value}"`);
2007
- } catch {}
2008
- parameters[key.toLowerCase()] = value;
2009
- continue;
2010
- }
2011
- if (match = rest.match(unquotedParamRE)) {
2012
- [, key, value, rest] = match;
2013
- parameters[key.toLowerCase()] = value;
2014
- continue;
2015
- }
2016
- if (match = rest.match(token68ParamRE)) {
2017
- if (Object.keys(parameters).length) break;
2018
- [, token68, rest] = match;
2019
- break;
2020
- }
2021
- return;
2022
- }
2023
- const challenge = {
2024
- scheme,
2025
- parameters
2026
- };
2027
- if (token68) challenge.token68 = token68;
2028
- challenges.push(challenge);
2029
- }
2030
- if (!challenges.length) return;
2031
- return challenges;
2032
- }
2033
- async function parseOAuthResponseErrorBody(response) {
2034
- if (response.status > 399 && response.status < 500) {
2035
- assertReadableResponse(response);
2036
- assertApplicationJson(response);
2037
- try {
2038
- const json = await response.clone().json();
2039
- if (isJsonObject(json) && typeof json.error === "string" && json.error.length) return json;
2040
- } catch {}
2041
- }
2042
- }
2043
- async function checkOAuthBodyError(response, expected, label) {
2044
- if (response.status !== expected) {
2045
- checkAuthenticationChallenges(response);
2046
- let err;
2047
- if (err = await parseOAuthResponseErrorBody(response)) {
2048
- await response.body?.cancel();
2049
- throw new ResponseBodyError("server responded with an error in the response body", {
2050
- cause: err,
2051
- response
2052
- });
2053
- }
2054
- throw OPE(`"response" is not a conform ${label} response (unexpected HTTP status code)`, RESPONSE_IS_NOT_CONFORM, response);
2055
- }
2056
- }
2057
- function assertDPoP(option) {
2058
- if (!branded.has(option)) throw CodedTypeError$1("\"options.DPoP\" is not a valid DPoPHandle", ERR_INVALID_ARG_VALUE$1);
2059
- }
2060
- const skipSubjectCheck$1 = Symbol();
2061
- function getContentType(input) {
2062
- return input.headers.get("content-type")?.split(";")[0];
2063
- }
2064
- async function authenticatedRequest(as, client, clientAuthentication, url, body, headers$1, options) {
2065
- await clientAuthentication(as, client, body, headers$1);
2066
- headers$1.set("content-type", "application/x-www-form-urlencoded;charset=UTF-8");
2067
- return (options?.[customFetch$1] || fetch)(url.href, {
2068
- body,
2069
- headers: Object.fromEntries(headers$1.entries()),
2070
- method: "POST",
2071
- redirect: "manual",
2072
- signal: signal$1(url, options?.signal)
2073
- });
2074
- }
2075
- async function tokenEndpointRequest(as, client, clientAuthentication, grantType, parameters, options) {
2076
- const url = resolveEndpoint(as, "token_endpoint", client.use_mtls_endpoint_aliases, options?.[allowInsecureRequests$1] !== true);
2077
- parameters.set("grant_type", grantType);
2078
- const headers$1 = prepareHeaders(options?.headers);
2079
- headers$1.set("accept", "application/json");
2080
- if (options?.DPoP !== void 0) {
2081
- assertDPoP(options.DPoP);
2082
- await options.DPoP.addProof(url, headers$1, "POST");
2083
- }
2084
- const response = await authenticatedRequest(as, client, clientAuthentication, url, parameters, headers$1, options);
2085
- options?.DPoP?.cacheNonce(response, url);
2086
- return response;
2087
- }
2088
- async function refreshTokenGrantRequest(as, client, clientAuthentication, refreshToken, options) {
2089
- assertAs(as);
2090
- assertClient(client);
2091
- assertString$1(refreshToken, "\"refreshToken\"");
2092
- const parameters = new URLSearchParams(options?.additionalParameters);
2093
- parameters.set("refresh_token", refreshToken);
2094
- return tokenEndpointRequest(as, client, clientAuthentication, "refresh_token", parameters, options);
2095
- }
2096
- const idTokenClaims = /* @__PURE__ */ new WeakMap();
2097
- const jwtRefs = /* @__PURE__ */ new WeakMap();
2098
- function getValidatedIdTokenClaims(ref) {
2099
- if (!ref.id_token) return;
2100
- const claims = idTokenClaims.get(ref);
2101
- if (!claims) throw CodedTypeError$1("\"ref\" was already garbage collected or did not resolve from the proper sources", ERR_INVALID_ARG_VALUE$1);
2102
- return claims;
2103
- }
2104
- async function processGenericAccessTokenResponse(as, client, response, additionalRequiredIdTokenClaims, decryptFn, recognizedTokenTypes) {
2105
- assertAs(as);
2106
- assertClient(client);
2107
- if (!looseInstanceOf(response, Response)) throw CodedTypeError$1("\"response\" must be an instance of Response", ERR_INVALID_ARG_TYPE$1);
2108
- await checkOAuthBodyError(response, 200, "Token Endpoint");
2109
- assertReadableResponse(response);
2110
- const json = await getResponseJsonBody(response);
2111
- assertString$1(json.access_token, "\"response\" body \"access_token\" property", INVALID_RESPONSE, { body: json });
2112
- assertString$1(json.token_type, "\"response\" body \"token_type\" property", INVALID_RESPONSE, { body: json });
2113
- json.token_type = json.token_type.toLowerCase();
2114
- if (json.expires_in !== void 0) {
2115
- let expiresIn = typeof json.expires_in !== "number" ? parseFloat(json.expires_in) : json.expires_in;
2116
- assertNumber(expiresIn, true, "\"response\" body \"expires_in\" property", INVALID_RESPONSE, { body: json });
2117
- json.expires_in = expiresIn;
2118
- }
2119
- if (json.refresh_token !== void 0) assertString$1(json.refresh_token, "\"response\" body \"refresh_token\" property", INVALID_RESPONSE, { body: json });
2120
- if (json.scope !== void 0 && typeof json.scope !== "string") throw OPE("\"response\" body \"scope\" property must be a string", INVALID_RESPONSE, { body: json });
2121
- if (json.id_token !== void 0) {
2122
- assertString$1(json.id_token, "\"response\" body \"id_token\" property", INVALID_RESPONSE, { body: json });
2123
- const requiredClaims = [
2124
- "aud",
2125
- "exp",
2126
- "iat",
2127
- "iss",
2128
- "sub"
2129
- ];
2130
- if (client.require_auth_time === true) requiredClaims.push("auth_time");
2131
- if (client.default_max_age !== void 0) {
2132
- assertNumber(client.default_max_age, true, "\"client.default_max_age\"");
2133
- requiredClaims.push("auth_time");
2134
- }
2135
- if (additionalRequiredIdTokenClaims?.length) requiredClaims.push(...additionalRequiredIdTokenClaims);
2136
- const { claims, jwt } = await validateJwt(json.id_token, checkSigningAlgorithm.bind(void 0, client.id_token_signed_response_alg, as.id_token_signing_alg_values_supported, "RS256"), getClockSkew(client), getClockTolerance(client), decryptFn).then(validatePresence.bind(void 0, requiredClaims)).then(validateIssuer.bind(void 0, as)).then(validateAudience.bind(void 0, client.client_id));
2137
- if (Array.isArray(claims.aud) && claims.aud.length !== 1) {
2138
- if (claims.azp === void 0) throw OPE("ID Token \"aud\" (audience) claim includes additional untrusted audiences", JWT_CLAIM_COMPARISON, {
2139
- claims,
2140
- claim: "aud"
2141
- });
2142
- if (claims.azp !== client.client_id) throw OPE("unexpected ID Token \"azp\" (authorized party) claim value", JWT_CLAIM_COMPARISON, {
2143
- expected: client.client_id,
2144
- claims,
2145
- claim: "azp"
2146
- });
2147
- }
2148
- if (claims.auth_time !== void 0) assertNumber(claims.auth_time, true, "ID Token \"auth_time\" (authentication time)", INVALID_RESPONSE, { claims });
2149
- jwtRefs.set(response, jwt);
2150
- idTokenClaims.set(json, claims);
2151
- }
2152
- if (recognizedTokenTypes?.[json.token_type] !== void 0) recognizedTokenTypes[json.token_type](response, json);
2153
- else if (json.token_type !== "dpop" && json.token_type !== "bearer") throw new UnsupportedOperationError("unsupported `token_type` value", { cause: { body: json } });
2154
- return json;
2155
- }
2156
- function checkAuthenticationChallenges(response) {
2157
- let challenges;
2158
- if (challenges = parseWwwAuthenticateChallenges(response)) throw new WWWAuthenticateChallengeError("server responded with a challenge in the WWW-Authenticate HTTP Header", {
2159
- cause: challenges,
2160
- response
2161
- });
2162
- }
2163
- async function processRefreshTokenResponse(as, client, response, options) {
2164
- return processGenericAccessTokenResponse(as, client, response, void 0, options?.[jweDecrypt], options?.recognizedTokenTypes);
2165
- }
2166
- function validateAudience(expected, result) {
2167
- if (Array.isArray(result.claims.aud)) {
2168
- if (!result.claims.aud.includes(expected)) throw OPE("unexpected JWT \"aud\" (audience) claim value", JWT_CLAIM_COMPARISON, {
2169
- expected,
2170
- claims: result.claims,
2171
- claim: "aud"
2172
- });
2173
- } else if (result.claims.aud !== expected) throw OPE("unexpected JWT \"aud\" (audience) claim value", JWT_CLAIM_COMPARISON, {
2174
- expected,
2175
- claims: result.claims,
2176
- claim: "aud"
2177
- });
2178
- return result;
2179
- }
2180
- function validateIssuer(as, result) {
2181
- const expected = as[_expectedIssuer]?.(result) ?? as.issuer;
2182
- if (result.claims.iss !== expected) throw OPE("unexpected JWT \"iss\" (issuer) claim value", JWT_CLAIM_COMPARISON, {
2183
- expected,
2184
- claims: result.claims,
2185
- claim: "iss"
2186
- });
2187
- return result;
2188
- }
2189
- const branded = /* @__PURE__ */ new WeakSet();
2190
- function brand(searchParams) {
2191
- branded.add(searchParams);
2192
- return searchParams;
2193
- }
2194
- const nopkce = Symbol();
2195
- async function authorizationCodeGrantRequest(as, client, clientAuthentication, callbackParameters, redirectUri, codeVerifier, options) {
2196
- assertAs(as);
2197
- assertClient(client);
2198
- if (!branded.has(callbackParameters)) throw CodedTypeError$1("\"callbackParameters\" must be an instance of URLSearchParams obtained from \"validateAuthResponse()\", or \"validateJwtAuthResponse()", ERR_INVALID_ARG_VALUE$1);
2199
- assertString$1(redirectUri, "\"redirectUri\"");
2200
- const code = getURLSearchParameter(callbackParameters, "code");
2201
- if (!code) throw OPE("no authorization code in \"callbackParameters\"", INVALID_RESPONSE);
2202
- const parameters = new URLSearchParams(options?.additionalParameters);
2203
- parameters.set("redirect_uri", redirectUri);
2204
- parameters.set("code", code);
2205
- if (codeVerifier !== nopkce) {
2206
- assertString$1(codeVerifier, "\"codeVerifier\"");
2207
- parameters.set("code_verifier", codeVerifier);
2208
- }
2209
- return tokenEndpointRequest(as, client, clientAuthentication, "authorization_code", parameters, options);
2210
- }
2211
- const jwtClaimNames = {
2212
- aud: "audience",
2213
- c_hash: "code hash",
2214
- client_id: "client id",
2215
- exp: "expiration time",
2216
- iat: "issued at",
2217
- iss: "issuer",
2218
- jti: "jwt id",
2219
- nonce: "nonce",
2220
- s_hash: "state hash",
2221
- sub: "subject",
2222
- ath: "access token hash",
2223
- htm: "http method",
2224
- htu: "http uri",
2225
- cnf: "confirmation",
2226
- auth_time: "authentication time"
2227
- };
2228
- function validatePresence(required, result) {
2229
- for (const claim of required) if (result.claims[claim] === void 0) throw OPE(`JWT "${claim}" (${jwtClaimNames[claim]}) claim missing`, INVALID_RESPONSE, { claims: result.claims });
2230
- return result;
2231
- }
2232
- const expectNoNonce = Symbol();
2233
- const skipAuthTimeCheck = Symbol();
2234
- async function processAuthorizationCodeResponse(as, client, response, options) {
2235
- if (typeof options?.expectedNonce === "string" || typeof options?.maxAge === "number" || options?.requireIdToken) return processAuthorizationCodeOpenIDResponse(as, client, response, options.expectedNonce, options.maxAge, options[jweDecrypt], options.recognizedTokenTypes);
2236
- return processAuthorizationCodeOAuth2Response(as, client, response, options?.[jweDecrypt], options?.recognizedTokenTypes);
2237
- }
2238
- async function processAuthorizationCodeOpenIDResponse(as, client, response, expectedNonce, maxAge, decryptFn, recognizedTokenTypes) {
2239
- const additionalRequiredClaims = [];
2240
- switch (expectedNonce) {
2241
- case void 0:
2242
- expectedNonce = expectNoNonce;
2243
- break;
2244
- case expectNoNonce: break;
2245
- default:
2246
- assertString$1(expectedNonce, "\"expectedNonce\" argument");
2247
- additionalRequiredClaims.push("nonce");
2248
- }
2249
- maxAge ??= client.default_max_age;
2250
- switch (maxAge) {
2251
- case void 0:
2252
- maxAge = skipAuthTimeCheck;
2253
- break;
2254
- case skipAuthTimeCheck: break;
2255
- default:
2256
- assertNumber(maxAge, true, "\"maxAge\" argument");
2257
- additionalRequiredClaims.push("auth_time");
2258
- }
2259
- const result = await processGenericAccessTokenResponse(as, client, response, additionalRequiredClaims, decryptFn, recognizedTokenTypes);
2260
- assertString$1(result.id_token, "\"response\" body \"id_token\" property", INVALID_RESPONSE, { body: result });
2261
- const claims = getValidatedIdTokenClaims(result);
2262
- if (maxAge !== skipAuthTimeCheck) {
2263
- const now = epochTime() + getClockSkew(client);
2264
- const tolerance = getClockTolerance(client);
2265
- if (claims.auth_time + maxAge < now - tolerance) throw OPE("too much time has elapsed since the last End-User authentication", JWT_TIMESTAMP_CHECK, {
2266
- claims,
2267
- now,
2268
- tolerance,
2269
- claim: "auth_time"
2270
- });
2271
- }
2272
- if (expectedNonce === expectNoNonce) {
2273
- if (claims.nonce !== void 0) throw OPE("unexpected ID Token \"nonce\" claim value", JWT_CLAIM_COMPARISON, {
2274
- expected: void 0,
2275
- claims,
2276
- claim: "nonce"
2277
- });
2278
- } else if (claims.nonce !== expectedNonce) throw OPE("unexpected ID Token \"nonce\" claim value", JWT_CLAIM_COMPARISON, {
2279
- expected: expectedNonce,
2280
- claims,
2281
- claim: "nonce"
2282
- });
2283
- return result;
2284
- }
2285
- async function processAuthorizationCodeOAuth2Response(as, client, response, decryptFn, recognizedTokenTypes) {
2286
- const result = await processGenericAccessTokenResponse(as, client, response, void 0, decryptFn, recognizedTokenTypes);
2287
- const claims = getValidatedIdTokenClaims(result);
2288
- if (claims) {
2289
- if (client.default_max_age !== void 0) {
2290
- assertNumber(client.default_max_age, true, "\"client.default_max_age\"");
2291
- const now = epochTime() + getClockSkew(client);
2292
- const tolerance = getClockTolerance(client);
2293
- if (claims.auth_time + client.default_max_age < now - tolerance) throw OPE("too much time has elapsed since the last End-User authentication", JWT_TIMESTAMP_CHECK, {
2294
- claims,
2295
- now,
2296
- tolerance,
2297
- claim: "auth_time"
2298
- });
2299
- }
2300
- if (claims.nonce !== void 0) throw OPE("unexpected ID Token \"nonce\" claim value", JWT_CLAIM_COMPARISON, {
2301
- expected: void 0,
2302
- claims,
2303
- claim: "nonce"
2304
- });
2305
- }
2306
- return result;
2307
- }
2308
- const WWW_AUTHENTICATE_CHALLENGE = "OAUTH_WWW_AUTHENTICATE_CHALLENGE";
2309
- const RESPONSE_BODY_ERROR = "OAUTH_RESPONSE_BODY_ERROR";
2310
- const UNSUPPORTED_OPERATION = "OAUTH_UNSUPPORTED_OPERATION";
2311
- const AUTHORIZATION_RESPONSE_ERROR = "OAUTH_AUTHORIZATION_RESPONSE_ERROR";
2312
- const PARSE_ERROR = "OAUTH_PARSE_ERROR";
2313
- const INVALID_RESPONSE = "OAUTH_INVALID_RESPONSE";
2314
- const RESPONSE_IS_NOT_JSON = "OAUTH_RESPONSE_IS_NOT_JSON";
2315
- const RESPONSE_IS_NOT_CONFORM = "OAUTH_RESPONSE_IS_NOT_CONFORM";
2316
- const HTTP_REQUEST_FORBIDDEN = "OAUTH_HTTP_REQUEST_FORBIDDEN";
2317
- const REQUEST_PROTOCOL_FORBIDDEN = "OAUTH_REQUEST_PROTOCOL_FORBIDDEN";
2318
- const JWT_TIMESTAMP_CHECK = "OAUTH_JWT_TIMESTAMP_CHECK_FAILED";
2319
- const JWT_CLAIM_COMPARISON = "OAUTH_JWT_CLAIM_COMPARISON_FAILED";
2320
- const JSON_ATTRIBUTE_COMPARISON = "OAUTH_JSON_ATTRIBUTE_COMPARISON_FAILED";
2321
- const MISSING_SERVER_METADATA = "OAUTH_MISSING_SERVER_METADATA";
2322
- const INVALID_SERVER_METADATA = "OAUTH_INVALID_SERVER_METADATA";
2323
- function assertReadableResponse(response) {
2324
- if (response.bodyUsed) throw CodedTypeError$1("\"response\" body has been used already", ERR_INVALID_ARG_VALUE$1);
2325
- }
2326
- async function validateJwt(jws, checkAlg, clockSkew$2, clockTolerance$2, decryptJwt) {
2327
- let { 0: protectedHeader, 1: payload, length } = jws.split(".");
2328
- if (length === 5) if (decryptJwt !== void 0) {
2329
- jws = await decryptJwt(jws);
2330
- ({0: protectedHeader, 1: payload, length} = jws.split("."));
2331
- } else throw new UnsupportedOperationError("JWE decryption is not configured", { cause: jws });
2332
- if (length !== 3) throw OPE("Invalid JWT", INVALID_RESPONSE, jws);
2333
- let header;
2334
- try {
2335
- header = JSON.parse(buf(b64u(protectedHeader)));
2336
- } catch (cause) {
2337
- throw OPE("failed to parse JWT Header body as base64url encoded JSON", PARSE_ERROR, cause);
2338
- }
2339
- if (!isJsonObject(header)) throw OPE("JWT Header must be a top level object", INVALID_RESPONSE, jws);
2340
- checkAlg(header);
2341
- if (header.crit !== void 0) throw new UnsupportedOperationError("no JWT \"crit\" header parameter extensions are supported", { cause: { header } });
2342
- let claims;
2343
- try {
2344
- claims = JSON.parse(buf(b64u(payload)));
2345
- } catch (cause) {
2346
- throw OPE("failed to parse JWT Payload body as base64url encoded JSON", PARSE_ERROR, cause);
2347
- }
2348
- if (!isJsonObject(claims)) throw OPE("JWT Payload must be a top level object", INVALID_RESPONSE, jws);
2349
- const now = epochTime() + clockSkew$2;
2350
- if (claims.exp !== void 0) {
2351
- if (typeof claims.exp !== "number") throw OPE("unexpected JWT \"exp\" (expiration time) claim type", INVALID_RESPONSE, { claims });
2352
- if (claims.exp <= now - clockTolerance$2) throw OPE("unexpected JWT \"exp\" (expiration time) claim value, expiration is past current timestamp", JWT_TIMESTAMP_CHECK, {
2353
- claims,
2354
- now,
2355
- tolerance: clockTolerance$2,
2356
- claim: "exp"
2357
- });
2358
- }
2359
- if (claims.iat !== void 0) {
2360
- if (typeof claims.iat !== "number") throw OPE("unexpected JWT \"iat\" (issued at) claim type", INVALID_RESPONSE, { claims });
2361
- }
2362
- if (claims.iss !== void 0) {
2363
- if (typeof claims.iss !== "string") throw OPE("unexpected JWT \"iss\" (issuer) claim type", INVALID_RESPONSE, { claims });
2364
- }
2365
- if (claims.nbf !== void 0) {
2366
- if (typeof claims.nbf !== "number") throw OPE("unexpected JWT \"nbf\" (not before) claim type", INVALID_RESPONSE, { claims });
2367
- if (claims.nbf > now + clockTolerance$2) throw OPE("unexpected JWT \"nbf\" (not before) claim value", JWT_TIMESTAMP_CHECK, {
2368
- claims,
2369
- now,
2370
- tolerance: clockTolerance$2,
2371
- claim: "nbf"
2372
- });
2373
- }
2374
- if (claims.aud !== void 0) {
2375
- if (typeof claims.aud !== "string" && !Array.isArray(claims.aud)) throw OPE("unexpected JWT \"aud\" (audience) claim type", INVALID_RESPONSE, { claims });
2376
- }
2377
- return {
2378
- header,
2379
- claims,
2380
- jwt: jws
2381
- };
2382
- }
2383
- async function consumeStream(request) {
2384
- if (request.bodyUsed) throw CodedTypeError$1("form_post Request instances must contain a readable body", ERR_INVALID_ARG_VALUE$1, { cause: request });
2385
- return request.text();
2386
- }
2387
- async function formPostResponse(request) {
2388
- if (request.method !== "POST") throw CodedTypeError$1("form_post responses are expected to use the POST method", ERR_INVALID_ARG_VALUE$1, { cause: request });
2389
- if (getContentType(request) !== "application/x-www-form-urlencoded") throw CodedTypeError$1("form_post responses are expected to use the application/x-www-form-urlencoded content-type", ERR_INVALID_ARG_VALUE$1, { cause: request });
2390
- return consumeStream(request);
2391
- }
2392
- function checkSigningAlgorithm(client, issuer, fallback, header) {
2393
- if (client !== void 0) {
2394
- if (typeof client === "string" ? header.alg !== client : !client.includes(header.alg)) throw OPE("unexpected JWT \"alg\" header parameter", INVALID_RESPONSE, {
2395
- header,
2396
- expected: client,
2397
- reason: "client configuration"
2398
- });
2399
- return;
2400
- }
2401
- if (Array.isArray(issuer)) {
2402
- if (!issuer.includes(header.alg)) throw OPE("unexpected JWT \"alg\" header parameter", INVALID_RESPONSE, {
2403
- header,
2404
- expected: issuer,
2405
- reason: "authorization server metadata"
2406
- });
2407
- return;
2408
- }
2409
- if (fallback !== void 0) {
2410
- if (typeof fallback === "string" ? header.alg !== fallback : typeof fallback === "function" ? !fallback(header.alg) : !fallback.includes(header.alg)) throw OPE("unexpected JWT \"alg\" header parameter", INVALID_RESPONSE, {
2411
- header,
2412
- expected: fallback,
2413
- reason: "default value"
2414
- });
2415
- return;
2416
- }
2417
- throw OPE("missing client or server configuration to verify used JWT \"alg\" header parameter", void 0, {
2418
- client,
2419
- issuer,
2420
- fallback
2421
- });
2422
- }
2423
- function getURLSearchParameter(parameters, name) {
2424
- const { 0: value, length } = parameters.getAll(name);
2425
- if (length > 1) throw OPE(`"${name}" parameter must be provided only once`, INVALID_RESPONSE);
2426
- return value;
2427
- }
2428
- const skipStateCheck$1 = Symbol();
2429
- const expectNoState = Symbol();
2430
- function validateAuthResponse(as, client, parameters, expectedState) {
2431
- assertAs(as);
2432
- assertClient(client);
2433
- if (parameters instanceof URL) parameters = parameters.searchParams;
2434
- if (!(parameters instanceof URLSearchParams)) throw CodedTypeError$1("\"parameters\" must be an instance of URLSearchParams, or URL", ERR_INVALID_ARG_TYPE$1);
2435
- if (getURLSearchParameter(parameters, "response")) throw OPE("\"parameters\" contains a JARM response, use validateJwtAuthResponse() instead of validateAuthResponse()", INVALID_RESPONSE, { parameters });
2436
- const iss = getURLSearchParameter(parameters, "iss");
2437
- const state = getURLSearchParameter(parameters, "state");
2438
- if (!iss && as.authorization_response_iss_parameter_supported) throw OPE("response parameter \"iss\" (issuer) missing", INVALID_RESPONSE, { parameters });
2439
- if (iss && iss !== as.issuer) throw OPE("unexpected \"iss\" (issuer) response parameter value", INVALID_RESPONSE, {
2440
- expected: as.issuer,
2441
- parameters
2442
- });
2443
- switch (expectedState) {
2444
- case void 0:
2445
- case expectNoState:
2446
- if (state !== void 0) throw OPE("unexpected \"state\" response parameter encountered", INVALID_RESPONSE, {
2447
- expected: void 0,
2448
- parameters
2449
- });
2450
- break;
2451
- case skipStateCheck$1: break;
2452
- default:
2453
- assertString$1(expectedState, "\"expectedState\" argument");
2454
- if (state !== expectedState) throw OPE(state === void 0 ? "response parameter \"state\" missing" : "unexpected \"state\" response parameter value", INVALID_RESPONSE, {
2455
- expected: expectedState,
2456
- parameters
2457
- });
2458
- }
2459
- if (getURLSearchParameter(parameters, "error")) throw new AuthorizationResponseError("authorization response from the server is an error", { cause: parameters });
2460
- const id_token = getURLSearchParameter(parameters, "id_token");
2461
- const token = getURLSearchParameter(parameters, "token");
2462
- if (id_token !== void 0 || token !== void 0) throw new UnsupportedOperationError("implicit and hybrid flows are not supported");
2463
- return brand(new URLSearchParams(parameters));
2464
- }
2465
- async function getResponseJsonBody(response, check = assertApplicationJson) {
2466
- let json;
2467
- try {
2468
- json = await response.json();
2469
- } catch (cause) {
2470
- check(response);
2471
- throw OPE("failed to parse \"response\" body as JSON", PARSE_ERROR, cause);
2472
- }
2473
- if (!isJsonObject(json)) throw OPE("\"response\" body must be a top level object", INVALID_RESPONSE, { body: json });
2474
- return json;
2475
- }
2476
- const _nodiscoverycheck = Symbol();
2477
- const _expectedIssuer = Symbol();
2478
-
2479
- //#endregion
2480
- //#region ../../node_modules/openid-client/build/index.js
2481
- let headers;
2482
- let USER_AGENT;
2483
- if (typeof navigator === "undefined" || !navigator.userAgent?.startsWith?.("Mozilla/5.0 ")) {
2484
- USER_AGENT = `openid-client/v6.8.1`;
2485
- headers = { "user-agent": USER_AGENT };
2486
- }
2487
- const int = (config) => {
2488
- return props.get(config);
2489
- };
2490
- let props;
2491
- let tbi;
2492
- function ClientSecretPost(clientSecret) {
2493
- if (clientSecret !== void 0) return ClientSecretPost$1(clientSecret);
2494
- tbi ||= /* @__PURE__ */ new WeakMap();
2495
- return (as, client, body, headers$1) => {
2496
- let auth;
2497
- if (!(auth = tbi.get(client))) {
2498
- assertString(client.client_secret, "\"metadata.client_secret\"");
2499
- auth = ClientSecretPost$1(client.client_secret);
2500
- tbi.set(client, auth);
2501
- }
2502
- return auth(as, client, body, headers$1);
2503
- };
2504
- }
2505
- function assertString(input, it) {
2506
- if (typeof input !== "string") throw CodedTypeError(`${it} must be a string`, ERR_INVALID_ARG_TYPE);
2507
- if (input.length === 0) throw CodedTypeError(`${it} must not be empty`, ERR_INVALID_ARG_VALUE);
2508
- }
2509
- function None() {
2510
- return None$1();
2511
- }
2512
- const skipStateCheck = skipStateCheck$1;
2513
- const skipSubjectCheck = skipSubjectCheck$1;
2514
- const customFetch = customFetch$1;
2515
- const modifyAssertion = modifyAssertion$1;
2516
- const clockSkew = clockSkew$1;
2517
- const clockTolerance = clockTolerance$1;
2518
- const ERR_INVALID_ARG_VALUE = "ERR_INVALID_ARG_VALUE";
2519
- const ERR_INVALID_ARG_TYPE = "ERR_INVALID_ARG_TYPE";
2520
- function CodedTypeError(message, code, cause) {
2521
- const err = new TypeError(message, { cause });
2522
- Object.assign(err, { code });
2523
- return err;
2524
- }
2525
- function calculatePKCECodeChallenge(codeVerifier) {
2526
- return calculatePKCECodeChallenge$1(codeVerifier);
2527
- }
2528
- function randomPKCECodeVerifier() {
2529
- return generateRandomCodeVerifier();
2530
- }
2531
- function randomState() {
2532
- return generateRandomState();
2533
- }
2534
- var ClientError = class extends Error {
2535
- code;
2536
- constructor(message, options) {
2537
- super(message, options);
2538
- this.name = this.constructor.name;
2539
- this.code = options?.code;
2540
- Error.captureStackTrace?.(this, this.constructor);
2541
- }
2542
- };
2543
- const decoder = new TextDecoder();
2544
- function e(msg, cause, code) {
2545
- return new ClientError(msg, {
2546
- cause,
2547
- code
2548
- });
2549
- }
2550
- function errorHandler(err) {
2551
- if (err instanceof TypeError || err instanceof ClientError || err instanceof ResponseBodyError || err instanceof AuthorizationResponseError || err instanceof WWWAuthenticateChallengeError) throw err;
2552
- if (err instanceof OperationProcessingError) switch (err.code) {
2553
- case HTTP_REQUEST_FORBIDDEN: throw e("only requests to HTTPS are allowed", err, err.code);
2554
- case REQUEST_PROTOCOL_FORBIDDEN: throw e("only requests to HTTP or HTTPS are allowed", err, err.code);
2555
- case RESPONSE_IS_NOT_CONFORM: throw e("unexpected HTTP response status code", err.cause, err.code);
2556
- case RESPONSE_IS_NOT_JSON: throw e("unexpected response content-type", err.cause, err.code);
2557
- case PARSE_ERROR: throw e("parsing error occured", err, err.code);
2558
- case INVALID_RESPONSE: throw e("invalid response encountered", err, err.code);
2559
- case JWT_CLAIM_COMPARISON: throw e("unexpected JWT claim value encountered", err, err.code);
2560
- case JSON_ATTRIBUTE_COMPARISON: throw e("unexpected JSON attribute value encountered", err, err.code);
2561
- case JWT_TIMESTAMP_CHECK: throw e("JWT timestamp claim value failed validation", err, err.code);
2562
- default: throw e(err.message, err, err.code);
2563
- }
2564
- if (err instanceof UnsupportedOperationError) throw e("unsupported operation", err, err.code);
2565
- if (err instanceof DOMException) switch (err.name) {
2566
- case "OperationError": throw e("runtime operation error", err, UNSUPPORTED_OPERATION);
2567
- case "NotSupportedError": throw e("runtime unsupported operation", err, UNSUPPORTED_OPERATION);
2568
- case "TimeoutError": throw e("operation timed out", err, "OAUTH_TIMEOUT");
2569
- case "AbortError": throw e("operation aborted", err, "OAUTH_ABORT");
2570
- }
2571
- throw new ClientError("something went wrong", { cause: err });
2572
- }
2573
- function handleEntraId(server, as, options) {
2574
- if (server.origin === "https://login.microsoftonline.com" && (!options?.algorithm || options.algorithm === "oidc")) {
2575
- as[kEntraId] = true;
2576
- return true;
2577
- }
2578
- return false;
2579
- }
2580
- function handleB2Clogin(server, options) {
2581
- if (server.hostname.endsWith(".b2clogin.com") && (!options?.algorithm || options.algorithm === "oidc")) return true;
2582
- return false;
2583
- }
2584
- async function discovery(server, clientId, metadata, clientAuthentication, options) {
2585
- const instance = new Configuration(await performDiscovery(server, options), clientId, metadata, clientAuthentication);
2586
- let internals = int(instance);
2587
- if (options?.[customFetch]) internals.fetch = options[customFetch];
2588
- if (options?.timeout) internals.timeout = options.timeout;
2589
- if (options?.execute) for (const extension of options.execute) extension(instance);
2590
- return instance;
2591
- }
2592
- async function performDiscovery(server, options) {
2593
- if (!(server instanceof URL)) throw CodedTypeError("\"server\" must be an instance of URL", ERR_INVALID_ARG_TYPE);
2594
- const resolve = !server.href.includes("/.well-known/");
2595
- const timeout = options?.timeout ?? 30;
2596
- const signal$2 = AbortSignal.timeout(timeout * 1e3);
2597
- const as = await (resolve ? discoveryRequest(server, {
2598
- algorithm: options?.algorithm,
2599
- [customFetch$1]: options?.[customFetch],
2600
- [allowInsecureRequests$1]: options?.execute?.includes(allowInsecureRequests),
2601
- signal: signal$2,
2602
- headers: new Headers(headers)
2603
- }) : (options?.[customFetch] || fetch)((() => {
2604
- checkProtocol(server, options?.execute?.includes(allowInsecureRequests) ? false : true);
2605
- return server.href;
2606
- })(), {
2607
- headers: Object.fromEntries(new Headers({
2608
- accept: "application/json",
2609
- ...headers
2610
- }).entries()),
2611
- body: void 0,
2612
- method: "GET",
2613
- redirect: "manual",
2614
- signal: signal$2
2615
- })).then((response) => processDiscoveryResponse(_nodiscoverycheck, response)).catch(errorHandler);
2616
- if (resolve && new URL(as.issuer).href !== server.href) handleEntraId(server, as, options) || handleB2Clogin(server, options) || (() => {
2617
- throw new ClientError("discovered metadata issuer does not match the expected issuer", {
2618
- code: JSON_ATTRIBUTE_COMPARISON,
2619
- cause: {
2620
- expected: server.href,
2621
- body: as,
2622
- attribute: "issuer"
2623
- }
2624
- });
2625
- })();
2626
- return as;
2627
- }
2628
- function getServerHelpers(metadata) {
2629
- return { supportsPKCE: {
2630
- __proto__: null,
2631
- value(method = "S256") {
2632
- return metadata.code_challenge_methods_supported?.includes(method) === true;
2633
- }
2634
- } };
2635
- }
2636
- function addServerHelpers(metadata) {
2637
- Object.defineProperties(metadata, getServerHelpers(metadata));
2638
- }
2639
- const kEntraId = Symbol();
2640
- var Configuration = class {
2641
- constructor(server, clientId, metadata, clientAuthentication) {
2642
- if (typeof clientId !== "string" || !clientId.length) throw CodedTypeError("\"clientId\" must be a non-empty string", ERR_INVALID_ARG_TYPE);
2643
- if (typeof metadata === "string") metadata = { client_secret: metadata };
2644
- if (metadata?.client_id !== void 0 && clientId !== metadata.client_id) throw CodedTypeError("\"clientId\" and \"metadata.client_id\" must be the same", ERR_INVALID_ARG_VALUE);
2645
- const client = {
2646
- ...structuredClone(metadata),
2647
- client_id: clientId
2648
- };
2649
- client[clockSkew$1] = metadata?.[clockSkew$1] ?? 0;
2650
- client[clockTolerance$1] = metadata?.[clockTolerance$1] ?? 30;
2651
- let auth;
2652
- if (clientAuthentication) auth = clientAuthentication;
2653
- else if (typeof client.client_secret === "string" && client.client_secret.length) auth = ClientSecretPost(client.client_secret);
2654
- else auth = None();
2655
- let c = Object.freeze(client);
2656
- const clone = structuredClone(server);
2657
- if (kEntraId in server) clone[_expectedIssuer] = ({ claims: { tid } }) => server.issuer.replace("{tenantid}", tid);
2658
- let as = Object.freeze(clone);
2659
- props ||= /* @__PURE__ */ new WeakMap();
2660
- props.set(this, {
2661
- __proto__: null,
2662
- as,
2663
- c,
2664
- auth,
2665
- tlsOnly: true,
2666
- jwksCache: {}
2667
- });
2668
- }
2669
- serverMetadata() {
2670
- const metadata = structuredClone(int(this).as);
2671
- addServerHelpers(metadata);
2672
- return metadata;
2673
- }
2674
- clientMetadata() {
2675
- return structuredClone(int(this).c);
2676
- }
2677
- get timeout() {
2678
- return int(this).timeout;
2679
- }
2680
- set timeout(value) {
2681
- int(this).timeout = value;
2682
- }
2683
- get [customFetch]() {
2684
- return int(this).fetch;
2685
- }
2686
- set [customFetch](value) {
2687
- int(this).fetch = value;
2688
- }
2689
- };
2690
- Object.freeze(Configuration.prototype);
2691
- function getHelpers(response) {
2692
- let exp = void 0;
2693
- if (response.expires_in !== void 0) {
2694
- const now = /* @__PURE__ */ new Date();
2695
- now.setSeconds(now.getSeconds() + response.expires_in);
2696
- exp = now.getTime();
2697
- }
2698
- return {
2699
- expiresIn: {
2700
- __proto__: null,
2701
- value() {
2702
- if (exp) {
2703
- const now = Date.now();
2704
- if (exp > now) return Math.floor((exp - now) / 1e3);
2705
- return 0;
2706
- }
2707
- }
2708
- },
2709
- claims: {
2710
- __proto__: null,
2711
- value() {
2712
- try {
2713
- return getValidatedIdTokenClaims(this);
2714
- } catch {
2715
- return;
2716
- }
2717
- }
2718
- }
2719
- };
2720
- }
2721
- function addHelpers(response) {
2722
- Object.defineProperties(response, getHelpers(response));
2723
- }
2724
- function allowInsecureRequests(config) {
2725
- int(config).tlsOnly = false;
2726
- }
2727
- function stripParams(url) {
2728
- url = new URL(url);
2729
- url.search = "";
2730
- url.hash = "";
2731
- return url.href;
2732
- }
2733
- function webInstanceOf(input, toStringTag) {
2734
- try {
2735
- return Object.getPrototypeOf(input)[Symbol.toStringTag] === toStringTag;
2736
- } catch {
2737
- return false;
2738
- }
2739
- }
2740
- async function authorizationCodeGrant(config, currentUrl, checks, tokenEndpointParameters, options) {
2741
- checkConfig(config);
2742
- if (options?.flag !== retry && !(currentUrl instanceof URL) && !webInstanceOf(currentUrl, "Request")) throw CodedTypeError("\"currentUrl\" must be an instance of URL, or Request", ERR_INVALID_ARG_TYPE);
2743
- let authResponse;
2744
- let redirectUri;
2745
- const { as, c, auth, fetch: fetch$1, tlsOnly, jarm, hybrid, nonRepudiation, timeout, decrypt, implicit } = int(config);
2746
- if (options?.flag === retry) {
2747
- authResponse = options.authResponse;
2748
- redirectUri = options.redirectUri;
2749
- } else {
2750
- if (!(currentUrl instanceof URL)) {
2751
- const request = currentUrl;
2752
- currentUrl = new URL(currentUrl.url);
2753
- switch (request.method) {
2754
- case "GET": break;
2755
- case "POST":
2756
- const params = new URLSearchParams(await formPostResponse(request));
2757
- if (hybrid) currentUrl.hash = params.toString();
2758
- else for (const [k, v] of params.entries()) currentUrl.searchParams.append(k, v);
2759
- break;
2760
- default: throw CodedTypeError("unexpected Request HTTP method", ERR_INVALID_ARG_VALUE);
2761
- }
2762
- }
2763
- redirectUri = stripParams(currentUrl);
2764
- switch (true) {
2765
- case !!jarm:
2766
- authResponse = await jarm(currentUrl, checks?.expectedState);
2767
- break;
2768
- case !!hybrid:
2769
- authResponse = await hybrid(currentUrl, checks?.expectedNonce, checks?.expectedState, checks?.maxAge);
2770
- break;
2771
- case !!implicit: throw new TypeError("authorizationCodeGrant() cannot be used by response_type=id_token clients");
2772
- default: try {
2773
- authResponse = validateAuthResponse(as, c, currentUrl.searchParams, checks?.expectedState);
2774
- } catch (err) {
2775
- errorHandler(err);
1646
+ //#region src/auth/providers/ReactAuthProvider.ts
1647
+ var ReactAuthProvider = class {
1648
+ alepha = $inject(Alepha);
1649
+ onRender = $hook({
1650
+ on: "react:server:render:begin",
1651
+ handler: async ({ request, state }) => {
1652
+ if (request?.user) {
1653
+ const { token, realm, ...user } = request.user;
1654
+ this.alepha.state.set("alepha.server.request.user", user);
1655
+ state.user = user;
2776
1656
  }
2777
1657
  }
2778
- }
2779
- const response = await authorizationCodeGrantRequest(as, c, auth, authResponse, redirectUri, checks?.pkceCodeVerifier || nopkce, {
2780
- additionalParameters: tokenEndpointParameters,
2781
- [customFetch$1]: fetch$1,
2782
- [allowInsecureRequests$1]: !tlsOnly,
2783
- DPoP: options?.DPoP,
2784
- headers: new Headers(headers),
2785
- signal: signal(timeout)
2786
- }).catch(errorHandler);
2787
- if (typeof checks?.expectedNonce === "string" || typeof checks?.maxAge === "number") checks.idTokenExpected = true;
2788
- const p = processAuthorizationCodeResponse(as, c, response, {
2789
- expectedNonce: checks?.expectedNonce,
2790
- maxAge: checks?.maxAge,
2791
- requireIdToken: checks?.idTokenExpected,
2792
- [jweDecrypt]: decrypt
2793
1658
  });
2794
- let result;
2795
- try {
2796
- result = await p;
2797
- } catch (err) {
2798
- if (retryable(err, options)) return authorizationCodeGrant(config, void 0, checks, tokenEndpointParameters, {
2799
- ...options,
2800
- flag: retry,
2801
- authResponse,
2802
- redirectUri
2803
- });
2804
- errorHandler(err);
2805
- }
2806
- result.id_token && await nonRepudiation?.(response);
2807
- addHelpers(result);
2808
- return result;
2809
- }
2810
- async function refreshTokenGrant(config, refreshToken, parameters, options) {
2811
- checkConfig(config);
2812
- parameters = new URLSearchParams(parameters);
2813
- const { as, c, auth, fetch: fetch$1, tlsOnly, nonRepudiation, timeout, decrypt } = int(config);
2814
- const response = await refreshTokenGrantRequest(as, c, auth, refreshToken, {
2815
- [customFetch$1]: fetch$1,
2816
- [allowInsecureRequests$1]: !tlsOnly,
2817
- additionalParameters: parameters,
2818
- DPoP: options?.DPoP,
2819
- headers: new Headers(headers),
2820
- signal: signal(timeout)
2821
- }).catch(errorHandler);
2822
- const p = processRefreshTokenResponse(as, c, response, { [jweDecrypt]: decrypt });
2823
- let result;
2824
- try {
2825
- result = await p;
2826
- } catch (err) {
2827
- if (retryable(err, options)) return refreshTokenGrant(config, refreshToken, parameters, {
2828
- ...options,
2829
- flag: retry
2830
- });
2831
- errorHandler(err);
2832
- }
2833
- result.id_token && await nonRepudiation?.(response);
2834
- addHelpers(result);
2835
- return result;
2836
- }
2837
- function buildAuthorizationUrl(config, parameters) {
2838
- checkConfig(config);
2839
- const { as, c, tlsOnly, hybrid, jarm, implicit } = int(config);
2840
- const authorizationEndpoint = resolveEndpoint(as, "authorization_endpoint", false, tlsOnly);
2841
- parameters = new URLSearchParams(parameters);
2842
- if (!parameters.has("client_id")) parameters.set("client_id", c.client_id);
2843
- if (!parameters.has("request_uri") && !parameters.has("request")) {
2844
- if (!parameters.has("response_type")) parameters.set("response_type", hybrid ? "code id_token" : implicit ? "id_token" : "code");
2845
- if (implicit && !parameters.has("nonce")) throw CodedTypeError("response_type=id_token clients must provide a nonce parameter in their authorization request parameters", ERR_INVALID_ARG_VALUE);
2846
- if (jarm) parameters.set("response_mode", "jwt");
2847
- }
2848
- for (const [k, v] of parameters.entries()) authorizationEndpoint.searchParams.append(k, v);
2849
- return authorizationEndpoint;
2850
- }
2851
- function buildEndSessionUrl(config, parameters) {
2852
- checkConfig(config);
2853
- const { as, c, tlsOnly } = int(config);
2854
- const endSessionEndpoint = resolveEndpoint(as, "end_session_endpoint", false, tlsOnly);
2855
- parameters = new URLSearchParams(parameters);
2856
- if (!parameters.has("client_id")) parameters.set("client_id", c.client_id);
2857
- for (const [k, v] of parameters.entries()) endSessionEndpoint.searchParams.append(k, v);
2858
- return endSessionEndpoint;
2859
- }
2860
- function checkConfig(input) {
2861
- if (!(input instanceof Configuration)) throw CodedTypeError("\"config\" must be an instance of Configuration", ERR_INVALID_ARG_TYPE);
2862
- if (Object.getPrototypeOf(input) !== Configuration.prototype) throw CodedTypeError("subclassing Configuration is not allowed", ERR_INVALID_ARG_VALUE);
2863
- }
2864
- function signal(timeout) {
2865
- return timeout ? AbortSignal.timeout(timeout * 1e3) : void 0;
2866
- }
2867
- function retryable(err, options) {
2868
- if (options?.DPoP && options.flag !== retry) return isDPoPNonceError(err);
2869
- return false;
2870
- }
2871
- const retry = Symbol();
2872
-
2873
- //#endregion
2874
- //#region src/auth/descriptors/$auth.ts
2875
- /**
2876
- * Creates an authentication provider descriptor for handling user login flows.
2877
- *
2878
- * Supports multiple authentication strategies: credentials (username/password), OAuth2,
2879
- * and OIDC (OpenID Connect). Handles token management, user profile retrieval, and
2880
- * integration with both external identity providers (Auth0, Keycloak) and internal realms.
2881
- *
2882
- * **Authentication Types**: Credentials, OAuth2 (Google, GitHub), OIDC, External providers
2883
- *
2884
- * @example
2885
- * ```ts
2886
- * class AuthProviders {
2887
- * // Internal credentials-based auth
2888
- * credentials = $auth({
2889
- * realm: this.userRealm,
2890
- * credentials: {
2891
- * account: async ({ username, password }) => {
2892
- * return await this.validateUser(username, password);
2893
- * }
2894
- * }
2895
- * });
2896
- *
2897
- * // External OIDC provider
2898
- * keycloak = $auth({
2899
- * oidc: {
2900
- * issuer: "https://auth.example.com",
2901
- * clientId: "my-app",
2902
- * clientSecret: "secret",
2903
- * redirectUri: "/auth/callback"
2904
- * }
2905
- * });
2906
- * }
2907
- * ```
2908
- */
2909
- const $auth = (options) => {
2910
- return createDescriptor(AuthDescriptor, options);
2911
1659
  };
2912
- var AuthDescriptor = class extends Descriptor {
2913
- securityProvider = $inject(SecurityProvider);
2914
- dateTimeProvider = $inject(DateTimeProvider);
2915
- oauth;
2916
- get name() {
2917
- return this.options.name ?? this.config.propertyKey;
2918
- }
2919
- get jwks_uri() {
2920
- const jwks = this.oauth?.serverMetadata().jwks_uri;
2921
- if (!jwks) throw new AlephaError("No JWKS URI available for the auth provider");
2922
- return jwks;
2923
- }
2924
- get scope() {
2925
- if ("oauth" in this.options) return this.options.oauth.scope;
2926
- if ("oidc" in this.options) return this.options.oidc.scope || "openid profile email";
2927
- throw new AlephaError("No OAuth2 or OIDC configuration available for the auth provider");
2928
- }
2929
- get redirect_uri() {
2930
- if ("oauth" in this.options) return this.options.oauth.redirectUri;
2931
- if ("oidc" in this.options) return this.options.oidc.redirectUri;
2932
- throw new AlephaError("No OAuth2 or OIDC configuration available for the auth provider");
2933
- }
2934
- /**
2935
- * Refreshes the access token using the refresh token.
2936
- * Can be used on oauth2, oidc or credentials auth providers.
2937
- */
2938
- async refresh(refreshToken, accessToken) {
2939
- if ("realm" in this.options) return this.options.realm.refreshToken(refreshToken, accessToken).then((it) => it.tokens).catch((error) => {
2940
- throw new SecurityError("Failed to refresh access token using the refresh token (realm)", { cause: error });
2941
- });
2942
- else if (this.oauth) try {
2943
- return {
2944
- ...await refreshTokenGrant(this.oauth, refreshToken),
2945
- issued_at: this.dateTimeProvider.now().unix()
2946
- };
2947
- } catch (error) {
2948
- throw new SecurityError("Failed to refresh access token using the refresh token (oauth2)", { cause: error });
2949
- }
2950
- throw new AlephaError("No realm or OAuth2 configuration available for refreshing the access token");
2951
- }
2952
- /**
2953
- * Extracts user information from the access token.
2954
- * This is used to create a user account from the access token.
2955
- */
2956
- async user(tokens) {
2957
- try {
2958
- if ("oauth" in this.options) {
2959
- const profile = await this.options.oauth.userinfo(tokens);
2960
- if (this.options.oauth.account) return this.options.oauth.account({
2961
- ...tokens,
2962
- user: profile
2963
- });
2964
- return this.securityProvider.createUserFromPayload(profile);
2965
- }
2966
- if ("oidc" in this.options) {
2967
- const payload = this.getUserFromIdToken(tokens.id_token || "");
2968
- if (this.options.oidc.account) return this.options.oidc.account({
2969
- ...tokens,
2970
- user: payload
2971
- });
2972
- return this.securityProvider.createUserFromPayload(payload);
2973
- }
2974
- } catch (error) {
2975
- throw new SecurityError("Failed to extract user from identity provider tokens", { cause: error });
2976
- }
2977
- throw new AlephaError("This authentication does not support user extraction from tokens");
2978
- }
2979
- getUserFromIdToken(idToken) {
2980
- try {
2981
- return JSON.parse(Buffer.from(idToken.split(".")[1], "base64").toString("utf8"));
2982
- } catch (error) {
2983
- throw new AlephaError("Failed to parse ID Token payload", { cause: error });
2984
- }
2985
- }
2986
- async prepare() {
2987
- const addons = [];
2988
- addons.push(allowInsecureRequests);
2989
- if ("oidc" in this.options) {
2990
- const { oidc } = this.options;
2991
- this.oauth = await discovery(new URL(oidc.issuer), oidc.clientId, { client_secret: oidc.clientSecret }, void 0, { execute: addons });
2992
- }
2993
- if ("oauth" in this.options) {
2994
- const { oauth } = this.options;
2995
- this.oauth = new Configuration({
2996
- authorization_endpoint: oauth.authorization,
2997
- token_endpoint: oauth.token,
2998
- issuer: oauth.authorization,
2999
- jwks_uri: void 0,
3000
- end_session_endpoint: void 0
3001
- }, oauth.clientId, { client_secret: oauth.clientSecret });
3002
- }
3003
- }
3004
- };
3005
- $auth[KIND] = AuthDescriptor;
3006
-
3007
- //#endregion
3008
- //#region src/auth/schemas/tokensSchema.ts
3009
- const tokensSchema = t.object({
3010
- provider: t.text(),
3011
- access_token: t.text({ size: "rich" }),
3012
- issued_at: t.number(),
3013
- expires_in: t.optional(t.number()),
3014
- refresh_token: t.optional(t.text({ size: "rich" })),
3015
- refresh_token_expires_in: t.optional(t.number()),
3016
- refresh_expires_in: t.optional(t.number({ description: "Alias of `refresh_token_expires_in` for compatibility with some providers." })),
3017
- id_token: t.optional(t.text({ size: "rich" })),
3018
- scope: t.optional(t.text())
3019
- });
3020
-
3021
- //#endregion
3022
- //#region src/auth/schemas/tokenResponseSchema.ts
3023
- const tokenResponseSchema = t.extend(tokensSchema, {
3024
- user: userAccountInfoSchema,
3025
- api: apiLinksResponseSchema
3026
- });
3027
-
3028
- //#endregion
3029
- //#region src/auth/schemas/userinfoResponseSchema.ts
3030
- const userinfoResponseSchema = t.object({
3031
- user: t.optional(userAccountInfoSchema),
3032
- api: apiLinksResponseSchema
3033
- });
3034
1660
 
3035
1661
  //#endregion
3036
1662
  //#region src/auth/services/ReactAuth.ts
3037
1663
  /**
3038
1664
  * Browser, SSR friendly, service to handle authentication.
3039
1665
  */
3040
- var ReactAuth = class ReactAuth {
1666
+ var ReactAuth = class {
3041
1667
  log = $logger();
3042
1668
  alepha = $inject(Alepha);
3043
1669
  httpClient = $inject(HttpClient);
3044
- static path = {
3045
- login: "/oauth/login",
3046
- callback: "/oauth/callback",
3047
- logout: "/oauth/logout",
3048
- token: "/_auth/token",
3049
- refresh: "/_auth/refresh",
3050
- userinfo: "/_auth/userinfo"
3051
- };
3052
1670
  onBeginTransition = $hook({
3053
1671
  on: "react:transition:begin",
3054
1672
  handler: async (event) => {
@@ -3070,14 +1688,14 @@ var ReactAuth = class ReactAuth {
3070
1688
  return this.alepha.state.get("alepha.server.request.user");
3071
1689
  }
3072
1690
  async ping() {
3073
- const { data } = await this.httpClient.fetch(ReactAuth.path.userinfo, { schema: { response: userinfoResponseSchema } });
1691
+ const { data } = await this.httpClient.fetch(alephaServerAuthRoutes.userinfo, { schema: { response: userinfoResponseSchema } });
3074
1692
  this.alepha.state.set("alepha.server.request.apiLinks", data.api);
3075
1693
  this.alepha.state.set("alepha.server.request.user", data.user);
3076
1694
  return data.user;
3077
1695
  }
3078
1696
  async login(provider, options) {
3079
1697
  if (options.username || options.password) {
3080
- const { data } = await this.httpClient.fetch(`${options.hostname || ""}${ReactAuth.path.token}?provider=${provider}`, {
1698
+ const { data } = await this.httpClient.fetch(`${options.hostname || ""}${alephaServerAuthRoutes.token}?provider=${provider}`, {
3081
1699
  method: "POST",
3082
1700
  body: JSON.stringify({
3083
1701
  username: options.username,
@@ -3093,483 +1711,18 @@ var ReactAuth = class ReactAuth {
3093
1711
  if (this.alepha.isBrowser()) {
3094
1712
  const browser = this.alepha.inject(ReactBrowserProvider);
3095
1713
  const redirect = options.redirect || (browser.transitioning ? window.location.origin + browser.transitioning.to : window.location.href);
3096
- const href = `${window.location.origin}${ReactAuth.path.login}?provider=${provider}&redirect_uri=${encodeURIComponent(redirect)}`;
1714
+ const href = `${window.location.origin}${alephaServerAuthRoutes.login}?provider=${provider}&redirect_uri=${encodeURIComponent(redirect)}`;
3097
1715
  if (browser.transitioning) throw new Redirection(href);
3098
1716
  else {
3099
1717
  window.location.href = href;
3100
1718
  return {};
3101
1719
  }
3102
1720
  }
3103
- throw new Redirection(`${ReactAuth.path.login}?provider=${provider}&redirect_uri=${options.redirect || "/"}`);
1721
+ throw new Redirection(`${alephaServerAuthRoutes.login}?provider=${provider}&redirect_uri=${options.redirect || "/"}`);
3104
1722
  }
3105
1723
  logout() {
3106
- window.location.href = `${ReactAuth.path.logout}?post_logout_redirect_uri=${encodeURIComponent(window.location.origin)}`;
3107
- }
3108
- };
3109
-
3110
- //#endregion
3111
- //#region src/auth/providers/ReactAuthProvider.ts
3112
- var ReactAuthProvider = class {
3113
- log = $logger();
3114
- alepha = $inject(Alepha);
3115
- serverCookiesProvider = $inject(ServerCookiesProvider);
3116
- dateTimeProvider = $inject(DateTimeProvider);
3117
- serverLinksProvider = $inject(ServerLinksProvider);
3118
- reactAuth = $inject(ReactAuth);
3119
- authorizationCode = $cookie({
3120
- name: "authorizationCode",
3121
- ttl: [15, "minutes"],
3122
- httpOnly: true,
3123
- schema: t.object({
3124
- provider: t.text(),
3125
- codeVerifier: t.optional(t.text({ size: "long" })),
3126
- redirectUri: t.optional(t.text({ size: "long" })),
3127
- state: t.optional(t.text()),
3128
- nonce: t.optional(t.text())
3129
- })
3130
- });
3131
- tokens = $cookie({
3132
- name: "tokens",
3133
- ttl: [30, "days"],
3134
- httpOnly: true,
3135
- compress: true,
3136
- encrypt: true,
3137
- schema: tokensSchema
3138
- });
3139
- onRender = $hook({
3140
- on: "react:server:render:begin",
3141
- handler: async ({ request, state }) => {
3142
- if (request?.user) {
3143
- const { token, realm, ...user } = request.user;
3144
- this.alepha.state.set("alepha.server.request.user", user);
3145
- state.user = user;
3146
- }
3147
- }
3148
- });
3149
- get identities() {
3150
- return this.alepha.descriptors($auth).filter((auth) => !auth.options.disabled);
1724
+ window.location.href = `${alephaServerAuthRoutes.logout}?post_logout_redirect_uri=${encodeURIComponent(window.location.origin)}`;
3151
1725
  }
3152
- configure = $hook({
3153
- on: "configure",
3154
- handler: async () => {
3155
- for (const identity of this.identities) await identity.prepare();
3156
- }
3157
- });
3158
- getAccessTokens(tokens) {
3159
- const idp = this.provider(tokens.provider);
3160
- if ("oidc" in idp.options && !("realm" in idp.options) && idp.options.oidc?.useIdToken) return tokens.id_token;
3161
- return tokens.access_token;
3162
- }
3163
- /**
3164
- * Fill request headers with access token from cookies or fallback to provider's fallback function.
3165
- */
3166
- onRequest = $hook({
3167
- on: "server:onRequest",
3168
- after: this.serverCookiesProvider,
3169
- handler: async ({ request }) => {
3170
- const cookies = request.cookies;
3171
- if (cookies) {
3172
- const tokens = await this.cookiesToTokens(cookies);
3173
- if (tokens) {
3174
- request.headers.authorization = `Bearer ${this.getAccessTokens(tokens)}`;
3175
- this.log.trace("Access token set in request headers", { provider: tokens.provider });
3176
- }
3177
- }
3178
- if (!request.headers.authorization) {
3179
- for (const provider of this.identities) if (!("realm" in provider.options) && !!provider.options.fallback) {
3180
- const token = await provider.options.fallback();
3181
- if (token) {
3182
- request.headers.authorization = `Bearer ${token}`;
3183
- break;
3184
- }
3185
- }
3186
- }
3187
- }
3188
- });
3189
- /**
3190
- * Convert cookies to tokens.
3191
- * If the tokens are expired, try to refresh them using the refresh token.
3192
- */
3193
- async cookiesToTokens(cookies) {
3194
- const tokens = this.tokens.get({ cookies });
3195
- if (!tokens) {
3196
- this.log.trace("No tokens found in cookies");
3197
- return;
3198
- }
3199
- this.log.trace("Tokens found in cookies", {
3200
- expires_in: tokens.expires_in,
3201
- issued_at: tokens.issued_at
3202
- });
3203
- const refreshedTokens = await this.refreshTokens(tokens);
3204
- if (!refreshedTokens) {
3205
- this.tokens.del({ cookies });
3206
- return;
3207
- }
3208
- if (refreshedTokens.access_token !== tokens.access_token) this.setTokens(refreshedTokens, cookies);
3209
- return refreshedTokens;
3210
- }
3211
- async refreshTokens(tokens) {
3212
- if (tokens.expires_in && tokens.issued_at) {
3213
- if (tokens.issued_at + (tokens.expires_in - 10) < this.dateTimeProvider.now().unix()) {
3214
- this.log.trace("Tokens are expired");
3215
- if (tokens.refresh_token) {
3216
- this.log.trace("Trying to refresh tokens using refresh token");
3217
- try {
3218
- const newTokens = {
3219
- ...await this.provider(tokens).refresh(tokens.refresh_token, tokens.access_token),
3220
- provider: tokens.provider,
3221
- issued_at: this.dateTimeProvider.now().unix()
3222
- };
3223
- this.log.debug("Tokens refreshed successfully");
3224
- return newTokens;
3225
- } catch (e$1) {
3226
- this.log.warn("Failed to refresh token", e$1);
3227
- }
3228
- }
3229
- return;
3230
- }
3231
- }
3232
- if (!tokens.issued_at && tokens.access_token) return;
3233
- return tokens;
3234
- }
3235
- /**
3236
- * Get user information.
3237
- */
3238
- userinfo = $route({
3239
- path: ReactAuth.path.userinfo,
3240
- schema: { response: userinfoResponseSchema },
3241
- handler: async ({ user, headers: headers$1, cookies }) => {
3242
- const tokens = this.tokens.get({ cookies });
3243
- if (tokens) {
3244
- const provider = this.provider(tokens);
3245
- if (!("realm" in provider.options)) {
3246
- const user$1 = await provider.user(tokens);
3247
- return {
3248
- api: await this.serverLinksProvider.getUserApiLinks({
3249
- authorization: headers$1.authorization,
3250
- user: user$1
3251
- }),
3252
- user: user$1
3253
- };
3254
- }
3255
- }
3256
- return {
3257
- api: await this.serverLinksProvider.getUserApiLinks({
3258
- authorization: headers$1.authorization,
3259
- user
3260
- }),
3261
- user
3262
- };
3263
- }
3264
- });
3265
- /**
3266
- * Refresh a token for internal providers.
3267
- */
3268
- refresh = $route({
3269
- path: ReactAuth.path.refresh,
3270
- method: "POST",
3271
- schema: {
3272
- query: t.object({ provider: t.text() }),
3273
- body: t.object({
3274
- refresh_token: t.text({ size: "rich" }),
3275
- access_token: t.optional(t.text({
3276
- size: "rich",
3277
- description: "Required if provider has stateless refresh token on credentials mode"
3278
- }))
3279
- }),
3280
- response: tokensSchema
3281
- },
3282
- handler: async ({ query, body, cookies }) => {
3283
- const provider = this.provider(query);
3284
- const tokens = {
3285
- provider: query.provider,
3286
- ...await provider.refresh(body.refresh_token, body.access_token)
3287
- };
3288
- this.setTokens(tokens, cookies);
3289
- return tokens;
3290
- }
3291
- });
3292
- /**
3293
- * Login for local password-based authentication.
3294
- */
3295
- token = $route({
3296
- path: ReactAuth.path.token,
3297
- method: "POST",
3298
- schema: {
3299
- query: t.object({ provider: t.text() }),
3300
- body: t.object({
3301
- username: t.text(),
3302
- password: t.text()
3303
- }),
3304
- response: tokenResponseSchema
3305
- },
3306
- handler: async ({ query, body, cookies }) => {
3307
- const provider = this.provider(query);
3308
- const realm = "realm" in provider.options && provider.options.realm;
3309
- if (!realm) throw new SecurityError(`Auth provider '${query.provider}' does not support password grant`);
3310
- const credentials = "credentials" in provider.options && provider.options.credentials;
3311
- if (!credentials) throw new SecurityError(`Auth provider '${query.provider}' does not support password grant`);
3312
- let user;
3313
- try {
3314
- user = await credentials.account(body);
3315
- } catch (e$1) {
3316
- throw new UnauthorizedError(`Failed to authenticate user`, { cause: e$1 });
3317
- }
3318
- const tokens = {
3319
- provider: query.provider,
3320
- ...await realm.createToken(user)
3321
- };
3322
- this.setTokens(tokens, cookies);
3323
- const api = await this.serverLinksProvider.getUserApiLinks({ user });
3324
- return {
3325
- ...tokens,
3326
- user,
3327
- api
3328
- };
3329
- }
3330
- });
3331
- /**
3332
- * Oauth2/OIDC login route.
3333
- */
3334
- login = $route({
3335
- path: ReactAuth.path.login,
3336
- schema: { query: t.object({
3337
- provider: t.text(),
3338
- redirect_uri: t.optional(t.text({ size: "rich" }))
3339
- }) },
3340
- handler: async ({ query, url, reply }) => {
3341
- const provider = this.provider(query);
3342
- const oauth = provider.oauth;
3343
- if (!oauth) throw new SecurityError(`Auth provider '${query.provider}' does not support OAuth2`);
3344
- const scope = provider.scope;
3345
- let redirect_uri = provider.redirect_uri || ReactAuth.path.callback;
3346
- if (redirect_uri.startsWith("/")) redirect_uri = `${url.protocol}//${url.host}${redirect_uri}`;
3347
- const oidc = "oidc" in provider.options && provider.options.oidc;
3348
- if (!oauth.serverMetadata().supportsPKCE()) {
3349
- const state = randomState();
3350
- const parameters$1 = {
3351
- redirect_uri,
3352
- state
3353
- };
3354
- if (oidc) parameters$1.nonce = randomState();
3355
- if (scope) parameters$1.scope = scope;
3356
- this.authorizationCode.set({
3357
- state,
3358
- nonce: parameters$1.nonce,
3359
- redirectUri: query.redirect_uri ?? "/",
3360
- provider: query.provider
3361
- });
3362
- reply.redirect(buildAuthorizationUrl(oauth, parameters$1).toString());
3363
- return;
3364
- }
3365
- const codeVerifier = randomPKCECodeVerifier();
3366
- const codeChallenge = await calculatePKCECodeChallenge(codeVerifier);
3367
- const parameters = {
3368
- redirect_uri,
3369
- code_challenge: codeChallenge,
3370
- code_challenge_method: "S256"
3371
- };
3372
- if (scope) parameters.scope = scope;
3373
- this.authorizationCode.set({
3374
- codeVerifier,
3375
- redirectUri: query.redirect_uri ?? "/",
3376
- provider: query.provider
3377
- });
3378
- reply.redirect(buildAuthorizationUrl(oauth, parameters).toString());
3379
- }
3380
- });
3381
- /**
3382
- * Callback for OAuth2/OIDC providers.
3383
- * It handles the authorization code flow and retrieves the access token.
3384
- */
3385
- callback = $route({
3386
- path: ReactAuth.path.callback,
3387
- handler: async ({ url, reply, cookies }) => {
3388
- const authorizationCode = this.authorizationCode.get({ cookies });
3389
- if (!authorizationCode) throw new BadRequestError("Missing code verifier");
3390
- const provider = this.provider(authorizationCode);
3391
- const oauth = provider.oauth;
3392
- if (!oauth) throw new SecurityError(`Auth provider '${provider.name}' does not support OAuth2`);
3393
- const redirectUri = authorizationCode.redirectUri ?? "/";
3394
- const externalTokens = await authorizationCodeGrant(oauth, url, {
3395
- pkceCodeVerifier: authorizationCode.codeVerifier,
3396
- expectedState: authorizationCode.state,
3397
- expectedNonce: authorizationCode.nonce
3398
- }).then((tokens$1) => ({
3399
- issued_at: this.dateTimeProvider.now().unix(),
3400
- provider: provider.name,
3401
- ...tokens$1
3402
- })).catch((e$1) => {
3403
- this.log.error("Failed to get access token", e$1);
3404
- throw new SecurityError("Failed to get access token", { cause: e$1 });
3405
- });
3406
- this.authorizationCode.del({ cookies });
3407
- const realm = "realm" in provider.options && provider.options.realm;
3408
- if (!realm) {
3409
- this.setTokens(externalTokens, cookies);
3410
- reply.redirect(redirectUri);
3411
- return;
3412
- }
3413
- const user = await provider.user(externalTokens);
3414
- const tokens = await realm.createToken(user);
3415
- this.setTokens({
3416
- ...tokens,
3417
- issued_at: this.dateTimeProvider.now().unix(),
3418
- provider: provider.name
3419
- }, cookies);
3420
- reply.redirect(redirectUri);
3421
- }
3422
- });
3423
- /**
3424
- * Logout route for OAuth2/OIDC providers.
3425
- */
3426
- logout = $route({
3427
- path: ReactAuth.path.logout,
3428
- method: "GET",
3429
- schema: { query: t.object({ post_logout_redirect_uri: t.optional(t.text()) }) },
3430
- handler: async ({ query, reply, cookies }) => {
3431
- const redirect = query.post_logout_redirect_uri ?? "/";
3432
- const tokens = this.tokens.get({ cookies });
3433
- if (!tokens) {
3434
- reply.redirect(redirect);
3435
- return;
3436
- }
3437
- const provider = this.provider(tokens.provider);
3438
- this.tokens.del({ cookies });
3439
- if ("realm" in provider.options && tokens.refresh_token) {
3440
- const onDeleteSession = provider.options.realm.options.settings?.onDeleteSession;
3441
- if (onDeleteSession) try {
3442
- await onDeleteSession(tokens.refresh_token);
3443
- } catch (e$1) {
3444
- this.log.error("Failed to delete session", e$1);
3445
- }
3446
- }
3447
- const oauth = provider.oauth;
3448
- if (!oauth) {
3449
- reply.redirect(redirect);
3450
- return;
3451
- }
3452
- const params = new URLSearchParams();
3453
- const idToken = tokens?.id_token;
3454
- params.set("post_logout_redirect_uri", redirect);
3455
- if (idToken) params.set("id_token_hint", idToken);
3456
- const customLogoutUri = "oidc" in provider.options ? provider.options.oidc?.logoutUri : void 0;
3457
- if (customLogoutUri) {
3458
- reply.redirect(`${customLogoutUri}?${params}`);
3459
- return;
3460
- }
3461
- if (!oauth.serverMetadata().end_session_endpoint) {
3462
- reply.redirect(redirect);
3463
- return;
3464
- }
3465
- reply.redirect(buildEndSessionUrl(oauth, params).toString());
3466
- }
3467
- });
3468
- provider(opts) {
3469
- const name = typeof opts === "string" ? opts : opts.provider;
3470
- const identity = this.identities.find((identity$1) => identity$1.name === name);
3471
- if (!identity) throw new SecurityError(`Auth provider '${name}' not found`);
3472
- return identity;
3473
- }
3474
- setTokens(tokens, cookies) {
3475
- const exp = tokens.refresh_token_expires_in || tokens.refresh_expires_in || tokens.expires_in;
3476
- const ttl = exp ? this.dateTimeProvider.duration(exp, "seconds") : void 0;
3477
- this.tokens.set(tokens, {
3478
- cookies,
3479
- ttl
3480
- });
3481
- }
3482
- };
3483
-
3484
- //#endregion
3485
- //#region src/auth/descriptors/$authGithub.ts
3486
- /**
3487
- * Already configured GitHub authentication descriptor.
3488
- *
3489
- * Uses OAuth2 to authenticate users via their GitHub accounts.
3490
- * Upon successful authentication, it links the GitHub account to a user session.
3491
- *
3492
- * Environment Variables:
3493
- * - `GITHUB_CLIENT_ID`: The client ID obtained from the GitHub Developer Settings.
3494
- * - `GITHUB_CLIENT_SECRET`: The client secret obtained from the GitHub Developer Settings.
3495
- */
3496
- const $authGithub = (realm, options) => {
3497
- const { alepha } = $context();
3498
- const env = alepha.parseEnv(t.object({
3499
- GITHUB_CLIENT_ID: t.string(),
3500
- GITHUB_CLIENT_SECRET: t.string()
3501
- }));
3502
- return $auth({
3503
- realm,
3504
- name: "github",
3505
- oauth: {
3506
- clientId: env.GITHUB_CLIENT_ID,
3507
- clientSecret: env.GITHUB_CLIENT_SECRET,
3508
- authorization: "https://github.com/login/oauth/authorize",
3509
- token: "https://github.com/login/oauth/access_token",
3510
- scope: "read:user user:email",
3511
- userinfo: async (tokens) => {
3512
- const BASE_URL = "https://api.github.com";
3513
- const res = await fetch(`${BASE_URL}/user`, { headers: {
3514
- Authorization: `Bearer ${tokens.access_token}`,
3515
- "User-Agent": "Alepha"
3516
- } }).then((res$1) => res$1.json());
3517
- const user = { sub: res.id.toString() };
3518
- if (res.email) user.email = res.email;
3519
- if (res.name) user.name = res.name.trim();
3520
- if (res.avatar_url) user.picture = res.avatar_url;
3521
- if (!user.email) {
3522
- const res$1 = await fetch(`${BASE_URL}/user/emails`, { headers: {
3523
- Authorization: `Bearer ${tokens.access_token}`,
3524
- "User-Agent": "Alepha"
3525
- } });
3526
- if (res$1.ok) {
3527
- const emails = await res$1.json();
3528
- user.email = (emails.find((e$1) => e$1.primary) ?? emails[0]).email;
3529
- }
3530
- }
3531
- return user;
3532
- },
3533
- ...options
3534
- }
3535
- });
3536
- };
3537
-
3538
- //#endregion
3539
- //#region src/auth/descriptors/$authGoogle.ts
3540
- /**
3541
- * Already configured Google authentication descriptor.
3542
- *
3543
- * Uses OpenID Connect (OIDC) to authenticate users via their Google accounts.
3544
- * Upon successful authentication, it links the Google account to a user session.
3545
- *
3546
- * Environment Variables:
3547
- * - `GOOGLE_CLIENT_ID`: The client ID obtained from the Google Developer Console.
3548
- * - `GOOGLE_CLIENT_SECRET`: The client secret obtained from the Google Developer Console.
3549
- */
3550
- const $authGoogle = (realm, options) => {
3551
- const { alepha } = $context();
3552
- const env = alepha.parseEnv(t.object({
3553
- GOOGLE_CLIENT_ID: t.string(),
3554
- GOOGLE_CLIENT_SECRET: t.string()
3555
- }));
3556
- return $auth({
3557
- realm,
3558
- name: "google",
3559
- oidc: {
3560
- issuer: "https://accounts.google.com",
3561
- clientId: env.GOOGLE_CLIENT_ID,
3562
- clientSecret: env.GOOGLE_CLIENT_SECRET,
3563
- ...options
3564
- }
3565
- });
3566
- };
3567
-
3568
- //#endregion
3569
- //#region src/auth/errors/SessionExpiredError.ts
3570
- var SessionExpiredError = class extends AlephaError {
3571
- name = "SessionExpiredError";
3572
- status = 401;
3573
1726
  };
3574
1727
 
3575
1728
  //#endregion
@@ -3604,12 +1757,13 @@ const AlephaReactAuth = $module({
3604
1757
  descriptors: [$auth],
3605
1758
  services: [
3606
1759
  AlephaReact,
3607
- AlephaServerCookies,
1760
+ AlephaServerLinks,
1761
+ AlephaServerAuth,
3608
1762
  ReactAuthProvider,
3609
1763
  ReactAuth
3610
1764
  ]
3611
1765
  });
3612
1766
 
3613
1767
  //#endregion
3614
- export { $auth, $authGithub, $authGoogle, AlephaReactAuth, AuthDescriptor, ReactAuth, ReactAuthProvider, SessionExpiredError, useAuth };
1768
+ export { AlephaReactAuth, ReactAuth, ReactAuthProvider, useAuth };
3615
1769
  //# sourceMappingURL=index.js.map