oidc-spa 7.2.1 → 7.2.3

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 (257) hide show
  1. package/backend.js.map +1 -1
  2. package/core/AuthResponse.js.map +1 -1
  3. package/core/Oidc.js.map +1 -1
  4. package/core/OidcInitializationError.js.map +1 -1
  5. package/core/OidcMetadata.js.map +1 -1
  6. package/core/StateData.js.map +1 -1
  7. package/core/configId.js.map +1 -1
  8. package/core/createOidc.js +1 -1
  9. package/core/createOidc.js.map +1 -1
  10. package/core/diagnostic.js.map +1 -1
  11. package/core/evtIsUserActive.js.map +1 -1
  12. package/core/handleOidcCallback.js.map +1 -1
  13. package/core/iframeMessageProtection.js.map +1 -1
  14. package/core/index.js.map +1 -1
  15. package/core/initialLocationHref.js.map +1 -1
  16. package/core/isNewBrowserSession.js.map +1 -1
  17. package/core/loginOrGoToAuthServer.js.map +1 -1
  18. package/core/loginPropagationToOtherTabs.js.map +1 -1
  19. package/core/loginSilent.js.map +1 -1
  20. package/core/logoutPropagationToOtherTabs.js.map +1 -1
  21. package/core/oidcClientTsUserToTokens.js.map +1 -1
  22. package/core/ongoingLoginOrRefreshProcesses.js.map +1 -1
  23. package/core/persistedAuthState.js.map +1 -1
  24. package/entrypoint.js.map +1 -1
  25. package/esm/core/AuthResponse.js +2 -2
  26. package/esm/core/AuthResponse.js.map +1 -1
  27. package/esm/core/Oidc.d.ts +1 -1
  28. package/esm/core/Oidc.js.map +1 -1
  29. package/esm/core/OidcInitializationError.js.map +1 -1
  30. package/esm/core/OidcMetadata.js +2 -2
  31. package/esm/core/OidcMetadata.js.map +1 -1
  32. package/esm/core/StateData.js +3 -3
  33. package/esm/core/StateData.js.map +1 -1
  34. package/esm/core/configId.js.map +1 -1
  35. package/esm/core/createOidc.d.ts +2 -2
  36. package/esm/core/createOidc.js +33 -33
  37. package/esm/core/createOidc.js.map +1 -1
  38. package/esm/core/diagnostic.d.ts +1 -1
  39. package/esm/core/diagnostic.js +4 -4
  40. package/esm/core/diagnostic.js.map +1 -1
  41. package/esm/core/evtIsUserActive.d.ts +1 -1
  42. package/esm/core/evtIsUserActive.js +5 -5
  43. package/esm/core/evtIsUserActive.js.map +1 -1
  44. package/esm/core/handleOidcCallback.d.ts +2 -2
  45. package/esm/core/handleOidcCallback.js +5 -5
  46. package/esm/core/handleOidcCallback.js.map +1 -1
  47. package/esm/core/iframeMessageProtection.d.ts +1 -1
  48. package/esm/core/iframeMessageProtection.js +3 -3
  49. package/esm/core/iframeMessageProtection.js.map +1 -1
  50. package/esm/core/index.d.ts +4 -4
  51. package/esm/core/index.js +4 -4
  52. package/esm/core/index.js.map +1 -1
  53. package/esm/core/initialLocationHref.js.map +1 -1
  54. package/esm/core/isNewBrowserSession.d.ts +1 -1
  55. package/esm/core/isNewBrowserSession.js.map +1 -1
  56. package/esm/core/loginOrGoToAuthServer.d.ts +2 -2
  57. package/esm/core/loginOrGoToAuthServer.js +6 -6
  58. package/esm/core/loginOrGoToAuthServer.js.map +1 -1
  59. package/esm/core/loginPropagationToOtherTabs.js +3 -3
  60. package/esm/core/loginPropagationToOtherTabs.js.map +1 -1
  61. package/esm/core/loginSilent.d.ts +2 -2
  62. package/esm/core/loginSilent.js +8 -8
  63. package/esm/core/loginSilent.js.map +1 -1
  64. package/esm/core/logoutPropagationToOtherTabs.js +3 -3
  65. package/esm/core/logoutPropagationToOtherTabs.js.map +1 -1
  66. package/esm/core/oidcClientTsUserToTokens.d.ts +2 -2
  67. package/esm/core/oidcClientTsUserToTokens.js +4 -4
  68. package/esm/core/oidcClientTsUserToTokens.js.map +1 -1
  69. package/esm/core/ongoingLoginOrRefreshProcesses.js +3 -3
  70. package/esm/core/ongoingLoginOrRefreshProcesses.js.map +1 -1
  71. package/esm/core/persistedAuthState.js +2 -2
  72. package/esm/core/persistedAuthState.js.map +1 -1
  73. package/esm/entrypoint.js +3 -3
  74. package/esm/entrypoint.js.map +1 -1
  75. package/esm/index.d.ts +1 -1
  76. package/esm/index.js +2 -2
  77. package/esm/index.js.map +1 -1
  78. package/esm/keycloak/index.d.ts +3 -3
  79. package/esm/keycloak/index.js +3 -3
  80. package/esm/keycloak/index.js.map +1 -1
  81. package/esm/keycloak/isKeycloak.js.map +1 -1
  82. package/esm/keycloak/keycloak-js/Keycloak.d.ts +1 -1
  83. package/esm/keycloak/keycloak-js/Keycloak.js +9 -9
  84. package/esm/keycloak/keycloak-js/Keycloak.js.map +1 -1
  85. package/esm/keycloak/keycloak-js/index.d.ts +2 -2
  86. package/esm/keycloak/keycloak-js/index.js +2 -2
  87. package/esm/keycloak/keycloak-js/index.js.map +1 -1
  88. package/esm/keycloak/keycloak-js/types.js.map +1 -1
  89. package/esm/keycloak/keycloakIssuerUriParsed.js +3 -3
  90. package/esm/keycloak/keycloakIssuerUriParsed.js.map +1 -1
  91. package/esm/keycloak/keycloakUtils.d.ts +1 -1
  92. package/esm/keycloak/keycloakUtils.js +3 -3
  93. package/esm/keycloak/keycloakUtils.js.map +1 -1
  94. package/esm/keycloak-js.d.ts +1 -1
  95. package/esm/keycloak-js.js +2 -2
  96. package/esm/keycloak-js.js.map +1 -1
  97. package/esm/mock/index.d.ts +1 -1
  98. package/esm/mock/index.js +2 -2
  99. package/esm/mock/index.js.map +1 -1
  100. package/esm/mock/oidc.d.ts +1 -1
  101. package/esm/mock/oidc.js +6 -6
  102. package/esm/mock/oidc.js.map +1 -1
  103. package/esm/mock/react.d.ts +8 -8
  104. package/esm/mock/react.js +3 -3
  105. package/esm/mock/react.js.map +1 -1
  106. package/esm/react/index.d.ts +1 -1
  107. package/esm/react/index.js +2 -2
  108. package/esm/react/index.js.map +1 -1
  109. package/esm/react/react.d.ts +2 -2
  110. package/esm/react/react.js +6 -6
  111. package/esm/react/react.js.map +1 -1
  112. package/esm/tools/Deferred.js.map +1 -1
  113. package/esm/tools/EphemeralSessionStorage.js +2 -2
  114. package/esm/tools/EphemeralSessionStorage.js.map +1 -1
  115. package/esm/tools/Evt.js +3 -3
  116. package/esm/tools/Evt.js.map +1 -1
  117. package/esm/tools/StatefulEvt.js.map +1 -1
  118. package/esm/tools/ValueOrAsyncGetter.js.map +1 -1
  119. package/esm/tools/asymmetricEncryption.js.map +1 -1
  120. package/esm/tools/base64.js.map +1 -1
  121. package/esm/tools/createObjectThatThrowsIfAccessed.js.map +1 -1
  122. package/esm/tools/decodeJwt.js.map +1 -1
  123. package/esm/tools/generateUrlSafeRandom.js.map +1 -1
  124. package/esm/tools/getDownlinkAndRtt.js +2 -2
  125. package/esm/tools/getDownlinkAndRtt.js.map +1 -1
  126. package/esm/tools/getIsOnline.js +2 -2
  127. package/esm/tools/getIsOnline.js.map +1 -1
  128. package/esm/tools/getIsValidRemoteJson.js.map +1 -1
  129. package/esm/tools/getPrUserInteraction.js +2 -2
  130. package/esm/tools/getPrUserInteraction.js.map +1 -1
  131. package/esm/tools/getUserEnvironmentInfo.js.map +1 -1
  132. package/esm/tools/haveSharedParentDomain.js.map +1 -1
  133. package/esm/tools/isDev.js.map +1 -1
  134. package/esm/tools/parseKeycloakIssuerUri.js +2 -2
  135. package/esm/tools/parseKeycloakIssuerUri.js.map +1 -1
  136. package/esm/tools/readExpirationTimeInJwt.js +3 -3
  137. package/esm/tools/readExpirationTimeInJwt.js.map +1 -1
  138. package/esm/tools/startCountdown.js +2 -2
  139. package/esm/tools/startCountdown.js.map +1 -1
  140. package/esm/tools/subscribeToUserInteraction.js +2 -2
  141. package/esm/tools/subscribeToUserInteraction.js.map +1 -1
  142. package/esm/tools/toFullyQualifiedUrl.js.map +1 -1
  143. package/esm/tools/toHumanReadableDuration.js.map +1 -1
  144. package/esm/tools/urlSearchParams.js.map +1 -1
  145. package/esm/tools/workerTimers.js +2 -2
  146. package/esm/tools/workerTimers.js.map +1 -1
  147. package/index.js.map +1 -1
  148. package/keycloak/index.js.map +1 -1
  149. package/keycloak/isKeycloak.js.map +1 -1
  150. package/keycloak/keycloak-js/Keycloak.js.map +1 -1
  151. package/keycloak/keycloak-js/index.js.map +1 -1
  152. package/keycloak/keycloak-js/types.js.map +1 -1
  153. package/keycloak/keycloakIssuerUriParsed.js.map +1 -1
  154. package/keycloak/keycloakUtils.js.map +1 -1
  155. package/keycloak-js.js.map +1 -1
  156. package/mock/index.js.map +1 -1
  157. package/mock/oidc.js.map +1 -1
  158. package/mock/react.js.map +1 -1
  159. package/package.json +11 -33
  160. package/react/index.js.map +1 -1
  161. package/react/react.js.map +1 -1
  162. package/src/backend.ts +391 -0
  163. package/src/core/AuthResponse.ts +26 -0
  164. package/src/core/Oidc.ts +140 -0
  165. package/src/core/OidcInitializationError.ts +19 -0
  166. package/src/core/OidcMetadata.ts +271 -0
  167. package/src/core/StateData.ts +118 -0
  168. package/src/core/configId.ts +3 -0
  169. package/src/core/createOidc.ts +1576 -0
  170. package/src/core/diagnostic.ts +267 -0
  171. package/src/core/evtIsUserActive.ts +108 -0
  172. package/src/core/handleOidcCallback.ts +321 -0
  173. package/src/core/iframeMessageProtection.ts +100 -0
  174. package/src/core/index.ts +4 -0
  175. package/src/core/initialLocationHref.ts +5 -0
  176. package/src/core/isNewBrowserSession.ts +37 -0
  177. package/src/core/loginOrGoToAuthServer.ts +324 -0
  178. package/src/core/loginPropagationToOtherTabs.ts +51 -0
  179. package/src/core/loginSilent.ts +242 -0
  180. package/src/core/logoutPropagationToOtherTabs.ts +53 -0
  181. package/src/core/oidcClientTsUserToTokens.ts +229 -0
  182. package/src/core/ongoingLoginOrRefreshProcesses.ts +47 -0
  183. package/src/core/persistedAuthState.ts +122 -0
  184. package/src/entrypoint.ts +69 -0
  185. package/src/index.ts +1 -0
  186. package/src/keycloak/index.ts +8 -0
  187. package/src/keycloak/isKeycloak.ts +23 -0
  188. package/src/keycloak/keycloak-js/Keycloak.ts +1097 -0
  189. package/src/keycloak/keycloak-js/index.ts +2 -0
  190. package/src/keycloak/keycloak-js/types.ts +442 -0
  191. package/src/keycloak/keycloakIssuerUriParsed.ts +29 -0
  192. package/src/keycloak/keycloakUtils.ts +90 -0
  193. package/src/keycloak-js.ts +1 -0
  194. package/src/mock/index.ts +1 -0
  195. package/src/mock/oidc.ts +211 -0
  196. package/src/mock/react.tsx +11 -0
  197. package/src/react/index.ts +1 -0
  198. package/src/react/react.tsx +476 -0
  199. package/src/tools/Deferred.ts +33 -0
  200. package/src/tools/EphemeralSessionStorage.ts +223 -0
  201. package/src/tools/Evt.ts +56 -0
  202. package/src/tools/StatefulEvt.ts +38 -0
  203. package/src/tools/ValueOrAsyncGetter.ts +1 -0
  204. package/src/tools/asymmetricEncryption.ts +184 -0
  205. package/src/tools/base64.ts +7 -0
  206. package/src/tools/createObjectThatThrowsIfAccessed.ts +40 -0
  207. package/src/tools/decodeJwt.ts +95 -0
  208. package/src/tools/generateUrlSafeRandom.ts +26 -0
  209. package/src/tools/getDownlinkAndRtt.ts +22 -0
  210. package/src/tools/getIsOnline.ts +20 -0
  211. package/src/tools/getIsValidRemoteJson.ts +18 -0
  212. package/src/tools/getPrUserInteraction.ts +27 -0
  213. package/src/tools/getUserEnvironmentInfo.ts +42 -0
  214. package/src/tools/haveSharedParentDomain.ts +13 -0
  215. package/src/tools/isDev.ts +30 -0
  216. package/src/tools/parseKeycloakIssuerUri.ts +49 -0
  217. package/src/tools/readExpirationTimeInJwt.ts +16 -0
  218. package/src/tools/startCountdown.ts +36 -0
  219. package/src/tools/subscribeToUserInteraction.ts +33 -0
  220. package/src/tools/toFullyQualifiedUrl.ts +58 -0
  221. package/src/tools/toHumanReadableDuration.ts +21 -0
  222. package/src/tools/urlSearchParams.ts +130 -0
  223. package/src/tools/workerTimers.ts +57 -0
  224. package/src/vendor/backend/evt.ts +2 -0
  225. package/src/vendor/backend/jsonwebtoken.ts +1 -0
  226. package/src/vendor/backend/node-fetch.ts +2 -0
  227. package/src/vendor/backend/node-jose.ts +1 -0
  228. package/src/vendor/backend/tsafe.ts +5 -0
  229. package/src/vendor/backend/zod.ts +1 -0
  230. package/src/vendor/frontend/oidc-client-ts.ts +1 -0
  231. package/src/vendor/frontend/tsafe.ts +6 -0
  232. package/src/vendor/frontend/worker-timers.ts +2 -0
  233. package/tools/Deferred.js.map +1 -1
  234. package/tools/EphemeralSessionStorage.js.map +1 -1
  235. package/tools/Evt.js.map +1 -1
  236. package/tools/StatefulEvt.js.map +1 -1
  237. package/tools/ValueOrAsyncGetter.js.map +1 -1
  238. package/tools/asymmetricEncryption.js.map +1 -1
  239. package/tools/base64.js.map +1 -1
  240. package/tools/createObjectThatThrowsIfAccessed.js.map +1 -1
  241. package/tools/decodeJwt.js.map +1 -1
  242. package/tools/generateUrlSafeRandom.js.map +1 -1
  243. package/tools/getDownlinkAndRtt.js.map +1 -1
  244. package/tools/getIsOnline.js.map +1 -1
  245. package/tools/getIsValidRemoteJson.js.map +1 -1
  246. package/tools/getPrUserInteraction.js.map +1 -1
  247. package/tools/getUserEnvironmentInfo.js.map +1 -1
  248. package/tools/haveSharedParentDomain.js.map +1 -1
  249. package/tools/isDev.js.map +1 -1
  250. package/tools/parseKeycloakIssuerUri.js.map +1 -1
  251. package/tools/readExpirationTimeInJwt.js.map +1 -1
  252. package/tools/startCountdown.js.map +1 -1
  253. package/tools/subscribeToUserInteraction.js.map +1 -1
  254. package/tools/toFullyQualifiedUrl.js.map +1 -1
  255. package/tools/toHumanReadableDuration.js.map +1 -1
  256. package/tools/urlSearchParams.js.map +1 -1
  257. package/tools/workerTimers.js.map +1 -1
