oidc-spa 8.1.9 → 8.1.11

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 (196) hide show
  1. package/backend.d.ts +27 -6
  2. package/backend.js +124 -139
  3. package/backend.js.map +1 -1
  4. package/core/Oidc.d.ts +28 -4
  5. package/core/createOidc.d.ts +12 -3
  6. package/core/createOidc.js +1 -1
  7. package/core/createOidc.js.map +1 -1
  8. package/core/earlyInit.d.ts +1 -0
  9. package/core/earlyInit.js +11 -4
  10. package/core/earlyInit.js.map +1 -1
  11. package/core/iframeMessageProtection.js +16 -18
  12. package/core/iframeMessageProtection.js.map +1 -1
  13. package/core/loginOrGoToAuthServer.js +8 -3
  14. package/core/loginOrGoToAuthServer.js.map +1 -1
  15. package/core/loginSilent.js +4 -0
  16. package/core/loginSilent.js.map +1 -1
  17. package/core/oidcClientTsUserToTokens.d.ts +1 -1
  18. package/core/oidcClientTsUserToTokens.js.map +1 -1
  19. package/core/requiredPostHydrationReplaceNavigationUrl.d.ts +6 -0
  20. package/core/requiredPostHydrationReplaceNavigationUrl.js +12 -0
  21. package/core/requiredPostHydrationReplaceNavigationUrl.js.map +1 -0
  22. package/entrypoint.d.ts +1 -0
  23. package/entrypoint.js +3 -1
  24. package/entrypoint.js.map +1 -1
  25. package/esm/angular.d.ts +14 -4
  26. package/esm/angular.js +155 -10
  27. package/esm/angular.js.map +1 -1
  28. package/esm/backend.d.ts +48 -0
  29. package/esm/backend.js +259 -0
  30. package/esm/backend.js.map +1 -0
  31. package/esm/core/Oidc.d.ts +28 -4
  32. package/esm/core/createOidc.d.ts +12 -3
  33. package/esm/core/createOidc.js +1 -1
  34. package/esm/core/createOidc.js.map +1 -1
  35. package/esm/core/earlyInit.d.ts +1 -0
  36. package/esm/core/earlyInit.js +11 -4
  37. package/esm/core/earlyInit.js.map +1 -1
  38. package/esm/core/iframeMessageProtection.js +16 -18
  39. package/esm/core/iframeMessageProtection.js.map +1 -1
  40. package/esm/core/loginOrGoToAuthServer.js +8 -3
  41. package/esm/core/loginOrGoToAuthServer.js.map +1 -1
  42. package/esm/core/loginSilent.js +4 -0
  43. package/esm/core/loginSilent.js.map +1 -1
  44. package/esm/core/oidcClientTsUserToTokens.d.ts +1 -1
  45. package/esm/core/oidcClientTsUserToTokens.js.map +1 -1
  46. package/esm/core/requiredPostHydrationReplaceNavigationUrl.d.ts +6 -0
  47. package/esm/core/requiredPostHydrationReplaceNavigationUrl.js +8 -0
  48. package/esm/core/requiredPostHydrationReplaceNavigationUrl.js.map +1 -0
  49. package/esm/entrypoint.d.ts +1 -0
  50. package/esm/entrypoint.js +1 -0
  51. package/esm/entrypoint.js.map +1 -1
  52. package/esm/mock/oidc.d.ts +1 -1
  53. package/esm/mock/oidc.js.map +1 -1
  54. package/esm/react/react.d.ts +1 -1
  55. package/esm/tanstack-start/react/accessTokenValidation_rfc9068.d.ts +12 -0
  56. package/esm/tanstack-start/react/accessTokenValidation_rfc9068.js +95 -0
  57. package/esm/tanstack-start/react/accessTokenValidation_rfc9068.js.map +1 -0
  58. package/esm/tanstack-start/react/apiBuilder.d.ts +27 -0
  59. package/esm/tanstack-start/react/apiBuilder.js +58 -0
  60. package/esm/tanstack-start/react/apiBuilder.js.map +1 -0
  61. package/esm/tanstack-start/react/createOidcSpaApi.d.ts +9 -0
  62. package/esm/tanstack-start/react/createOidcSpaApi.js +678 -0
  63. package/esm/tanstack-start/react/createOidcSpaApi.js.map +1 -0
  64. package/esm/tanstack-start/react/index.d.ts +3 -0
  65. package/esm/tanstack-start/react/index.js +4 -0
  66. package/esm/tanstack-start/react/index.js.map +1 -0
  67. package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/UnifiedClientRetryForSsrLoadersError.d.ts +4 -0
  68. package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/UnifiedClientRetryForSsrLoadersError.js +8 -0
  69. package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/UnifiedClientRetryForSsrLoadersError.js.map +1 -0
  70. package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/enableUnifiedClientRetryForSsrLoaders.d.ts +4 -0
  71. package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/enableUnifiedClientRetryForSsrLoaders.js +76 -0
  72. package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/enableUnifiedClientRetryForSsrLoaders.js.map +1 -0
  73. package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/entrypoint.d.ts +1 -0
  74. package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/entrypoint.js +11 -0
  75. package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/entrypoint.js.map +1 -0
  76. package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/index.d.ts +2 -0
  77. package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/index.js +3 -0
  78. package/esm/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/index.js.map +1 -0
  79. package/esm/tanstack-start/react/types.d.ts +355 -0
  80. package/esm/tanstack-start/react/types.js +2 -0
  81. package/esm/tanstack-start/react/types.js.map +1 -0
  82. package/esm/tanstack-start/react/withHandlingOidcPostLoginNavigation.d.ts +2 -0
  83. package/esm/tanstack-start/react/withHandlingOidcPostLoginNavigation.js +25 -0
  84. package/esm/tanstack-start/react/withHandlingOidcPostLoginNavigation.js.map +1 -0
  85. package/esm/tools/GetterOrDirectValue.d.ts +1 -0
  86. package/esm/tools/GetterOrDirectValue.js +2 -0
  87. package/esm/tools/GetterOrDirectValue.js.map +1 -0
  88. package/esm/tools/ZodSchemaLike.d.ts +3 -0
  89. package/esm/tools/ZodSchemaLike.js +2 -0
  90. package/esm/tools/ZodSchemaLike.js.map +1 -0
  91. package/esm/tools/inferIsViteDev.d.ts +1 -0
  92. package/esm/tools/inferIsViteDev.js +6 -0
  93. package/esm/tools/inferIsViteDev.js.map +1 -0
  94. package/esm/tools/infer_import_meta_env_BASE_URL.d.ts +1 -0
  95. package/esm/tools/infer_import_meta_env_BASE_URL.js +15 -0
  96. package/esm/tools/infer_import_meta_env_BASE_URL.js.map +1 -0
  97. package/esm/tools/tsafe/uncapitalize.d.ts +2 -0
  98. package/esm/tools/tsafe/uncapitalize.js +5 -0
  99. package/esm/tools/tsafe/uncapitalize.js.map +1 -0
  100. package/esm/vendor/backend/evt.d.ts +2 -0
  101. package/esm/vendor/backend/evt.js +3286 -0
  102. package/esm/vendor/backend/jose.d.ts +1 -0
  103. package/esm/vendor/backend/jose.js +3546 -0
  104. package/esm/vendor/backend/tsafe.d.ts +5 -0
  105. package/esm/vendor/backend/tsafe.js +68 -0
  106. package/esm/vendor/backend/zod.d.ts +1 -0
  107. package/esm/vendor/backend/zod.js +4023 -0
  108. package/esm/vendor/frontend/worker-timers.js +261 -1
  109. package/mock/oidc.d.ts +1 -1
  110. package/mock/oidc.js.map +1 -1
  111. package/package.json +40 -4
  112. package/react/react.d.ts +1 -1
  113. package/src/angular.ts +224 -9
  114. package/src/backend.ts +201 -166
  115. package/src/core/Oidc.ts +41 -11
  116. package/src/core/createOidc.ts +12 -3
  117. package/src/core/earlyInit.ts +19 -4
  118. package/src/core/iframeMessageProtection.ts +14 -15
  119. package/src/core/loginOrGoToAuthServer.ts +11 -3
  120. package/src/core/loginSilent.ts +5 -0
  121. package/src/core/oidcClientTsUserToTokens.ts +2 -2
  122. package/src/core/requiredPostHydrationReplaceNavigationUrl.ts +11 -0
  123. package/src/entrypoint.ts +1 -0
  124. package/src/mock/oidc.ts +2 -2
  125. package/src/react/react.tsx +1 -1
  126. package/src/tanstack-start/react/accessTokenValidation_rfc9068.ts +135 -0
  127. package/src/tanstack-start/react/apiBuilder.ts +151 -0
  128. package/src/tanstack-start/react/createOidcSpaApi.tsx +1009 -0
  129. package/src/tanstack-start/react/index.ts +5 -0
  130. package/src/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/UnifiedClientRetryForSsrLoadersError.ts +8 -0
  131. package/src/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/enableUnifiedClientRetryForSsrLoaders.tsx +110 -0
  132. package/src/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/entrypoint.ts +13 -0
  133. package/src/tanstack-start/react/rfcUnifiedClientRetryForSsrLoaders/index.ts +2 -0
  134. package/src/tanstack-start/react/types.tsx +415 -0
  135. package/src/tanstack-start/react/withHandlingOidcPostLoginNavigation.tsx +35 -0
  136. package/src/tools/GetterOrDirectValue.ts +1 -0
  137. package/src/tools/ZodSchemaLike.ts +3 -0
  138. package/src/tools/getThisCodebaseRootDirPath_cjs.ts +19 -0
  139. package/src/tools/inferIsViteDev.ts +6 -0
  140. package/src/tools/infer_import_meta_env_BASE_URL.ts +19 -0
  141. package/src/tools/tsafe/uncapitalize.ts +4 -0
  142. package/src/vendor/backend/jose.ts +1 -0
  143. package/src/vendor/build-runtime/babel.ts +6 -0
  144. package/src/vendor/build-runtime/magic-string.ts +3 -0
  145. package/src/vite-plugin/detectProjectType.ts +20 -0
  146. package/src/vite-plugin/excludeModuleExportFromOptimizedDeps.ts +20 -0
  147. package/src/vite-plugin/handleClientEntrypoint.ts +260 -0
  148. package/src/vite-plugin/index.ts +1 -0
  149. package/src/vite-plugin/transformCreateFileRoute.ts +240 -0
  150. package/src/vite-plugin/vite-plugin.ts +54 -0
  151. package/tools/GetterOrDirectValue.d.ts +1 -0
  152. package/tools/GetterOrDirectValue.js +3 -0
  153. package/tools/GetterOrDirectValue.js.map +1 -0
  154. package/tools/ZodSchemaLike.d.ts +3 -0
  155. package/tools/ZodSchemaLike.js +3 -0
  156. package/tools/ZodSchemaLike.js.map +1 -0
  157. package/tools/getThisCodebaseRootDirPath_cjs.d.ts +2 -0
  158. package/tools/getThisCodebaseRootDirPath_cjs.js +53 -0
  159. package/tools/getThisCodebaseRootDirPath_cjs.js.map +1 -0
  160. package/tools/tsafe/uncapitalize.d.ts +2 -0
  161. package/tools/tsafe/uncapitalize.js +8 -0
  162. package/tools/tsafe/uncapitalize.js.map +1 -0
  163. package/vendor/backend/jose.d.ts +1 -0
  164. package/vendor/backend/jose.js +3 -0
  165. package/vendor/build-runtime/babel.d.ts +6 -0
  166. package/vendor/build-runtime/babel.js +3 -0
  167. package/vendor/build-runtime/magic-string.d.ts +2 -0
  168. package/vendor/build-runtime/magic-string.js +2 -0
  169. package/vendor/frontend/oidc-client-ts.js +0 -2
  170. package/vite-plugin/detectProjectType.d.ts +10 -0
  171. package/vite-plugin/detectProjectType.js +15 -0
  172. package/vite-plugin/detectProjectType.js.map +1 -0
  173. package/vite-plugin/excludeModuleExportFromOptimizedDeps.d.ts +4 -0
  174. package/vite-plugin/excludeModuleExportFromOptimizedDeps.js +50 -0
  175. package/vite-plugin/excludeModuleExportFromOptimizedDeps.js.map +1 -0
  176. package/vite-plugin/handleClientEntrypoint.d.ts +10 -0
  177. package/vite-plugin/handleClientEntrypoint.js +211 -0
  178. package/vite-plugin/handleClientEntrypoint.js.map +1 -0
  179. package/vite-plugin/index.d.ts +1 -0
  180. package/vite-plugin/index.js +6 -0
  181. package/vite-plugin/index.js.map +1 -0
  182. package/vite-plugin/transformCreateFileRoute.d.ts +10 -0
  183. package/vite-plugin/transformCreateFileRoute.js +173 -0
  184. package/vite-plugin/transformCreateFileRoute.js.map +1 -0
  185. package/vite-plugin/vite-plugin.d.ts +5 -0
  186. package/vite-plugin/vite-plugin.js +46 -0
  187. package/vite-plugin/vite-plugin.js.map +1 -0
  188. package/src/vendor/backend/jsonwebtoken.ts +0 -1
  189. package/src/vendor/backend/node-fetch.ts +0 -2
  190. package/src/vendor/backend/node-jose.ts +0 -1
  191. package/vendor/backend/jsonwebtoken.d.ts +0 -1
  192. package/vendor/backend/jsonwebtoken.js +0 -3
  193. package/vendor/backend/node-fetch.d.ts +0 -2
  194. package/vendor/backend/node-fetch.js +0 -2
  195. package/vendor/backend/node-jose.d.ts +0 -1
  196. package/vendor/backend/node-jose.js +0 -3