@@ -0,0 +1,1576 @@
1
+ import {
2
+ UserManager as OidcClientTsUserManager,
3
+ WebStorageStateStore,
4
+ type User as OidcClientTsUser,
5
+ InMemoryWebStorage
6
+ } from "../vendor/frontend/oidc-client-ts";
7
+ import type { OidcMetadata } from "./OidcMetadata";
8
+ import { id, assert, is, type Equals } from "../vendor/frontend/tsafe";
9
+ import { setTimeout, clearTimeout } from "../tools/workerTimers";
10
+ import { Deferred } from "../tools/Deferred";
11
+ import { createEvtIsUserActive } from "./evtIsUserActive";
12
+ import { createStartCountdown } from "../tools/startCountdown";
13
+ import { toHumanReadableDuration } from "../tools/toHumanReadableDuration";
14
+ import { toFullyQualifiedUrl } from "../tools/toFullyQualifiedUrl";
15
+ import { OidcInitializationError } from "./OidcInitializationError";
16
+ import { type StateData, generateStateUrlParamValue, STATE_STORE_KEY_PREFIX } from "./StateData";
17
+ import { notifyOtherTabsOfLogout, getPrOtherTabLogout } from "./logoutPropagationToOtherTabs";
18
+ import { notifyOtherTabsOfLogin, getPrOtherTabLogin } from "./loginPropagationToOtherTabs";
19
+ import { getConfigId } from "./configId";
20
+ import { oidcClientTsUserToTokens } from "./oidcClientTsUserToTokens";
21
+ import { loginSilent } from "./loginSilent";
22
+ import { authResponseToUrl } from "./AuthResponse";
23
+ import { handleOidcCallback, retrieveRedirectAuthResponseAndStateData } from "./handleOidcCallback";
24
+ import { getPersistedAuthState, persistAuthState } from "./persistedAuthState";
25
+ import type { Oidc } from "./Oidc";
26
+ import { createEvt } from "../tools/Evt";
27
+ import { getHaveSharedParentDomain } from "../tools/haveSharedParentDomain";
28
+ import {
29
+ createLoginOrGoToAuthServer,
30
+ getPrSafelyRestoredFromBfCacheAfterLoginBackNavigation
31
+ } from "./loginOrGoToAuthServer";
32
+ import { createEphemeralSessionStorage } from "../tools/EphemeralSessionStorage";
33
+ import {
34
+ startLoginOrRefreshProcess,
35
+ waitForAllOtherOngoingLoginOrRefreshProcessesToComplete
36
+ } from "./ongoingLoginOrRefreshProcesses";
37
+ import { initialLocationHref } from "./initialLocationHref";
38
+ import { createGetIsNewBrowserSession } from "./isNewBrowserSession";
39
+ import { getIsOnline } from "../tools/getIsOnline";
40
+ import { isKeycloak } from "../keycloak/isKeycloak";
41
+
42
+ // NOTE: Replaced at build time
43
+ const VERSION = "{{OIDC_SPA_VERSION}}";
44
+
45
+ export type ParamsOfCreateOidc<
46
+ DecodedIdToken extends Record<string, unknown> = Record<string, unknown>,
47
+ AutoLogin extends boolean = false
48
+ > = {
49
+ issuerUri: string;
50
+ clientId: string;
51
+ /**
52
+ * The scopes being requested from the OIDC/OAuth2 provider (default: `["profile"]`
53
+ * (the scope "openid" is added automatically as it's mandatory)
54
+ **/
55
+ scopes?: string[];
56
+
57
+ /**
58
+ * Transform the url (authorization endpoint) before redirecting to the login pages.
59
+ *
60
+ * The isSilent parameter is true when the redirect is initiated in the background iframe for silent signin.
61
+ * This can be used to omit ui related query parameters (like `ui_locales`).
62
+ */
63
+ transformUrlBeforeRedirect?: (params: { authorizationUrl: string; isSilent: boolean }) => string;
64
+
65
+ /**
66
+ * Extra query params to be added to the authorization endpoint url before redirecting or silent signing in.
67
+ * You can provide a function that returns those extra query params, it will be called
68
+ * when login() is called.
69
+ *
70
+ * Example: extraQueryParams: ()=> ({ ui_locales: "fr" })
71
+ *
72
+ * This parameter can also be passed to login() directly.
73
+ */
74
+ extraQueryParams?:
75
+ | Record<string, string | undefined>
76
+ | ((params: { isSilent: boolean; url: string }) => Record<string, string | undefined>);
77
+ /**
78
+ * Extra body params to be added to the /token POST request.
79
+ *
80
+ * It will be used when for the initial request, whenever the token is getting refreshed and if you call `renewTokens()`.
81
+ * You can also provide this parameter directly to the `renewTokens()` method.
82
+ *
83
+ * It can be either a string to string record or a function that returns a string to string record.
84
+ *
85
+ * Example: extraTokenParams: ()=> ({ selectedCustomer: "xxx" })
86
+ * extraTokenParams: { selectedCustomer: "xxx" }
87
+ */
88
+ extraTokenParams?: Record<string, string | undefined> | (() => Record<string, string | undefined>);
89
+ /**
90
+ * Usage discouraged, it's here because we don't want to assume too much on your
91
+ * usecase but I can't think of a scenario where you would want anything
92
+ * other than the current page.
93
+ *
94
+ * Where to redirect after successful login.
95
+ * Default: window.location.href (here)
96
+ *
97
+ * It does not need to include the origin, eg: "/dashboard"
98
+ *
99
+ * This parameter can also be passed to login() directly as `redirectUrl`.
100
+ */
101
+ postLoginRedirectUrl?: string;
102
+
103
+ /**
104
+ * What should you put in this parameter?
105
+ * - Vite project: `BASE_URL: import.meta.env.BASE_URL`
106
+ * - Create React App project: `BASE_URL: process.env.PUBLIC_URL`
107
+ * - Other: `BASE_URL: "/"` (Usually, or `/dashboard` if your app is not at the root of the domain)
108
+ */
109
+ homeUrl: string;
110
+
111
+ decodedIdTokenSchema?: {
112
+ parse: (decodedIdToken_original: Oidc.Tokens.DecodedIdToken_base) => DecodedIdToken;
113
+ };
114
+
115
+ /**
116
+ * This parameter defines after how many seconds of inactivity the user should be
117
+ * logged out automatically.
118
+ *
119
+ * WARNING: It should be configured on the identity server side
120
+ * as it's the authoritative source for security policies and not the client.
121
+ * If you don't provide this parameter it will be inferred from the refresh token expiration time.
122
+ * */
123
+ idleSessionLifetimeInSeconds?: number;
124
+
125
+ /**
126
+ * Usage discouraged, this parameter exists because we don't want to assume
127
+ * too much about your usecase but I can't think of a scenario where you would
128
+ * want anything other than the current page.
129
+ *
130
+ * Default: { redirectTo: "current page" }
131
+ */
132
+ autoLogoutParams?: Parameters<Oidc.LoggedIn<any>["logout"]>[0];
133
+ autoLogin?: AutoLogin;
134
+
135
+ /**
136
+ * Default: false
137
+ *
138
+ * See: https://docs.oidc-spa.dev/v/v7/resources/iframe-related-issues
139
+ */
140
+ noIframe?: boolean;
141
+
142
+ debugLogs?: boolean;
143
+
144
+ /**
145
+ * WARNING: This option exists solely as a workaround
146
+ * for limitations in the Google OAuth API.
147
+ * See: https://docs.oidc-spa.dev/providers-configuration/google-oauth
148
+ *
149
+ * Do not use this for other providers.
150
+ * If you think you need a client secret in a SPA, you are likely
151
+ * trying to use a confidential (private) client in the browser,
152
+ * which is insecure and not supported.
153
+ */
154
+ __unsafe_clientSecret?: string;
155
+
156
+ /**
157
+ * WARNING: Setting this to true is a workaround for provider
158
+ * like Google OAuth that don't support JWT access token.
159
+ * Use at your own risk, this is a hack.
160
+ */
161
+ __unsafe_useIdTokenAsAccessToken?: boolean;
162
+
163
+ /**
164
+ * This option should only be used as a last resort.
165
+ *
166
+ * If your OIDC provider is correctly configured, this should not be necessary.
167
+ *
168
+ * The metadata is normally retrieved automatically from:
169
+ * `${issuerUri}/.well-known/openid-configuration`
170
+ *
171
+ * Use this only if that endpoint is not accessible (e.g. due to missing CORS headers
172
+ * or non-standard deployments), and you cannot fix the server-side configuration.
173
+ */
174
+ __metadata?: Partial<OidcMetadata>;
175
+ };
176
+
177
+ const globalContext = {
178
+ prOidcByConfigId: new Map<string, Promise<Oidc<any>>>(),
179
+ hasLogoutBeenCalled: id<boolean>(false),
180
+ evtRequestToPersistTokens: createEvt<{ configIdOfInstancePostingTheRequest: string }>()
181
+ };
182
+
183
+ /** @see: https://docs.oidc-spa.dev/v/v7/usage */
184
+ export async function createOidc<
185
+ DecodedIdToken extends Record<string, unknown> = Record<string, unknown>,
186
+ AutoLogin extends boolean = false
187
+ >(
188
+ params: ParamsOfCreateOidc<DecodedIdToken, AutoLogin>
189
+ ): Promise<AutoLogin extends true ? Oidc.LoggedIn<DecodedIdToken> : Oidc<DecodedIdToken>> {
190
+ for (const name of ["issuerUri", "clientId"] as const) {
191
+ const value = params[name];
192
+ if (!value) {
193
+ throw new Error(
194
+ `The parameter "${name}" is required, you provided: ${value}. (Forgot a .env variable?)`
195
+ );
196
+ }
197
+ }
198
+
199
+ const { issuerUri: issuerUri_params, clientId, scopes = ["profile"], debugLogs, ...rest } = params;
200
+
201
+ const issuerUri = toFullyQualifiedUrl({
202
+ urlish: issuerUri_params,
203
+ doAssertNoQueryParams: true,
204
+ doOutputWithTrailingSlash: false
205
+ });
206
+
207
+ const log = (() => {
208
+ if (!debugLogs) {
209
+ return undefined;
210
+ }
211
+
212
+ return id<typeof console.log>((...[first, ...rest]) => {
213
+ const label = "oidc-spa";
214
+
215
+ if (typeof first === "string") {
216
+ console.log(...[`${label}: ${first}`, ...rest]);
217
+ } else {
218
+ console.log(...[`${label}:`, first, ...rest]);
219
+ }
220
+ });
221
+ })();
222
+
223
+ const configId = getConfigId({ issuerUri, clientId });
224
+
225
+ const { prOidcByConfigId } = globalContext;
226
+
227
+ use_previous_instance: {
228
+ const prOidc = prOidcByConfigId.get(configId);
229
+
230
+ if (prOidc === undefined) {
231
+ break use_previous_instance;
232
+ }
233
+
234
+ log?.(
235
+ [
236
+ `createOidc was called again with the same config (${JSON.stringify({
237
+ issuerUri,
238
+ clientId
239
+ })})`,
240
+ `Returning the previous instance. All potential different parameters are ignored.`
241
+ ].join(" ")
242
+ );
243
+
244
+ // @ts-expect-error: We know what we're doing
245
+ return prOidc;
246
+ }
247
+
248
+ const dOidc = new Deferred<Oidc<any>>();
249
+
250
+ prOidcByConfigId.set(configId, dOidc.pr);
251
+
252
+ const oidc = await createOidc_nonMemoized(rest, {
253
+ issuerUri,
254
+ clientId,
255
+ scopes,
256
+ configId,
257
+ log
258
+ });
259
+
260
+ dOidc.resolve(oidc);
261
+
262
+ return oidc;
263
+ }
264
+
265
+ export async function createOidc_nonMemoized<
266
+ DecodedIdToken extends Record<string, unknown> = Record<string, unknown>,
267
+ AutoLogin extends boolean = false
268
+ >(
269
+ params: Omit<
270
+ ParamsOfCreateOidc<DecodedIdToken, AutoLogin>,
271
+ "issuerUri" | "clientId" | "scopes" | "debugLogs"
272
+ >,
273
+ preProcessedParams: {
274
+ issuerUri: string;
275
+ clientId: string;
276
+ scopes: string[];
277
+ configId: string;
278
+ log: typeof console.log | undefined;
279
+ }
280
+ ): Promise<AutoLogin extends true ? Oidc.LoggedIn<DecodedIdToken> : Oidc<DecodedIdToken>> {
281
+ const {
282
+ transformUrlBeforeRedirect,
283
+ extraQueryParams: extraQueryParamsOrGetter,
284
+ extraTokenParams: extraTokenParamsOrGetter,
285
+ homeUrl: homeUrl_params,
286
+ decodedIdTokenSchema,
287
+ idleSessionLifetimeInSeconds,
288
+ autoLogoutParams = { redirectTo: "current page" },
289
+ autoLogin = false,
290
+ postLoginRedirectUrl: postLoginRedirectUrl_default,
291
+ __unsafe_clientSecret,
292
+ __unsafe_useIdTokenAsAccessToken = false,
293
+ __metadata,
294
+ noIframe = false
295
+ } = params;
296
+
297
+ const { issuerUri, clientId, scopes, configId, log } = preProcessedParams;
298
+
299
+ const getExtraQueryParams = (() => {
300
+ if (extraQueryParamsOrGetter === undefined) {
301
+ return undefined;
302
+ }
303
+
304
+ if (typeof extraQueryParamsOrGetter !== "function") {
305
+ return () => extraQueryParamsOrGetter;
306
+ }
307
+
308
+ return extraQueryParamsOrGetter;
309
+ })();
310
+
311
+ const getExtraTokenParams = (() => {
312
+ if (extraTokenParamsOrGetter === undefined) {
313
+ return undefined;
314
+ }
315
+
316
+ if (typeof extraTokenParamsOrGetter !== "function") {
317
+ return () => extraTokenParamsOrGetter;
318
+ }
319
+
320
+ return extraTokenParamsOrGetter;
321
+ })();
322
+
323
+ const homeUrlAndRedirectUri = toFullyQualifiedUrl({
324
+ urlish: homeUrl_params,
325
+ doAssertNoQueryParams: true,
326
+ doOutputWithTrailingSlash: true
327
+ });
328
+
329
+ log?.(
330
+ `Calling createOidc v${VERSION} ${JSON.stringify(
331
+ {
332
+ issuerUri,
333
+ clientId,
334
+ scopes,
335
+ configId,
336
+ homeUrlAndRedirectUri
337
+ },
338
+ null,
339
+ 2
340
+ )}`
341
+ );
342
+
343
+ {
344
+ const { isHandled } = handleOidcCallback();
345
+
346
+ if (isHandled) {
347
+ await new Promise<never>(() => {});
348
+ }
349
+ }
350
+
351
+ const stateUrlParamValue_instance = generateStateUrlParamValue();
352
+
353
+ const canUseIframe = (() => {
354
+ if (noIframe) {
355
+ return false;
356
+ }
357
+
358
+ third_party_cookies: {
359
+ const isOidcServerThirdPartyRelativeToApp =
360
+ getHaveSharedParentDomain({
361
+ url1: window.location.origin,
362
+ url2: issuerUri
363
+ }) === false;
364
+
365
+ if (!isOidcServerThirdPartyRelativeToApp) {
366
+ break third_party_cookies;
367
+ }
368
+
369
+ const isGoogleChrome = (() => {
370
+ const ua = navigator.userAgent;
371
+ const vendor = navigator.vendor;
372
+
373
+ return (
374
+ /Chrome/.test(ua) && /Google Inc/.test(vendor) && !/Edg/.test(ua) && !/OPR/.test(ua)
375
+ );
376
+ })();
377
+
378
+ if (window.location.origin.startsWith("http://localhost") && isGoogleChrome) {
379
+ break third_party_cookies;
380
+ }
381
+
382
+ log?.(
383
+ [
384
+ "Can't use iframe because your auth server is on a third party domain relative",
385
+ "to the domain of your app and third party cookies are blocked by navigators."
386
+ ].join(" ")
387
+ );
388
+
389
+ return false;
390
+ }
391
+
392
+ // NOTE: Maybe not, it depend if the app can iframe itself.
393
+ return true;
394
+ })();
395
+
396
+ let isUserStoreInMemoryOnly: boolean;
397
+
398
+ const oidcClientTsUserManager = new OidcClientTsUserManager({
399
+ stateUrlParamValue: stateUrlParamValue_instance,
400
+ authority: issuerUri,
401
+ client_id: clientId,
402
+ redirect_uri: homeUrlAndRedirectUri,
403
+ silent_redirect_uri: homeUrlAndRedirectUri,
404
+ post_logout_redirect_uri: homeUrlAndRedirectUri,
405
+ response_mode: isKeycloak({ issuerUri }) ? "fragment" : "query",
406
+ response_type: "code",
407
+ scope: Array.from(new Set(["openid", ...scopes])).join(" "),
408
+ automaticSilentRenew: false,
409
+ userStore: new WebStorageStateStore({
410
+ store: (() => {
411
+ if (canUseIframe) {
412
+ isUserStoreInMemoryOnly = true;
413
+ return new InMemoryWebStorage();
414
+ }
415
+
416
+ isUserStoreInMemoryOnly = false;
417
+
418
+ const storage = createEphemeralSessionStorage({
419
+ sessionStorageTtlMs: 3 * 60_000
420
+ });
421
+
422
+ const { evtRequestToPersistTokens } = globalContext;
423
+
424
+ evtRequestToPersistTokens.subscribe(({ configIdOfInstancePostingTheRequest }) => {
425
+ if (configIdOfInstancePostingTheRequest === configId) {
426
+ return;
427
+ }
428
+
429
+ storage.persistCurrentStateAndSubsequentChanges();
430
+ });
431
+
432
+ return storage;
433
+ })()
434
+ }),
435
+ stateStore: new WebStorageStateStore({ store: localStorage, prefix: STATE_STORE_KEY_PREFIX }),
436
+ client_secret: __unsafe_clientSecret,
437
+ metadata: __metadata
438
+ });
439
+
440
+ const evtIsUserLoggedIn = createEvt<boolean>();
441
+
442
+ const { loginOrGoToAuthServer } = createLoginOrGoToAuthServer({
443
+ configId,
444
+ oidcClientTsUserManager,
445
+ transformUrlBeforeRedirect,
446
+ getExtraQueryParams,
447
+ getExtraTokenParams,
448
+ homeUrl: homeUrlAndRedirectUri,
449
+ evtIsUserLoggedIn,
450
+ log
451
+ });
452
+
453
+ const { getIsNewBrowserSession } = createGetIsNewBrowserSession({
454
+ configId,
455
+ evtUserNotLoggedIn: (() => {
456
+ const evt = createEvt<void>();
457
+
458
+ evtIsUserLoggedIn.subscribe(isUserLoggedIn => {
459
+ if (!isUserLoggedIn) {
460
+ evt.post();
461
+ }
462
+ });
463
+
464
+ return evt;
465
+ })()
466
+ });
467
+
468
+ const { completeLoginOrRefreshProcess } = await startLoginOrRefreshProcess();
469
+
470
+ const resultOfLoginProcess = await (async (): Promise<
471
+ | undefined // User is currently not logged in
472
+ | Error // Initialization error
473
+ | {
474
+ oidcClientTsUser: OidcClientTsUser;
475
+ backFromAuthServer: Oidc.LoggedIn["backFromAuthServer"]; // Undefined is silent signin
476
+ }
477
+ > => {
478
+ handle_redirect_auth_response: {
479
+ const authResponseAndStateData = retrieveRedirectAuthResponseAndStateData({ configId });
480
+
481
+ if (authResponseAndStateData === undefined) {
482
+ break handle_redirect_auth_response;
483
+ }
484
+
485
+ const { authResponse, stateData } = authResponseAndStateData;
486
+
487
+ switch (stateData.action) {
488
+ case "login":
489
+ {
490
+ log?.(
491
+ `Handling login redirect auth response ${JSON.stringify(
492
+ authResponse,
493
+ null,
494
+ 2
495
+ )}`
496
+ );
497
+
498
+ const authResponseUrl = authResponseToUrl(authResponse);
499
+
500
+ let oidcClientTsUser: OidcClientTsUser | undefined = undefined;
501
+
502
+ try {
503
+ oidcClientTsUser = await oidcClientTsUserManager.signinRedirectCallback(
504
+ authResponseUrl
505
+ );
506
+ } catch (error) {
507
+ assert(error instanceof Error, "741947");
508
+
509
+ if (error.message === "Failed to fetch") {
510
+ return (
511
+ await import("./diagnostic")
512
+ ).createFailedToFetchTokenEndpointInitializationError({
513
+ clientId,
514
+ issuerUri
515
+ });
516
+ }
517
+
518
+ {
519
+ const authResponse_error = authResponse.error;
520
+
521
+ if (authResponse_error !== undefined) {
522
+ log?.(
523
+ `The auth server responded with: ${authResponse_error}, trying to restore from the http only cookie`
524
+ );
525
+ break handle_redirect_auth_response;
526
+ }
527
+ }
528
+
529
+ return error;
530
+ }
531
+
532
+ notifyOtherTabsOfLogin({ configId });
533
+
534
+ return {
535
+ oidcClientTsUser,
536
+ backFromAuthServer: {
537
+ extraQueryParams: stateData.extraQueryParams,
538
+ result: Object.fromEntries(
539
+ Object.entries(authResponse)
540
+ .map(([name, value]) => {
541
+ if (
542
+ name === "state" ||
543
+ name === "session_state" ||
544
+ name === "iss" ||
545
+ name === "code"
546
+ ) {
547
+ return undefined;
548
+ }
549
+
550
+ if (value === undefined) {
551
+ return undefined;
552
+ }
553
+
554
+ return [name, value];
555
+ })
556
+ .filter(entry => entry !== undefined)
557
+ )
558
+ }
559
+ };
560
+ }
561
+ break;
562
+ case "logout":
563
+ {
564
+ log?.("Handling logout redirect auth response", authResponse);
565
+
566
+ const authResponseUrl = authResponseToUrl(authResponse);
567
+
568
+ try {
569
+ await oidcClientTsUserManager.signoutRedirectCallback(authResponseUrl);
570
+ } catch {}
571
+
572
+ notifyOtherTabsOfLogout({
573
+ configId,
574
+ sessionId: stateData.sessionId
575
+ });
576
+
577
+ if (autoLogin) {
578
+ location.reload();
579
+ await new Promise<never>(() => {});
580
+ }
581
+
582
+ // NOTE: The user is no longer logged in.
583
+ return undefined;
584
+ }
585
+ break;
586
+ }
587
+ }
588
+
589
+ restore_from_session_storage: {
590
+ if (isUserStoreInMemoryOnly) {
591
+ break restore_from_session_storage;
592
+ }
593
+
594
+ let oidcClientTsUser: OidcClientTsUser | null;
595
+
596
+ try {
597
+ oidcClientTsUser = await oidcClientTsUserManager.getUser();
598
+ } catch {
599
+ // NOTE: Not sure if it can throw, but let's be safe.
600
+ oidcClientTsUser = null;
601
+ try {
602
+ await oidcClientTsUserManager.removeUser();
603
+ } catch {}
604
+ }
605
+
606
+ if (oidcClientTsUser === null) {
607
+ break restore_from_session_storage;
608
+ }
609
+
610
+ log?.("Restored the auth from ephemeral session storage");
611
+
612
+ return {
613
+ oidcClientTsUser,
614
+ backFromAuthServer: undefined
615
+ };
616
+ }
617
+
618
+ silent_login_if_possible_and_auto_login: {
619
+ const persistedAuthState = getPersistedAuthState({ configId });
620
+
621
+ if (persistedAuthState === "explicitly logged out" && !autoLogin) {
622
+ log?.("Skipping silent signin with iframe, the user has logged out");
623
+ break silent_login_if_possible_and_auto_login;
624
+ }
625
+
626
+ {
627
+ const { isOnline, prOnline } = getIsOnline();
628
+
629
+ if (!isOnline) {
630
+ if (autoLogin) {
631
+ log?.(
632
+ [
633
+ "The browser is currently offline",
634
+ "Since autoLogin is enabled we wait until it comes back online",
635
+ "to continue with authentication"
636
+ ].join(" ")
637
+ );
638
+ await prOnline;
639
+ } else {
640
+ log?.(
641
+ [
642
+ "The browser is not currently online so we proceed with initialization",
643
+ "assuming the user isn't authenticated"
644
+ ].join(" ")
645
+ );
646
+ break silent_login_if_possible_and_auto_login;
647
+ }
648
+ }
649
+ }
650
+
651
+ let authResponse_error: string | undefined = undefined;
652
+ let oidcClientTsUser: OidcClientTsUser | undefined = undefined;
653
+
654
+ actual_silent_signin: {
655
+ if (persistedAuthState === "explicitly logged out") {
656
+ break actual_silent_signin;
657
+ }
658
+
659
+ if (!canUseIframe) {
660
+ break actual_silent_signin;
661
+ }
662
+
663
+ log?.(
664
+ "Trying to restore the auth from the http only cookie (silent signin with iframe)"
665
+ );
666
+
667
+ const result_loginSilent = await loginSilent({
668
+ oidcClientTsUserManager,
669
+ stateUrlParamValue_instance,
670
+ configId,
671
+ transformUrlBeforeRedirect,
672
+ getExtraQueryParams,
673
+ getExtraTokenParams,
674
+ autoLogin
675
+ });
676
+
677
+ assert(result_loginSilent.outcome !== "token refreshed using refresh token", "876995");
678
+
679
+ if (result_loginSilent.outcome === "failure") {
680
+ switch (result_loginSilent.cause) {
681
+ case "can't reach well-known oidc endpoint":
682
+ return (
683
+ await import("./diagnostic")
684
+ ).createWellKnownOidcConfigurationEndpointUnreachableInitializationError({
685
+ issuerUri
686
+ });
687
+ case "timeout":
688
+ return (await import("./diagnostic")).createIframeTimeoutInitializationError(
689
+ {
690
+ redirectUri: homeUrlAndRedirectUri,
691
+ clientId,
692
+ issuerUri,
693
+ noIframe
694
+ }
695
+ );
696
+ }
697
+
698
+ assert<Equals<typeof result_loginSilent.cause, never>>(false);
699
+ }
700
+
701
+ assert<Equals<typeof result_loginSilent.outcome, "got auth response from iframe">>();
702
+
703
+ const { authResponse } = result_loginSilent;
704
+
705
+ log?.(`Silent signin auth response ${JSON.stringify(authResponse, null, 2)}`);
706
+
707
+ authResponse_error = authResponse.error;
708
+
709
+ try {
710
+ oidcClientTsUser = await oidcClientTsUserManager.signinRedirectCallback(
711
+ authResponseToUrl(authResponse)
712
+ );
713
+ } catch (error) {
714
+ assert(error instanceof Error, "433344");
715
+
716
+ if (error.message === "Failed to fetch") {
717
+ return (
718
+ await import("./diagnostic")
719
+ ).createFailedToFetchTokenEndpointInitializationError({
720
+ clientId,
721
+ issuerUri
722
+ });
723
+ }
724
+
725
+ if (authResponse_error === undefined) {
726
+ return error;
727
+ }
728
+ }
729
+ }
730
+
731
+ if (oidcClientTsUser === undefined) {
732
+ if (
733
+ autoLogin ||
734
+ (persistedAuthState === "logged in" &&
735
+ (authResponse_error === undefined ||
736
+ authResponse_error === "interaction_required" ||
737
+ authResponse_error === "login_required" ||
738
+ authResponse_error === "consent_required" ||
739
+ authResponse_error === "account_selection_required"))
740
+ ) {
741
+ log?.("Performing auto login with redirect");
742
+
743
+ persistAuthState({ configId, state: undefined });
744
+
745
+ completeLoginOrRefreshProcess();
746
+
747
+ if (autoLogin && persistedAuthState !== "logged in") {
748
+ evtIsUserLoggedIn.post(false);
749
+ }
750
+
751
+ await waitForAllOtherOngoingLoginOrRefreshProcessesToComplete({
752
+ prUnlock: new Promise<never>(() => {})
753
+ });
754
+
755
+ if (persistedAuthState === "logged in") {
756
+ globalContext.evtRequestToPersistTokens.post({
757
+ configIdOfInstancePostingTheRequest: configId
758
+ });
759
+ }
760
+
761
+ await loginOrGoToAuthServer({
762
+ action: "login",
763
+ doForceReloadOnBfCache: true,
764
+ redirectUrl: initialLocationHref,
765
+ // NOTE: Wether or not it's the preferred behavior, pushing to history
766
+ // only works on user interaction so it have to be false
767
+ doNavigateBackToLastPublicUrlIfTheTheUserNavigateBack: false,
768
+ extraQueryParams_local: undefined,
769
+ transformUrlBeforeRedirect_local: undefined,
770
+ interaction: (() => {
771
+ if (persistedAuthState === "explicitly logged out") {
772
+ return "ensure interaction";
773
+ }
774
+
775
+ if (autoLogin) {
776
+ return "directly redirect if active session show login otherwise";
777
+ }
778
+
779
+ return "ensure no interaction";
780
+ })()
781
+ });
782
+ assert(false, "321389");
783
+ }
784
+
785
+ if (authResponse_error !== undefined) {
786
+ log?.(
787
+ [
788
+ `The auth server responded with: ${authResponse_error} `,
789
+ "login_required" === authResponse_error
790
+ ? `(login_required just means that there's no active session for the user)`
791
+ : ""
792
+ ].join("")
793
+ );
794
+ }
795
+
796
+ break silent_login_if_possible_and_auto_login;
797
+ }
798
+
799
+ log?.("Successful silent signed in");
800
+
801
+ return {
802
+ oidcClientTsUser,
803
+ backFromAuthServer: undefined
804
+ };
805
+ }
806
+
807
+ // NOTE: The user is not logged in.
808
+ return undefined;
809
+ })();
810
+
811
+ completeLoginOrRefreshProcess();
812
+
813
+ await waitForAllOtherOngoingLoginOrRefreshProcessesToComplete({
814
+ prUnlock: Promise.resolve()
815
+ });
816
+
817
+ const oidc_common: Oidc.Common = {
818
+ params: {
819
+ issuerUri,
820
+ clientId
821
+ }
822
+ };
823
+
824
+ not_loggedIn_case: {
825
+ if (!(resultOfLoginProcess instanceof Error) && resultOfLoginProcess !== undefined) {
826
+ break not_loggedIn_case;
827
+ }
828
+
829
+ evtIsUserLoggedIn.post(false);
830
+
831
+ if (getPersistedAuthState({ configId }) !== "explicitly logged out") {
832
+ persistAuthState({ configId, state: undefined });
833
+ }
834
+
835
+ const oidc_notLoggedIn: Oidc.NotLoggedIn = (() => {
836
+ if (resultOfLoginProcess instanceof Error) {
837
+ log?.("User not logged in and there was an initialization error");
838
+
839
+ const error = resultOfLoginProcess;
840
+
841
+ const initializationError =
842
+ error instanceof OidcInitializationError
843
+ ? error
844
+ : new OidcInitializationError({
845
+ isAuthServerLikelyDown: false,
846
+ messageOrCause: error
847
+ });
848
+
849
+ if (autoLogin) {
850
+ throw initializationError;
851
+ }
852
+
853
+ console.error(
854
+ [
855
+ `oidc-spa Initialization Error: `,
856
+ `isAuthServerLikelyDown: ${initializationError.isAuthServerLikelyDown}`,
857
+ ``,
858
+ initializationError.message
859
+ ].join("\n")
860
+ );
861
+
862
+ return id<Oidc.NotLoggedIn>({
863
+ ...oidc_common,
864
+ isUserLoggedIn: false,
865
+ login: async () => {
866
+ alert("Authentication is currently unavailable. Please try again later.");
867
+ return new Promise<never>(() => {});
868
+ },
869
+ initializationError
870
+ });
871
+ }
872
+
873
+ if (resultOfLoginProcess === undefined) {
874
+ log?.("User not logged in");
875
+
876
+ return id<Oidc.NotLoggedIn>({
877
+ ...oidc_common,
878
+ isUserLoggedIn: false,
879
+ login: async ({
880
+ doesCurrentHrefRequiresAuth,
881
+ extraQueryParams,
882
+ redirectUrl,
883
+ transformUrlBeforeRedirect
884
+ }) => {
885
+ await waitForAllOtherOngoingLoginOrRefreshProcessesToComplete({
886
+ prUnlock: getPrSafelyRestoredFromBfCacheAfterLoginBackNavigation()
887
+ });
888
+
889
+ return loginOrGoToAuthServer({
890
+ action: "login",
891
+ doNavigateBackToLastPublicUrlIfTheTheUserNavigateBack:
892
+ doesCurrentHrefRequiresAuth,
893
+ doForceReloadOnBfCache: false,
894
+ redirectUrl:
895
+ redirectUrl ?? postLoginRedirectUrl_default ?? window.location.href,
896
+ extraQueryParams_local: extraQueryParams,
897
+ transformUrlBeforeRedirect_local: transformUrlBeforeRedirect,
898
+ interaction:
899
+ getPersistedAuthState({ configId }) === "explicitly logged out"
900
+ ? "ensure interaction"
901
+ : "directly redirect if active session show login otherwise"
902
+ });
903
+ },
904
+ initializationError: undefined
905
+ });
906
+ }
907
+
908
+ assert<Equals<typeof resultOfLoginProcess, never>>(false);
909
+ })();
910
+
911
+ {
912
+ const { prOtherTabLogin } = getPrOtherTabLogin({
913
+ configId
914
+ });
915
+
916
+ prOtherTabLogin.then(async () => {
917
+ log?.(`Other tab has logged in, reloading this tab`);
918
+
919
+ await waitForAllOtherOngoingLoginOrRefreshProcessesToComplete({
920
+ prUnlock: new Promise<never>(() => {})
921
+ });
922
+
923
+ window.location.reload();
924
+ });
925
+ }
926
+
927
+ // @ts-expect-error: We know what we're doing
928
+ return oidc_notLoggedIn;
929
+ }
930
+
931
+ log?.("User is logged in");
932
+
933
+ evtIsUserLoggedIn.post(true);
934
+
935
+ let currentTokens = oidcClientTsUserToTokens({
936
+ oidcClientTsUser: resultOfLoginProcess.oidcClientTsUser,
937
+ decodedIdTokenSchema,
938
+ __unsafe_useIdTokenAsAccessToken,
939
+ decodedIdToken_previous: undefined,
940
+ log
941
+ });
942
+
943
+ {
944
+ if (getPersistedAuthState({ configId }) !== undefined) {
945
+ persistAuthState({ configId, state: undefined });
946
+ }
947
+
948
+ if (!canUseIframe) {
949
+ persistAuthState({
950
+ configId,
951
+ state: {
952
+ stateDescription: "logged in",
953
+ refreshTokenExpirationTime: currentTokens.refreshTokenExpirationTime,
954
+ idleSessionLifetimeInSeconds
955
+ }
956
+ });
957
+ }
958
+ }
959
+
960
+ const autoLogoutCountdownTickCallbacks = new Set<
961
+ (params: { secondsLeft: number | undefined }) => void
962
+ >();
963
+
964
+ const onTokenChanges = new Set<(tokens: Oidc.Tokens<DecodedIdToken>) => void>();
965
+
966
+ const { sid: sessionId, sub: subjectId } = currentTokens.decodedIdToken_original;
967
+
968
+ assert(subjectId !== undefined, "The 'sub' claim is missing from the id token");
969
+ assert(sessionId === undefined || typeof sessionId === "string");
970
+
971
+ let wouldHaveAutoLoggedOutIfBrowserWasOnline = false;
972
+
973
+ const oidc_loggedIn = id<Oidc.LoggedIn<DecodedIdToken>>({
974
+ ...oidc_common,
975
+ isUserLoggedIn: true,
976
+ getTokens: async () => {
977
+ if (wouldHaveAutoLoggedOutIfBrowserWasOnline) {
978
+ await oidc_loggedIn.logout(autoLogoutParams);
979
+ assert(false);
980
+ }
981
+
982
+ renew_tokens: {
983
+ {
984
+ const msBeforeExpirationOfTheAccessToken =
985
+ currentTokens.accessTokenExpirationTime - Date.now();
986
+
987
+ if (msBeforeExpirationOfTheAccessToken > 30_000) {
988
+ break renew_tokens;
989
+ }
990
+ }
991
+
992
+ {
993
+ const msElapsedSinceCurrentTokenWereIssued = Date.now() - currentTokens.issuedAtTime;
994
+
995
+ if (msElapsedSinceCurrentTokenWereIssued < 5_000) {
996
+ break renew_tokens;
997
+ }
998
+ }
999
+
1000
+ await oidc_loggedIn.renewTokens();
1001
+ }
1002
+
1003
+ return currentTokens;
1004
+ },
1005
+ getDecodedIdToken: () => currentTokens.decodedIdToken,
1006
+ logout: async params => {
1007
+ if (globalContext.hasLogoutBeenCalled) {
1008
+ log?.("logout() has already been called, ignoring the call");
1009
+ return new Promise<never>(() => {});
1010
+ }
1011
+
1012
+ globalContext.hasLogoutBeenCalled = true;
1013
+
1014
+ const postLogoutRedirectUrl: string = (() => {
1015
+ switch (params.redirectTo) {
1016
+ case "current page":
1017
+ return window.location.href;
1018
+ case "home":
1019
+ return homeUrlAndRedirectUri;
1020
+ case "specific url":
1021
+ return toFullyQualifiedUrl({
1022
+ urlish: params.url,
1023
+ doAssertNoQueryParams: false
1024
+ });
1025
+ }
1026
+ })();
1027
+
1028
+ await waitForAllOtherOngoingLoginOrRefreshProcessesToComplete({
1029
+ prUnlock: new Promise<never>(() => {})
1030
+ });
1031
+
1032
+ window.addEventListener("pageshow", () => {
1033
+ location.reload();
1034
+ });
1035
+
1036
+ try {
1037
+ await oidcClientTsUserManager.signoutRedirect({
1038
+ state: id<StateData>({
1039
+ configId,
1040
+ context: "redirect",
1041
+ redirectUrl: postLogoutRedirectUrl,
1042
+ hasBeenProcessedByCallback: false,
1043
+ action: "logout",
1044
+ sessionId
1045
+ }),
1046
+ redirectMethod: "assign"
1047
+ });
1048
+ } catch (error) {
1049
+ assert(is<Error>(error));
1050
+
1051
+ if (error.message === "No end session endpoint") {
1052
+ log?.("No end session endpoint, managing logging state locally");
1053
+
1054
+ persistAuthState({ configId, state: { stateDescription: "explicitly logged out" } });
1055
+
1056
+ try {
1057
+ await oidcClientTsUserManager.removeUser();
1058
+ } catch {
1059
+ // NOTE: Not sure if it can throw
1060
+ }
1061
+
1062
+ notifyOtherTabsOfLogout({
1063
+ configId,
1064
+ sessionId
1065
+ });
1066
+
1067
+ window.location.href = postLogoutRedirectUrl;
1068
+ } else {
1069
+ throw error;
1070
+ }
1071
+ }
1072
+
1073
+ return new Promise<never>(() => {});
1074
+ },
1075
+ renewTokens: (() => {
1076
+ async function renewTokens_nonMutexed(params: {
1077
+ extraTokenParams: Record<string, string | undefined>;
1078
+ }) {
1079
+ const { extraTokenParams } = params;
1080
+
1081
+ const fallbackToFullPageReload = async (): Promise<never> => {
1082
+ persistAuthState({ configId, state: undefined });
1083
+
1084
+ await waitForAllOtherOngoingLoginOrRefreshProcessesToComplete({
1085
+ prUnlock: new Promise<never>(() => {})
1086
+ });
1087
+
1088
+ globalContext.evtRequestToPersistTokens.post({
1089
+ configIdOfInstancePostingTheRequest: configId
1090
+ });
1091
+
1092
+ await loginOrGoToAuthServer({
1093
+ action: "login",
1094
+ redirectUrl: window.location.href,
1095
+ doForceReloadOnBfCache: true,
1096
+ extraQueryParams_local: undefined,
1097
+ transformUrlBeforeRedirect_local: undefined,
1098
+ doNavigateBackToLastPublicUrlIfTheTheUserNavigateBack: false,
1099
+ interaction: "directly redirect if active session show login otherwise"
1100
+ });
1101
+ assert(false, "136134");
1102
+ };
1103
+
1104
+ if (!currentTokens.hasRefreshToken && !canUseIframe) {
1105
+ log?.(
1106
+ [
1107
+ "Unable to refresh tokens without a full app reload,",
1108
+ "because no refresh token is available",
1109
+ "and your app setup prevents silent sign-in via iframe.",
1110
+ "Your only option to refresh tokens is to call `window.location.reload()`"
1111
+ ].join(" ")
1112
+ );
1113
+
1114
+ await fallbackToFullPageReload();
1115
+
1116
+ assert(false, "136135");
1117
+ }
1118
+
1119
+ log?.("Renewing tokens");
1120
+
1121
+ const { completeLoginOrRefreshProcess } = await startLoginOrRefreshProcess();
1122
+
1123
+ const result_loginSilent = await loginSilent({
1124
+ oidcClientTsUserManager,
1125
+ stateUrlParamValue_instance,
1126
+ configId,
1127
+ transformUrlBeforeRedirect,
1128
+ getExtraQueryParams,
1129
+ getExtraTokenParams: () => extraTokenParams,
1130
+ autoLogin
1131
+ });
1132
+
1133
+ if (result_loginSilent.outcome === "failure") {
1134
+ completeLoginOrRefreshProcess();
1135
+ // NOTE: This is a configuration or network error, okay to throw,
1136
+ // this exception doesn't have to be handle if it fails it fails.
1137
+ throw new Error(result_loginSilent.cause);
1138
+ }
1139
+
1140
+ let oidcClientTsUser: OidcClientTsUser;
1141
+
1142
+ switch (result_loginSilent.outcome) {
1143
+ case "token refreshed using refresh token":
1144
+ {
1145
+ log?.("Refresh token used");
1146
+ oidcClientTsUser = result_loginSilent.oidcClientTsUser;
1147
+ }
1148
+ break;
1149
+ case "got auth response from iframe":
1150
+ {
1151
+ const { authResponse } = result_loginSilent;
1152
+
1153
+ log?.("Tokens refresh using iframe", authResponse);
1154
+
1155
+ const authResponse_error = authResponse.error;
1156
+
1157
+ let oidcClientTsUser_scope: OidcClientTsUser | undefined = undefined;
1158
+
1159
+ try {
1160
+ oidcClientTsUser_scope =
1161
+ await oidcClientTsUserManager.signinRedirectCallback(
1162
+ authResponseToUrl(authResponse)
1163
+ );
1164
+ } catch (error) {
1165
+ assert(error instanceof Error, "321389");
1166
+
1167
+ if (authResponse_error === undefined) {
1168
+ completeLoginOrRefreshProcess();
1169
+ // Same here, if it fails it fails.
1170
+ throw error;
1171
+ }
1172
+ }
1173
+
1174
+ if (oidcClientTsUser_scope === undefined) {
1175
+ // NOTE: Here we got a response but it's an error, session might have been
1176
+ // deleted or other edge case.
1177
+
1178
+ completeLoginOrRefreshProcess();
1179
+
1180
+ log?.(
1181
+ [
1182
+ "The user is probably not logged in anymore,",
1183
+ "need to redirect to login pages"
1184
+ ].join(" ")
1185
+ );
1186
+
1187
+ await fallbackToFullPageReload();
1188
+
1189
+ assert(false, "136135");
1190
+ }
1191
+
1192
+ oidcClientTsUser = oidcClientTsUser_scope;
1193
+ }
1194
+ break;
1195
+ default:
1196
+ assert<Equals<typeof result_loginSilent, never>>(false);
1197
+ break;
1198
+ }
1199
+
1200
+ currentTokens = oidcClientTsUserToTokens({
1201
+ oidcClientTsUser,
1202
+ decodedIdTokenSchema,
1203
+ __unsafe_useIdTokenAsAccessToken,
1204
+ decodedIdToken_previous: currentTokens.decodedIdToken,
1205
+ log
1206
+ });
1207
+
1208
+ if (getPersistedAuthState({ configId }) !== undefined) {
1209
+ persistAuthState({
1210
+ configId,
1211
+ state: {
1212
+ stateDescription: "logged in",
1213
+ refreshTokenExpirationTime: currentTokens.refreshTokenExpirationTime,
1214
+ idleSessionLifetimeInSeconds
1215
+ }
1216
+ });
1217
+ }
1218
+
1219
+ Array.from(onTokenChanges).forEach(onTokenChange => onTokenChange(currentTokens));
1220
+
1221
+ completeLoginOrRefreshProcess();
1222
+ }
1223
+
1224
+ let ongoingCall:
1225
+ | {
1226
+ pr: Promise<void>;
1227
+ extraTokenParams: Record<string, string | undefined>;
1228
+ }
1229
+ | undefined = undefined;
1230
+
1231
+ function handleFinally() {
1232
+ assert(ongoingCall !== undefined, "131276");
1233
+
1234
+ const { pr } = ongoingCall;
1235
+
1236
+ pr.finally(() => {
1237
+ assert(ongoingCall !== undefined, "549462");
1238
+
1239
+ if (ongoingCall.pr !== pr) {
1240
+ return;
1241
+ }
1242
+
1243
+ ongoingCall = undefined;
1244
+ });
1245
+ }
1246
+
1247
+ return async params => {
1248
+ const { extraTokenParams: extraTokenParams_local } = params ?? {};
1249
+
1250
+ const extraTokenParams = {
1251
+ ...getExtraTokenParams?.(),
1252
+ ...extraTokenParams_local
1253
+ };
1254
+
1255
+ if (ongoingCall === undefined) {
1256
+ ongoingCall = {
1257
+ pr: renewTokens_nonMutexed({ extraTokenParams }),
1258
+ extraTokenParams
1259
+ };
1260
+
1261
+ handleFinally();
1262
+
1263
+ return ongoingCall.pr;
1264
+ }
1265
+
1266
+ if (JSON.stringify(extraTokenParams) === JSON.stringify(ongoingCall.extraTokenParams)) {
1267
+ return ongoingCall.pr;
1268
+ }
1269
+
1270
+ ongoingCall = {
1271
+ pr: (async () => {
1272
+ try {
1273
+ await ongoingCall.pr;
1274
+ } catch {}
1275
+
1276
+ return renewTokens_nonMutexed({ extraTokenParams });
1277
+ })(),
1278
+ extraTokenParams
1279
+ };
1280
+
1281
+ handleFinally();
1282
+
1283
+ return ongoingCall.pr;
1284
+ };
1285
+ })(),
1286
+ subscribeToTokensChange: onTokenChange => {
1287
+ onTokenChanges.add(onTokenChange);
1288
+
1289
+ return {
1290
+ unsubscribe: () => {
1291
+ onTokenChanges.delete(onTokenChange);
1292
+ }
1293
+ };
1294
+ },
1295
+ subscribeToAutoLogoutCountdown: tickCallback => {
1296
+ autoLogoutCountdownTickCallbacks.add(tickCallback);
1297
+
1298
+ const unsubscribeFromAutoLogoutCountdown = () => {
1299
+ autoLogoutCountdownTickCallbacks.delete(tickCallback);
1300
+ };
1301
+
1302
+ return { unsubscribeFromAutoLogoutCountdown };
1303
+ },
1304
+ goToAuthServer: ({ extraQueryParams, redirectUrl, transformUrlBeforeRedirect }) =>
1305
+ loginOrGoToAuthServer({
1306
+ action: "go to auth server",
1307
+ redirectUrl: redirectUrl ?? window.location.href,
1308
+ extraQueryParams_local: extraQueryParams,
1309
+ transformUrlBeforeRedirect_local: transformUrlBeforeRedirect
1310
+ }),
1311
+ backFromAuthServer: resultOfLoginProcess.backFromAuthServer,
1312
+ isNewBrowserSession: (() => {
1313
+ const value = getIsNewBrowserSession({ subjectId });
1314
+
1315
+ log?.(`isNewBrowserSession: ${value}`);
1316
+
1317
+ return value;
1318
+ })()
1319
+ });
1320
+
1321
+ {
1322
+ const { prOtherTabLogout } = getPrOtherTabLogout({
1323
+ configId,
1324
+ sessionId
1325
+ });
1326
+
1327
+ prOtherTabLogout.then(async () => {
1328
+ log?.(`Other tab has logged out, refreshing current tab`);
1329
+
1330
+ await waitForAllOtherOngoingLoginOrRefreshProcessesToComplete({
1331
+ prUnlock: new Promise<never>(() => {})
1332
+ });
1333
+
1334
+ location.reload();
1335
+ });
1336
+ }
1337
+
1338
+ (function scheduleRenew() {
1339
+ if (!currentTokens.hasRefreshToken && !canUseIframe) {
1340
+ log?.(
1341
+ [
1342
+ "Disabling token auto refresh mechanism because we",
1343
+ "have no way to renew the tokens without a full page reload"
1344
+ ].join(" ")
1345
+ );
1346
+ return;
1347
+ }
1348
+
1349
+ const msBeforeExpiration =
1350
+ (currentTokens.refreshTokenExpirationTime ?? currentTokens.accessTokenExpirationTime) -
1351
+ Date.now();
1352
+
1353
+ const typeOfTheTokenWeGotTheTtlFrom =
1354
+ currentTokens.refreshTokenExpirationTime !== undefined ? "refresh" : "access";
1355
+
1356
+ const RENEW_MS_BEFORE_EXPIRES = 30_000;
1357
+
1358
+ if (msBeforeExpiration <= RENEW_MS_BEFORE_EXPIRES) {
1359
+ // NOTE: We just got a new token that is about to expire. This means that
1360
+ // the refresh token has reached it's max SSO time.
1361
+ // ...or that the refresh token have a very short lifespan...
1362
+ // anyway, no need to keep alive, it will probably redirect on the next getTokens() or refreshTokens() call
1363
+ log?.(
1364
+ [
1365
+ "Disabling auto renew mechanism. We just got fresh tokens",
1366
+ (() => {
1367
+ switch (typeOfTheTokenWeGotTheTtlFrom) {
1368
+ case "refresh":
1369
+ return [
1370
+ " and the refresh token is already about to expires.",
1371
+ "This means that we have reached the max session lifespan, we can't keep",
1372
+ "the session alive any longer.",
1373
+ "(This can also mean that the refresh token was configured with a TTL,",
1374
+ "aka the idle session lifespan, too low to make sense)"
1375
+ ].join(" ");
1376
+ case "access":
1377
+ return [
1378
+ currentTokens.hasRefreshToken
1379
+ ? ", we can't read the expiration time of the refresh token"
1380
+ : ", we don't have a refresh token",
1381
+ ` and the access token is already about to expire`,
1382
+ "we would spam the auth server by constantly renewing the access token in the background",
1383
+ "avoiding to do so."
1384
+ ].join(" ");
1385
+ }
1386
+ })()
1387
+ ].join(" ")
1388
+ );
1389
+ return;
1390
+ }
1391
+
1392
+ log?.(
1393
+ [
1394
+ toHumanReadableDuration(msBeforeExpiration),
1395
+ `before expiration of the ${typeOfTheTokenWeGotTheTtlFrom} token.`,
1396
+ `Scheduling renewal ${toHumanReadableDuration(
1397
+ RENEW_MS_BEFORE_EXPIRES
1398
+ )} before expiration to keep the session alive on the OIDC server.`
1399
+ ].join(" ")
1400
+ );
1401
+
1402
+ const timer = setTimeout(
1403
+ async () => {
1404
+ {
1405
+ const { isOnline, prOnline } = getIsOnline();
1406
+
1407
+ if (!isOnline) {
1408
+ const didCameBackOnlineInTime = await Promise.race([
1409
+ new Promise<false>(resolve =>
1410
+ setTimeout(() => resolve(false), RENEW_MS_BEFORE_EXPIRES - 1_000)
1411
+ ),
1412
+ prOnline.then(() => true)
1413
+ ]);
1414
+
1415
+ if (!didCameBackOnlineInTime) {
1416
+ log?.(
1417
+ [
1418
+ "The session expired on the OIDC server.",
1419
+ "We couldn't keep it alive because the browser was offline.",
1420
+ "We are not redirecting to the login page to support PWAs with offline features.",
1421
+ "However, the next getTokens() call will trigger a redirect to the Auth server login page."
1422
+ ].join(" ")
1423
+ );
1424
+ return;
1425
+ }
1426
+ }
1427
+ }
1428
+
1429
+ log?.(
1430
+ `Renewing the tokens now as the ${typeOfTheTokenWeGotTheTtlFrom} token will expire in ${toHumanReadableDuration(
1431
+ RENEW_MS_BEFORE_EXPIRES
1432
+ )}`
1433
+ );
1434
+
1435
+ await oidc_loggedIn.renewTokens();
1436
+ },
1437
+ Math.min(
1438
+ msBeforeExpiration - RENEW_MS_BEFORE_EXPIRES,
1439
+ // NOTE: We want to make sure we do not overflow the setTimeout
1440
+ // that must be a 32 bit unsigned integer.
1441
+ // This can happen if the tokenExpirationTime is more than 24.8 days in the future.
1442
+ Math.pow(2, 31) - 1
1443
+ )
1444
+ );
1445
+
1446
+ const { unsubscribe: tokenChangeUnsubscribe } = oidc_loggedIn.subscribeToTokensChange(() => {
1447
+ clearTimeout(timer);
1448
+ tokenChangeUnsubscribe();
1449
+ scheduleRenew();
1450
+ });
1451
+ })();
1452
+
1453
+ auto_logout: {
1454
+ const getCurrentRefreshTokenTtlInSeconds = () => {
1455
+ if (idleSessionLifetimeInSeconds !== undefined) {
1456
+ return idleSessionLifetimeInSeconds;
1457
+ }
1458
+
1459
+ if (currentTokens.refreshTokenExpirationTime === undefined) {
1460
+ return undefined;
1461
+ }
1462
+
1463
+ return (currentTokens.refreshTokenExpirationTime - currentTokens.issuedAtTime) / 1000;
1464
+ };
1465
+
1466
+ if (getCurrentRefreshTokenTtlInSeconds() === undefined) {
1467
+ log?.(
1468
+ `${
1469
+ currentTokens.hasRefreshToken
1470
+ ? "The refresh token is opaque, we can't read it's expiration time"
1471
+ : "No refresh token"
1472
+ }, and idleSessionLifetimeInSeconds was not set, can't implement auto logout mechanism`
1473
+ );
1474
+ break auto_logout;
1475
+ }
1476
+
1477
+ const { startCountdown } = createStartCountdown({
1478
+ tickCallback: async ({ secondsLeft }) => {
1479
+ const invokeAllCallbacks = (params: { secondsLeft: number | undefined }) => {
1480
+ const { secondsLeft } = params;
1481
+ Array.from(autoLogoutCountdownTickCallbacks).forEach(tickCallback =>
1482
+ tickCallback({ secondsLeft })
1483
+ );
1484
+ };
1485
+
1486
+ invokeAllCallbacks({ secondsLeft });
1487
+
1488
+ if (secondsLeft === 0) {
1489
+ cancel_if_offline: {
1490
+ const { isOnline, prOnline } = getIsOnline();
1491
+
1492
+ if (isOnline) {
1493
+ break cancel_if_offline;
1494
+ }
1495
+
1496
+ const didCameBackOnline = await Promise.race([
1497
+ new Promise<false>(resolve => setTimeout(() => resolve(false), 10_000)),
1498
+ prOnline.then(() => true)
1499
+ ]);
1500
+
1501
+ if (didCameBackOnline) {
1502
+ break cancel_if_offline;
1503
+ }
1504
+
1505
+ log?.(
1506
+ [
1507
+ "Normally now we should auto logout.",
1508
+ "However since the browser is currently offline",
1509
+ "we avoid calling logout() now to play nice in case",
1510
+ "this app is a PWA.",
1511
+ "Next getTokens() is called logout will be called"
1512
+ ].join(" ")
1513
+ );
1514
+
1515
+ unsubscribeFromIsUserActive();
1516
+
1517
+ invokeAllCallbacks({ secondsLeft: undefined });
1518
+
1519
+ wouldHaveAutoLoggedOutIfBrowserWasOnline = true;
1520
+
1521
+ return;
1522
+ }
1523
+
1524
+ await oidc_loggedIn.logout(autoLogoutParams);
1525
+ }
1526
+ }
1527
+ });
1528
+
1529
+ let stopCountdown: (() => void) | undefined = undefined;
1530
+
1531
+ const evtIsUserActive = createEvtIsUserActive({
1532
+ configId,
1533
+ sessionId
1534
+ });
1535
+
1536
+ const { unsubscribe: unsubscribeFromIsUserActive } = evtIsUserActive.subscribe(isUserActive => {
1537
+ if (isUserActive) {
1538
+ if (stopCountdown !== undefined) {
1539
+ stopCountdown();
1540
+ stopCountdown = undefined;
1541
+ }
1542
+ } else {
1543
+ assert(stopCountdown === undefined, "902992");
1544
+
1545
+ const currentRefreshTokenTtlInSeconds = getCurrentRefreshTokenTtlInSeconds();
1546
+
1547
+ assert(currentRefreshTokenTtlInSeconds !== undefined, "902992326");
1548
+
1549
+ stopCountdown = startCountdown({
1550
+ countDownFromSeconds: currentRefreshTokenTtlInSeconds
1551
+ }).stopCountdown;
1552
+ }
1553
+ });
1554
+
1555
+ {
1556
+ const currentRefreshTokenTtlInSeconds = getCurrentRefreshTokenTtlInSeconds();
1557
+
1558
+ assert(currentRefreshTokenTtlInSeconds !== undefined, "9029923253");
1559
+
1560
+ log?.(
1561
+ [
1562
+ `The user will be automatically logged out after ${toHumanReadableDuration(
1563
+ currentRefreshTokenTtlInSeconds * 1_000
1564
+ )} of inactivity.`,
1565
+ idleSessionLifetimeInSeconds === undefined
1566
+ ? undefined
1567
+ : `It was artificially defined by using the idleSessionLifetimeInSeconds param.`
1568
+ ]
1569
+ .filter(x => x !== undefined)
1570
+ .join("\n")
1571
+ );
1572
+ }
1573
+ }
1574
+
1575
+ return oidc_loggedIn;
1576
+ }