@@ -93,15 +93,16 @@ export async function initIframeMessageProtection(params: { stateUrlParamValue:
93
93
  }
94
94
 
95
95
  function startSessionStoragePublicKeyMaliciousWriteDetection() {
96
- setSessionStoragePublicKey();
97
-
98
96
  assert(capturedApis !== undefined);
99
97
 
100
- const { /*alert,*/ setTimeout } = capturedApis;
98
+ const { alert, setTimeout } = capturedApis;
99
+
100
+ sessionStorage.removeItem(sessionStorageKey);
101
101
 
102
102
  const checkTimeoutCallback = () => {
103
- if (sessionStorage.getItem(sessionStorageKey) !== publicKey) {
104
- /*
103
+ const publicKey_inStorage = sessionStorage.getItem(sessionStorageKey);
104
+
105
+ if (publicKey_inStorage !== null && publicKey_inStorage !== publicKey) {
105
106
  while (true) {
106
107
  alert(
107
108
  [
@@ -112,7 +113,6 @@ export async function initIframeMessageProtection(params: { stateUrlParamValue:
112
113
  ].join(" ")
113
114
  );
114
115
  }
115
- */
116
116
  }
117
117
  check();
118
118
  };
@@ -161,20 +161,19 @@ export async function postEncryptedAuthResponseToParent(params: { authResponse:
161
161
 
162
162
  parent.postMessage(getReadyMessage({ stateUrlParamValue: authResponse.state }), location.origin);
163
163
 
164
- const readPublicKey = () =>
165
- sessionStorage.getItem(getSessionStorageKey({ stateUrlParamValue: authResponse.state }));
166
-
167
164
  await new Promise<void>(resolve => setTimeout(resolve, 2));
168
165
 
169
- while (readPublicKey() === null) {
170
- await new Promise<void>(resolve => setTimeout(resolve, 2));
171
- }
166
+ let publicKey: string | null;
172
167
 
173
- await new Promise<void>(resolve => setTimeout(resolve, 7));
168
+ {
169
+ let sessionStorageKey = getSessionStorageKey({ stateUrlParamValue: authResponse.state });
174
170
 
175
- const publicKey = readPublicKey();
171
+ while ((publicKey = sessionStorage.getItem(sessionStorageKey)) === null) {
172
+ await new Promise<void>(resolve => setTimeout(resolve, 2));
173
+ }
174
+ }
176
175
 
177
- assert(publicKey !== null, "2293303");
176
+ await new Promise<void>(resolve => setTimeout(resolve, 7));
178
177
 
179
178
  const { encryptedMessage: encryptedMessage_withoutPrefix } = await asymmetricEncrypt({
180
179
  publicKey,
@@ -355,9 +355,17 @@ export function createLoginOrGoToAuthServer(params: {
355
355
  return new Promise<never>(() => {});
356
356
  }
357
357
 
358
- // NOTE: Here, except error on our understanding there can't be any other
359
- // error.
360
- assert(false, "30442320");
358
+ if (error.message.includes("Crypto.subtle is available only in secure contexts")) {
359
+ throw new Error(
360
+ [
361
+ `oidc-spa: ${error.message}.`,
362
+ "To fix this error see:",
363
+ "https://docs.oidc-spa.dev/v/v8/resources/fixing-crypto.subtle-is-available-only-in-secure-contexts-https"
364
+ ].join(" ")
365
+ );
366
+ }
367
+
368
+ assert(false, "224238482");
361
369
  }
362
370
  );
363
371
  }
@@ -178,6 +178,11 @@ export async function loginSilent(params: {
178
178
 
179
179
  window.removeEventListener("message", listener);
180
180
 
181
+ // NOTE: Acknowledge that we're also doing it later but
182
+ // since there's a aggressive write protection in place
183
+ // it's good to clear the key ASAP.
184
+ clearSessionStoragePublicKey();
185
+
181
186
  dEncryptedAuthResponse.resolve(message);
182
187
  };
183
188
 
@@ -9,7 +9,7 @@ import { INFINITY_TIME } from "../tools/INFINITY_TIME";
9
9
  export function oidcClientTsUserToTokens<DecodedIdToken extends Record<string, unknown>>(params: {
10
10
  oidcClientTsUser: OidcClientTsUser;
11
11
  decodedIdTokenSchema?: {
12
- parse: (decodedIdToken_original: Oidc.Tokens.DecodedIdToken_base) => DecodedIdToken;
12
+ parse: (decodedIdToken_original: Oidc.Tokens.DecodedIdToken_OidcCoreSpec) => DecodedIdToken;
13
13
  };
14
14
  __unsafe_useIdTokenAsAccessToken: boolean;
15
15
  decodedIdToken_previous: DecodedIdToken | undefined;
@@ -33,7 +33,7 @@ export function oidcClientTsUserToTokens<DecodedIdToken extends Record<string, u
33
33
 
34
34
  assert(idToken !== undefined, "No id token provided by the oidc server");
35
35
 
36
- const decodedIdToken_original = decodeJwt<Oidc.Tokens.DecodedIdToken_base>(idToken);
36
+ const decodedIdToken_original = decodeJwt<Oidc.Tokens.DecodedIdToken_OidcCoreSpec>(idToken);
37
37
 
38
38
  if (isFirstInit) {
39
39
  log?.(
@@ -0,0 +1,11 @@
1
+ let rootRelativeRedirectUrl: string | undefined = undefined;
2
+
3
+ export function getOidcRequiredPostHydrationReplaceNavigationUrl() {
4
+ return { rootRelativeRedirectUrl };
5
+ }
6
+
7
+ export function setOidcRequiredPostHydrationReplaceNavigationUrl(params: {
8
+ rootRelativeRedirectUrl: string;
9
+ }) {
10
+ rootRelativeRedirectUrl = params.rootRelativeRedirectUrl;
11
+ }
package/src/entrypoint.ts CHANGED
@@ -1 +1,2 @@
1
1
  export { oidcEarlyInit } from "./core/earlyInit";
2
+ export { getOidcRequiredPostHydrationReplaceNavigationUrl } from "./core/requiredPostHydrationReplaceNavigationUrl";
package/src/mock/oidc.ts CHANGED
@@ -32,7 +32,7 @@ const URL_SEARCH_PARAM_NAME = "isUserLoggedIn";
32
32
  const locationHref_moduleEvalTime = location.href;
33
33
 
34
34
  export async function createMockOidc<
35
- DecodedIdToken extends Record<string, unknown> = Oidc.Tokens.DecodedIdToken_base,
35
+ DecodedIdToken extends Record<string, unknown> = Oidc.Tokens.DecodedIdToken_OidcCoreSpec,
36
36
  AutoLogin extends boolean = false
37
37
  >(
38
38
  params: ParamsOfCreateMockOidc<DecodedIdToken, AutoLogin>
@@ -157,7 +157,7 @@ export async function createMockOidc<
157
157
  }),
158
158
  decodedIdToken_original:
159
159
  mockedTokens.decodedIdToken_original ??
160
- createObjectThatThrowsIfAccessed<Oidc.Tokens.DecodedIdToken_base>({
160
+ createObjectThatThrowsIfAccessed<Oidc.Tokens.DecodedIdToken_OidcCoreSpec>({
161
161
  debugMessage: [
162
162
  "You haven't provided a mocked decodedIdToken_original",
163
163
  "See https://docs.oidc-spa.dev/v/v8/mock"
@@ -454,7 +454,7 @@ export function createReactOidc_dependencyInjection<
454
454
 
455
455
  /** @see: https://docs.oidc-spa.dev/v/v8/usage#react-api */
456
456
  export function createReactOidc<
457
- DecodedIdToken extends Record<string, unknown> = Oidc.Tokens.DecodedIdToken_base,
457
+ DecodedIdToken extends Record<string, unknown> = Oidc.Tokens.DecodedIdToken_OidcCoreSpec,
458
458
  AutoLogin extends boolean = false
459
459
  >(params: ValueOrAsyncGetter<ParamsOfCreateOidc<DecodedIdToken, AutoLogin>>) {
460
460
  return createReactOidc_dependencyInjection(params, createOidc);
@@ -0,0 +1,135 @@
1
+ import type { CreateValidateAndGetAccessTokenClaims, ParamsOfBootstrap } from "./types";
2
+ import type { DecodedAccessToken_RFC9068 as AccessTokenClaims_RFC9068 } from "../../backend";
3
+ import type { ZodSchemaLike } from "../../tools/ZodSchemaLike";
4
+ import { createObjectThatThrowsIfAccessed } from "../../tools/createObjectThatThrowsIfAccessed";
5
+ import { assert, type Equals, is } from "../../tools/tsafe/assert";
6
+
7
+ export function createCreateValidateAndGetAccessTokenClaims_rfc9068<
8
+ AccessTokenClaims extends Record<string, unknown>
9
+ >(params: {
10
+ accessTokenClaimsSchema?: ZodSchemaLike<AccessTokenClaims_RFC9068, AccessTokenClaims>;
11
+ accessTokenClaims_mock?: AccessTokenClaims;
12
+ expectedAudience?:
13
+ | string
14
+ | ((params: {
15
+ paramsOfBootstrap: ParamsOfBootstrap<boolean, Record<string, unknown>, AccessTokenClaims>;
16
+ }) => string);
17
+ }) {
18
+ const {
19
+ accessTokenClaimsSchema,
20
+ accessTokenClaims_mock,
21
+ expectedAudience: expectedAudienceOrGetter
22
+ } = params;
23
+
24
+ const createValidateAndGetAccessTokenClaims: CreateValidateAndGetAccessTokenClaims<
25
+ AccessTokenClaims
26
+ > = ({ paramsOfBootstrap }) => {
27
+ if (paramsOfBootstrap.implementation === "mock") {
28
+ return {
29
+ validateAndGetAccessTokenClaims: async () => {
30
+ return {
31
+ isValid: true,
32
+ accessTokenClaims: (() => {
33
+ if (paramsOfBootstrap.accessTokenClaims_mock !== undefined) {
34
+ assert(is<AccessTokenClaims>(paramsOfBootstrap.accessTokenClaims_mock));
35
+ return paramsOfBootstrap.accessTokenClaims_mock;
36
+ }
37
+
38
+ if (accessTokenClaims_mock !== undefined) {
39
+ return accessTokenClaims_mock;
40
+ }
41
+
42
+ return createObjectThatThrowsIfAccessed<AccessTokenClaims>({
43
+ debugMessage: [
44
+ "oidc-spa: You didn't provide any mock for the accessTokenClaims",
45
+ "Either provide a default one by specifying accessTokenClaims_mock",
46
+ "as parameter of .withAccessTokenValidation() or",
47
+ "specify accessTokenClaims_mock when calling bootstrapOidc()"
48
+ ].join(" ")
49
+ });
50
+ })()
51
+ };
52
+ }
53
+ };
54
+ }
55
+ assert<Equals<(typeof paramsOfBootstrap)["implementation"], "real">>;
56
+
57
+ const prVerifyAndDecodeAccessToken = (async () => {
58
+ const { createOidcBackend } = await import("../../backend");
59
+
60
+ const { verifyAndDecodeAccessToken } = await createOidcBackend({
61
+ issuerUri: paramsOfBootstrap.issuerUri,
62
+ decodedAccessTokenSchema: accessTokenClaimsSchema
63
+ });
64
+
65
+ return verifyAndDecodeAccessToken;
66
+ })();
67
+
68
+ const expectedAudience = (() => {
69
+ if (expectedAudienceOrGetter === undefined) {
70
+ return undefined;
71
+ }
72
+ if (typeof expectedAudienceOrGetter === "function") {
73
+ return expectedAudienceOrGetter({ paramsOfBootstrap });
74
+ }
75
+ return expectedAudienceOrGetter;
76
+ })();
77
+
78
+ return {
79
+ validateAndGetAccessTokenClaims: async ({ accessToken }) => {
80
+ const verifyAndDecodeAccessToken = await prVerifyAndDecodeAccessToken;
81
+
82
+ const {
83
+ isValid,
84
+ errorCase,
85
+ errorMessage,
86
+ decodedAccessToken,
87
+ decodedAccessToken_original
88
+ } = await verifyAndDecodeAccessToken({ accessToken });
89
+
90
+ if (!isValid) {
91
+ return {
92
+ isValid: false,
93
+ errorMessage: `${errorCase}: ${errorMessage}`,
94
+ wwwAuthenticateHeaderErrorDescription: (() => {
95
+ switch (errorCase) {
96
+ case "does not respect schema":
97
+ return "The access token is malformed or missing required claims";
98
+ case "expired":
99
+ return "The access token expired";
100
+ case "invalid signature":
101
+ return "The access token signature is invalid";
102
+ }
103
+ })()
104
+ };
105
+ }
106
+
107
+ if (expectedAudience !== undefined) {
108
+ const aud_array =
109
+ typeof decodedAccessToken_original.aud === "string"
110
+ ? [decodedAccessToken_original.aud]
111
+ : decodedAccessToken_original.aud;
112
+
113
+ if (!aud_array.includes(expectedAudience)) {
114
+ return {
115
+ isValid: false,
116
+ errorMessage: [
117
+ "Access token is not for the expected audience.",
118
+ `Got aud claim: ${JSON.stringify(decodedAccessToken_original.aud)}`,
119
+ `Expected: ${expectedAudience}`
120
+ ].join(" "),
121
+ wwwAuthenticateHeaderErrorDescription: "The access token audience is invalid"
122
+ };
123
+ }
124
+ }
125
+
126
+ return {
127
+ isValid: true,
128
+ accessTokenClaims: decodedAccessToken
129
+ };
130
+ }
131
+ };
132
+ };
133
+
134
+ return { createValidateAndGetAccessTokenClaims };
135
+ }
@@ -0,0 +1,151 @@
1
+ import type { OidcSpaApi, CreateValidateAndGetAccessTokenClaims, ParamsOfBootstrap } from "./types";
2
+ import type { Oidc as Oidc_core } from "../../core";
3
+ import { assert, type Equals } from "../../tools/tsafe/assert";
4
+ import type { ZodSchemaLike } from "../../tools/ZodSchemaLike";
5
+ import type { DecodedAccessToken_RFC9068 as AccessTokenClaims_RFC9068 } from "../../backend";
6
+ import { createCreateValidateAndGetAccessTokenClaims_rfc9068 } from "./accessTokenValidation_rfc9068";
7
+ import { createOidcSpaApi } from "./createOidcSpaApi";
8
+
9
+ export type OidcSpaApiBuilder<
10
+ AutoLogin extends boolean = false,
11
+ DecodedIdToken extends Record<string, unknown> = Oidc_core.Tokens.DecodedIdToken_OidcCoreSpec,
12
+ AccessTokenClaims extends Record<string, unknown> | undefined = undefined,
13
+ ExcludedMethod extends
14
+ | "withAutoLogin"
15
+ | "withExpectedDecodedIdTokenShape"
16
+ | "withAccessTokenValidation"
17
+ | "finalize" = never
18
+ > = Omit<
19
+ {
20
+ withAutoLogin: () => OidcSpaApiBuilder<
21
+ true,
22
+ DecodedIdToken,
23
+ AccessTokenClaims,
24
+ ExcludedMethod | "withAutoLogin"
25
+ >;
26
+ withExpectedDecodedIdTokenShape: <DecodedIdToken extends Record<string, unknown>>(params: {
27
+ decodedIdTokenSchema: ZodSchemaLike<
28
+ Oidc_core.Tokens.DecodedIdToken_OidcCoreSpec,
29
+ DecodedIdToken
30
+ >;
31
+ decodedIdToken_mock?: NoInfer<DecodedIdToken>;
32
+ }) => OidcSpaApiBuilder<
33
+ AutoLogin,
34
+ DecodedIdToken,
35
+ AccessTokenClaims,
36
+ ExcludedMethod | "withExpectedDecodedIdTokenShape"
37
+ >;
38
+ withAccessTokenValidation: {
39
+ <AccessTokenClaims extends Record<string, unknown> = AccessTokenClaims_RFC9068>(params: {
40
+ type: "RFC 9068: JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens";
41
+ accessTokenClaimsSchema?: ZodSchemaLike<AccessTokenClaims_RFC9068, AccessTokenClaims>;
42
+ accessTokenClaims_mock?: NoInfer<AccessTokenClaims>;
43
+
44
+ expectedAudience?:
45
+ | string
46
+ | ((params: {
47
+ paramsOfBootstrap: ParamsOfBootstrap<
48
+ boolean,
49
+ Record<string, unknown>,
50
+ AccessTokenClaims
51
+ >;
52
+ }) => string);
53
+ }): OidcSpaApiBuilder<
54
+ AutoLogin,
55
+ DecodedIdToken,
56
+ AccessTokenClaims,
57
+ ExcludedMethod | "withAccessTokenValidation"
58
+ >;
59
+ <AccessTokenClaims extends Record<string, unknown>>(params: {
60
+ type: "custom";
61
+ createValidateAndGetAccessTokenClaims: CreateValidateAndGetAccessTokenClaims<AccessTokenClaims>;
62
+ }): OidcSpaApiBuilder<
63
+ AutoLogin,
64
+ DecodedIdToken,
65
+ AccessTokenClaims,
66
+ ExcludedMethod | "withAccessTokenValidation"
67
+ >;
68
+ };
69
+
70
+ finalize: () => OidcSpaApi<AutoLogin, DecodedIdToken, AccessTokenClaims>;
71
+ },
72
+ ExcludedMethod
73
+ >;
74
+
75
+ function createOidcSpaApiBuilder<
76
+ AutoLogin extends boolean = false,
77
+ DecodedIdToken extends Record<string, unknown> = Oidc_core.Tokens.DecodedIdToken_OidcCoreSpec,
78
+ AccessTokenClaims extends Record<string, unknown> | undefined = undefined
79
+ >(params: {
80
+ autoLogin: AutoLogin;
81
+ decodedIdTokenSchema:
82
+ | ZodSchemaLike<Oidc_core.Tokens.DecodedIdToken_OidcCoreSpec, DecodedIdToken>
83
+ | undefined;
84
+ decodedIdToken_mock: DecodedIdToken | undefined;
85
+ createValidateAndGetAccessTokenClaims:
86
+ | CreateValidateAndGetAccessTokenClaims<AccessTokenClaims>
87
+ | undefined;
88
+ }): OidcSpaApiBuilder<AutoLogin, DecodedIdToken, AccessTokenClaims> {
89
+ return {
90
+ withAutoLogin: () =>
91
+ createOidcSpaApiBuilder({
92
+ autoLogin: true,
93
+ decodedIdTokenSchema: params.decodedIdTokenSchema,
94
+ decodedIdToken_mock: params.decodedIdToken_mock,
95
+ createValidateAndGetAccessTokenClaims: params.createValidateAndGetAccessTokenClaims
96
+ }),
97
+ withExpectedDecodedIdTokenShape: ({ decodedIdTokenSchema, decodedIdToken_mock }) =>
98
+ createOidcSpaApiBuilder({
99
+ autoLogin: params.autoLogin,
100
+ decodedIdTokenSchema,
101
+ decodedIdToken_mock: decodedIdToken_mock,
102
+ createValidateAndGetAccessTokenClaims: params.createValidateAndGetAccessTokenClaims
103
+ }),
104
+ withAccessTokenValidation: params_scope =>
105
+ createOidcSpaApiBuilder({
106
+ autoLogin: params.autoLogin,
107
+ decodedIdTokenSchema: params.decodedIdTokenSchema,
108
+ decodedIdToken_mock: params.decodedIdToken_mock,
109
+ createValidateAndGetAccessTokenClaims: ((): any => {
110
+ switch (params_scope.type) {
111
+ case "RFC 9068: JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens": {
112
+ const { accessTokenClaimsSchema, accessTokenClaims_mock, expectedAudience } =
113
+ params_scope;
114
+
115
+ const { createValidateAndGetAccessTokenClaims } =
116
+ createCreateValidateAndGetAccessTokenClaims_rfc9068<
117
+ Exclude<AccessTokenClaims, undefined>
118
+ >({
119
+ // @ts-expect-error
120
+ accessTokenClaims_mock,
121
+ // @ts-expect-error
122
+ accessTokenClaimsSchema,
123
+ expectedAudience
124
+ });
125
+ return createValidateAndGetAccessTokenClaims;
126
+ }
127
+ case "custom": {
128
+ const { createValidateAndGetAccessTokenClaims } = params_scope;
129
+ return createValidateAndGetAccessTokenClaims;
130
+ }
131
+ default:
132
+ assert<Equals<typeof params_scope, never>>(false);
133
+ }
134
+ })()
135
+ }),
136
+ finalize: () =>
137
+ createOidcSpaApi<AutoLogin, DecodedIdToken, AccessTokenClaims>({
138
+ autoLogin: params.autoLogin,
139
+ decodedIdTokenSchema: params.decodedIdTokenSchema,
140
+ decodedIdToken_mock: params.decodedIdToken_mock,
141
+ createValidateAndGetAccessTokenClaims: params.createValidateAndGetAccessTokenClaims
142
+ })
143
+ };
144
+ }
145
+
146
+ export const oidcSpaApiBuilder = createOidcSpaApiBuilder({
147
+ autoLogin: false,
148
+ createValidateAndGetAccessTokenClaims: undefined,
149
+ decodedIdToken_mock: undefined,
150
+ decodedIdTokenSchema: undefined
151
+ });