oidc-spa 3.0.3 → 4.0.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.
package/react.js CHANGED
@@ -27,17 +27,18 @@ var __read = (this && this.__read) || function (o, n) {
27
27
  return ar;
28
28
  };
29
29
  Object.defineProperty(exports, "__esModule", { value: true });
30
- exports.createUseOidc = exports.createOidcProvider = void 0;
30
+ exports.createReactOidc = void 0;
31
31
  var jsx_runtime_1 = require("react/jsx-runtime");
32
32
  var react_1 = require("react");
33
33
  var oidc_1 = require("./oidc");
34
34
  var assert_1 = require("tsafe/assert");
35
- var decodeJwt_1 = require("./tools/decodeJwt");
36
35
  var id_1 = require("tsafe/id");
36
+ var useGuaranteedMemo_1 = require("./tools/powerhooks/useGuaranteedMemo");
37
37
  var oidcContext = (0, react_1.createContext)(undefined);
38
38
  /** @see: https://github.com/garronej/oidc-spa#option-2-usage-directly-within-react */
39
- function createOidcProvider(params) {
39
+ function createReactOidc(params) {
40
40
  var prOidc = (0, oidc_1.createOidc)(params);
41
+ var decodedIdTokenSchema = params.decodedIdTokenSchema;
41
42
  function OidcProvider(props) {
42
43
  var children = props.children, fallback = props.fallback;
43
44
  var _a = __read((0, react_1.useState)(undefined), 2), oidc = _a[0], setOidc = _a[1];
@@ -47,18 +48,16 @@ function createOidcProvider(params) {
47
48
  if (oidc === undefined) {
48
49
  return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: fallback === undefined ? null : fallback });
49
50
  }
50
- return (0, jsx_runtime_1.jsx)(oidcContext.Provider, { value: oidc, children: children });
51
+ return ((0, jsx_runtime_1.jsx)(oidcContext.Provider, { value: { oidc: oidc, decodedIdTokenSchema: decodedIdTokenSchema }, children: children }));
51
52
  }
52
- return { OidcProvider: OidcProvider, prOidc: prOidc };
53
- }
54
- exports.createOidcProvider = createOidcProvider;
55
- function createUseOidc(params) {
56
- var decodedIdTokenSchema = (params !== null && params !== void 0 ? params : {}).decodedIdTokenSchema;
57
53
  function useOidc(params) {
58
54
  var _a = (params !== null && params !== void 0 ? params : {}).assertUserLoggedIn, assertUserLoggedIn = _a === void 0 ? false : _a;
59
- var oidc = (0, react_1.useContext)(oidcContext);
60
- (0, assert_1.assert)(oidc !== undefined, "You must use useOidc inside a OidcProvider");
61
- var _b = __read((0, react_1.useReducer)(function () { return []; }, []), 2), forceUpdate = _b[1];
55
+ var _b = (function useClosure() {
56
+ var context = (0, react_1.useContext)(oidcContext);
57
+ (0, assert_1.assert)(context !== undefined, "You must use useOidc inside a OidcProvider");
58
+ return context;
59
+ })(), oidc = _b.oidc, decodedIdTokenSchema_context = _b.decodedIdTokenSchema;
60
+ var _c = __read((0, react_1.useReducer)(function () { return []; }, []), 2), forceUpdate = _c[1];
62
61
  (0, react_1.useEffect)(function () {
63
62
  if (!oidc.isUserLoggedIn) {
64
63
  return;
@@ -69,25 +68,53 @@ function createUseOidc(params) {
69
68
  if (assertUserLoggedIn && !oidc.isUserLoggedIn) {
70
69
  throw new Error("The user must be logged in to use this hook (assertUserLoggedIn was set to true)");
71
70
  }
72
- var tokens = oidc.isUserLoggedIn ? oidc.getTokens() : undefined;
73
- var decodedIdToken = (0, react_1.useMemo)(function () {
74
- if ((tokens === null || tokens === void 0 ? void 0 : tokens.idToken) === undefined) {
75
- return undefined;
76
- }
77
- var decodedIdToken = (0, decodeJwt_1.decodeJwt)(tokens.idToken);
78
- if (decodedIdTokenSchema !== undefined) {
79
- decodedIdTokenSchema.parse((0, decodeJwt_1.decodeJwt)(tokens.idToken));
80
- }
81
- return decodedIdToken;
82
- }, [tokens === null || tokens === void 0 ? void 0 : tokens.idToken]);
71
+ var oidcTokens = (function useClosure() {
72
+ var tokens = oidc.isUserLoggedIn ? oidc.getTokens() : undefined;
73
+ var oidcTokens = (0, useGuaranteedMemo_1.useGuaranteedMemo)(function () {
74
+ if (tokens === undefined) {
75
+ return undefined;
76
+ }
77
+ var oidcTokens = {
78
+ "accessToken": tokens.accessToken,
79
+ "accessTokenExpirationTime": tokens.accessTokenExpirationTime,
80
+ "idToken": tokens.idToken,
81
+ "refreshToken": tokens.refreshToken,
82
+ "refreshTokenExpirationTime": tokens.refreshTokenExpirationTime,
83
+ "decodedIdToken": null
84
+ };
85
+ var cache = undefined;
86
+ Object.defineProperty(oidcTokens, "decodedIdToken", {
87
+ "get": function () {
88
+ if (cache !== undefined) {
89
+ return cache.decodedIdToken;
90
+ }
91
+ var decodedIdToken = tokens.decodedIdToken;
92
+ if (decodedIdTokenSchema !== undefined &&
93
+ decodedIdTokenSchema !== decodedIdTokenSchema_context) {
94
+ decodedIdToken = decodedIdTokenSchema.parse(decodedIdToken);
95
+ }
96
+ cache = { decodedIdToken: decodedIdToken };
97
+ return decodedIdToken;
98
+ }
99
+ });
100
+ return oidcTokens;
101
+ }, [
102
+ tokens === null || tokens === void 0 ? void 0 : tokens.accessToken,
103
+ tokens === null || tokens === void 0 ? void 0 : tokens.accessTokenExpirationTime,
104
+ tokens === null || tokens === void 0 ? void 0 : tokens.idToken,
105
+ tokens === null || tokens === void 0 ? void 0 : tokens.refreshToken,
106
+ tokens === null || tokens === void 0 ? void 0 : tokens.refreshTokenExpirationTime
107
+ ]);
108
+ return { oidcTokens: oidcTokens };
109
+ })().oidcTokens;
83
110
  var common = {
84
111
  "params": oidc.params
85
112
  };
86
113
  return oidc.isUserLoggedIn
87
- ? (0, id_1.id)(__assign(__assign({}, common), { "isUserLoggedIn": true, "oidcTokens": __assign(__assign({}, tokens), { "decodedIdToken": decodedIdToken }), "logout": oidc.logout, "renewTokens": oidc.renewTokens, "login": undefined }))
88
- : (0, id_1.id)(__assign(__assign({}, common), { "isUserLoggedIn": false, "login": oidc.login, "oidcTokens": undefined, "logout": undefined }));
114
+ ? (0, id_1.id)(((0, assert_1.assert)(oidcTokens !== undefined), __assign(__assign({}, common), { "isUserLoggedIn": true, oidcTokens: oidcTokens, "logout": oidc.logout, "renewTokens": oidc.renewTokens })))
115
+ : (0, id_1.id)(__assign(__assign({}, common), { "isUserLoggedIn": false, "login": oidc.login }));
89
116
  }
90
- return { useOidc: useOidc };
117
+ return { OidcProvider: OidcProvider, useOidc: useOidc, prOidc: prOidc };
91
118
  }
92
- exports.createUseOidc = createUseOidc;
119
+ exports.createReactOidc = createReactOidc;
93
120
  //# sourceMappingURL=react.js.map
package/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"react.js","sourceRoot":"","sources":["src/react.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+BAQe;AACf,+BAA+C;AAC/C,uCAAsC;AACtC,+CAA8C;AAC9C,+BAA8B;AAE9B,IAAM,WAAW,GAAG,IAAA,qBAAa,EAAmB,SAAS,CAAC,CAAC;AAE/D,sFAAsF;AACtF,SAAgB,kBAAkB,CAAC,MAAwC;IACvE,IAAM,MAAM,GAAG,IAAA,iBAAU,EAAC,MAAM,CAAC,CAAC;IAElC,SAAS,YAAY,CAAC,KAAoD;QAC9D,IAAA,QAAQ,GAAe,KAAK,SAApB,EAAE,QAAQ,GAAK,KAAK,SAAV,CAAW;QAE/B,IAAA,KAAA,OAAkB,IAAA,gBAAQ,EAAmB,SAAS,CAAC,IAAA,EAAtD,IAAI,QAAA,EAAE,OAAO,QAAyC,CAAC;QAE9D,IAAA,iBAAS,EAAC;YACN,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC,EAAE,EAAE,CAAC,CAAC;QAEP,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACrB,OAAO,2DAAG,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,GAAI,CAAC;QAC3D,CAAC;QAED,OAAO,uBAAC,WAAW,CAAC,QAAQ,IAAC,KAAK,EAAE,IAAI,YAAG,QAAQ,GAAwB,CAAC;IAChF,CAAC;IAED,OAAO,EAAE,YAAY,cAAA,EAAE,MAAM,QAAA,EAAE,CAAC;AACpC,CAAC;AApBD,gDAoBC;AA2BD,SAAgB,aAAa,CAE3B,MAAoF;IAC1E,IAAA,oBAAoB,GAAK,CAAA,MAAM,aAAN,MAAM,cAAN,MAAM,GAAI,EAAE,CAAA,qBAAjB,CAAkB;IAI9C,SAAS,OAAO,CAAC,MAAwC;QAC7C,IAAA,KAA+B,CAAA,MAAM,aAAN,MAAM,cAAN,MAAM,GAAI,EAAE,CAAA,mBAAjB,EAA1B,kBAAkB,mBAAG,KAAK,KAAA,CAAkB;QAEpD,IAAM,IAAI,GAAG,IAAA,kBAAU,EAAC,WAAW,CAAC,CAAC;QAErC,IAAA,eAAM,EAAC,IAAI,KAAK,SAAS,EAAE,4CAA4C,CAAC,CAAC;QAEnE,IAAA,KAAA,OAAkB,IAAA,kBAAU,EAAC,cAAM,OAAA,EAAE,EAAF,CAAE,EAAE,EAAE,CAAC,IAAA,EAAvC,WAAW,QAA4B,CAAC;QAEjD,IAAA,iBAAS,EAAC;YACN,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;gBACvB,OAAO;YACX,CAAC;YAEO,IAAA,WAAW,GAAK,IAAI,CAAC,uBAAuB,CAAC,WAAW,CAAC,YAA9C,CAA+C;YAElE,OAAO,WAAW,CAAC;QACvB,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;QAEX,IAAI,kBAAkB,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CACX,kFAAkF,CACrF,CAAC;QACN,CAAC;QAED,IAAM,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAElE,IAAM,cAAc,GAAG,IAAA,eAAO,EAAC;YAC3B,IAAI,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,OAAO,MAAK,SAAS,EAAE,CAAC;gBAChC,OAAO,SAAS,CAAC;YACrB,CAAC;YAED,IAAM,cAAc,GAAG,IAAA,qBAAS,EAAC,MAAM,CAAC,OAAO,CAAuB,CAAC;YAEvE,IAAI,oBAAoB,KAAK,SAAS,EAAE,CAAC;gBACrC,oBAAoB,CAAC,KAAK,CAAC,IAAA,qBAAS,EAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;YAC1D,CAAC;YAED,OAAO,cAAc,CAAC;QAC1B,CAAC,EAAE,CAAC,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,OAAO,CAAC,CAAC,CAAC;QAEtB,IAAM,MAAM,GAAwB;YAChC,QAAQ,EAAE,IAAI,CAAC,MAAM;SACxB,CAAC;QAEF,OAAO,IAAI,CAAC,cAAc;YACtB,CAAC,CAAC,IAAA,OAAE,wBACK,MAAM,KACT,gBAAgB,EAAE,IAAI,EACtB,YAAY,wBACL,MAAO,KACV,gBAAgB,EAAE,cAAe,KAErC,QAAQ,EAAE,IAAI,CAAC,MAAM,EACrB,aAAa,EAAE,IAAI,CAAC,WAAW,EAC/B,OAAO,EAAE,SAAS,IACpB;YACJ,CAAC,CAAC,IAAA,OAAE,wBACK,MAAM,KACT,gBAAgB,EAAE,KAAK,EACvB,OAAO,EAAE,IAAI,CAAC,KAAK,EACnB,YAAY,EAAE,SAAS,EACvB,QAAQ,EAAE,SAAS,IACrB,CAAC;IACb,CAAC;IAED,OAAO,EAAE,OAAO,SAAA,EAAE,CAAC;AACvB,CAAC;AA1ED,sCA0EC"}
1
+ {"version":3,"file":"react.js","sourceRoot":"","sources":["src/react.tsx"],"names":[],"mappings":"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"}
package/src/oidc.ts CHANGED
@@ -1,12 +1,15 @@
1
- import { UserManager, type User } from "oidc-client-ts";
1
+ import { UserManager as OidcClientTsUserManager, type User as OidcClientTsUser } from "oidc-client-ts";
2
2
  import { id } from "tsafe/id";
3
3
  import { readExpirationTimeInJwt } from "./tools/readExpirationTimeInJwt";
4
4
  import { assert, type Equals } from "tsafe/assert";
5
5
  import { addQueryParamToUrl, retrieveQueryParamFromUrl } from "./tools/urlQueryParams";
6
6
  import { fnv1aHashToHex } from "./tools/fnv1aHashToHex";
7
7
  import { Deferred } from "./tools/Deferred";
8
+ import { decodeJwt } from "./tools/decodeJwt";
8
9
 
9
- export declare type Oidc = Oidc.LoggedIn | Oidc.NotLoggedIn;
10
+ export declare type Oidc<DecodedIdToken extends Record<string, unknown> = Record<string, unknown>> =
11
+ | Oidc.LoggedIn<DecodedIdToken>
12
+ | Oidc.NotLoggedIn;
10
13
 
11
14
  export declare namespace Oidc {
12
15
  export type Common = {
@@ -24,33 +27,46 @@ export declare namespace Oidc {
24
27
  }) => Promise<never>;
25
28
  };
26
29
 
27
- export type LoggedIn = Common & {
28
- isUserLoggedIn: true;
29
- renewTokens(): Promise<void>;
30
- getTokens: () => Tokens;
31
- subscribeToTokensChange: (onTokenChange: () => void) => { unsubscribe: () => void };
32
- logout: (
33
- params: { redirectTo: "home" | "current page" } | { redirectTo: "specific url"; url: string }
34
- ) => Promise<never>;
35
- };
30
+ export type LoggedIn<DecodedIdToken extends Record<string, unknown> = Record<string, unknown>> =
31
+ Common & {
32
+ isUserLoggedIn: true;
33
+ renewTokens(): Promise<void>;
34
+ getTokens: () => Tokens<DecodedIdToken>;
35
+ subscribeToTokensChange: (onTokenChange: () => void) => { unsubscribe: () => void };
36
+ logout: (
37
+ params:
38
+ | { redirectTo: "home" | "current page" }
39
+ | { redirectTo: "specific url"; url: string }
40
+ ) => Promise<never>;
41
+ };
36
42
 
37
- export type Tokens = {
38
- accessToken: string;
39
- accessTokenExpirationTime: number;
40
- idToken: string;
41
- refreshToken: string;
42
- refreshTokenExpirationTime: number;
43
- };
43
+ export type Tokens<DecodedIdToken extends Record<string, unknown> = Record<string, unknown>> =
44
+ Readonly<{
45
+ accessToken: string;
46
+ accessTokenExpirationTime: number;
47
+ idToken: string;
48
+ refreshToken: string;
49
+ refreshTokenExpirationTime: number;
50
+ decodedIdToken: DecodedIdToken;
51
+ }>;
44
52
  }
45
53
 
46
54
  const paramsToRetrieveFromSuccessfulLogin = ["code", "state", "session_state", "iss"] as const;
47
55
 
48
- /** @see: https://github.com/garronej/oidc-spa#option-1-usage-without-involving-the-ui-framework */
49
- export async function createOidc(params: {
56
+ export type ParamsOfCreateOidc<
57
+ DecodedIdToken extends Record<string, unknown> = Record<string, unknown>
58
+ > = {
50
59
  issuerUri: string;
51
60
  clientId: string;
52
61
  transformUrlBeforeRedirect?: (url: string) => string;
53
- getExtraQueryParams?: () => Record<string, string>;
62
+ /**
63
+ * Extra query params to be added on the login url.
64
+ * You can provide a function that returns those extra query params, it will be called
65
+ * when login() is called.
66
+ *
67
+ * Example: extraQueryParams: ()=> ({ ui_locales: "fr" })
68
+ */
69
+ extraQueryParams?: Record<string, string> | (() => Record<string, string>);
54
70
  /**
55
71
  * This parameter have to be provided if your App is not hosted at the origin of the subdomain.
56
72
  * For example if your site is hosted by navigating to `https://www.example.com`
@@ -64,15 +80,34 @@ export async function createOidc(params: {
64
80
  * you are supposed to have created in your `public/` directory.
65
81
  */
66
82
  publicUrl?: string;
67
- }): Promise<Oidc> {
83
+ decodedIdTokenSchema?: { parse: (data: unknown) => DecodedIdToken };
84
+ };
85
+
86
+ /** @see: https://github.com/garronej/oidc-spa#option-1-usage-without-involving-the-ui-framework */
87
+ export async function createOidc<
88
+ DecodedIdToken extends Record<string, unknown> = Record<string, unknown>
89
+ >(params: ParamsOfCreateOidc<DecodedIdToken>): Promise<Oidc<DecodedIdToken>> {
68
90
  const {
69
91
  issuerUri,
70
92
  clientId,
71
93
  transformUrlBeforeRedirect = url => url,
72
- getExtraQueryParams,
73
- publicUrl: publicUrl_params
94
+ extraQueryParams: extraQueryParamsOrGetter,
95
+ publicUrl: publicUrl_params,
96
+ decodedIdTokenSchema
74
97
  } = params;
75
98
 
99
+ const getExtraQueryParams = (() => {
100
+ if (typeof extraQueryParamsOrGetter === "function") {
101
+ return extraQueryParamsOrGetter;
102
+ }
103
+
104
+ if (extraQueryParamsOrGetter !== undefined) {
105
+ return () => extraQueryParamsOrGetter;
106
+ }
107
+
108
+ return undefined;
109
+ })();
110
+
76
111
  const publicUrl = (() => {
77
112
  if (publicUrl_params === undefined) {
78
113
  return window.location.origin;
@@ -88,7 +123,7 @@ export async function createOidc(params: {
88
123
  const configHash = fnv1aHashToHex(`${issuerUri} ${clientId}`);
89
124
  const configHashKey = "configHash";
90
125
 
91
- const userManager = new UserManager({
126
+ const oidcClientTsUserManager = new OidcClientTsUserManager({
92
127
  "authority": issuerUri,
93
128
  "client_id": clientId,
94
129
  "redirect_uri": "" /* provided when calling login */,
@@ -181,14 +216,14 @@ export async function createOidc(params: {
181
216
  document.addEventListener("visibilitychange", callback);
182
217
  }
183
218
 
184
- await userManager.signinRedirect({
219
+ await oidcClientTsUserManager.signinRedirect({
185
220
  redirect_uri,
186
221
  "redirectMethod": doesCurrentHrefRequiresAuth ? "replace" : "assign"
187
222
  });
188
223
  return new Promise<never>(() => {});
189
224
  };
190
225
 
191
- const currentTokens = await (async function getUser() {
226
+ const initialTokens = await (async function getUser() {
192
227
  read_successful_login_query_params: {
193
228
  let url = window.location.href;
194
229
 
@@ -233,33 +268,33 @@ export async function createOidc(params: {
233
268
 
234
269
  window.history.pushState(null, "", url);
235
270
 
236
- let user: User | undefined = undefined;
271
+ let oidcClientTsUser: OidcClientTsUser | undefined = undefined;
237
272
 
238
273
  try {
239
- user = await userManager.signinRedirectCallback(loginSuccessUrl);
274
+ oidcClientTsUser = await oidcClientTsUserManager.signinRedirectCallback(loginSuccessUrl);
240
275
  } catch {
241
276
  //NOTE: The user has likely pressed the back button just after logging in.
242
277
  return undefined;
243
278
  }
244
279
 
245
- return user;
280
+ return oidcClientTsUser;
246
281
  }
247
282
 
248
283
  restore_from_session: {
249
- const user = await userManager.getUser();
284
+ const oidcClientTsUser = await oidcClientTsUserManager.getUser();
250
285
 
251
- if (user === null) {
286
+ if (oidcClientTsUser === null) {
252
287
  break restore_from_session;
253
288
  }
254
289
 
255
290
  // The server might have restarted and the session might have been lost.
256
291
  try {
257
- await userManager.signinSilent();
292
+ await oidcClientTsUserManager.signinSilent();
258
293
  } catch {
259
294
  return undefined;
260
295
  }
261
296
 
262
- return user;
297
+ return oidcClientTsUser;
263
298
  }
264
299
 
265
300
  restore_from_http_only_cookie: {
@@ -334,7 +369,7 @@ export async function createOidc(params: {
334
369
 
335
370
  window.addEventListener("message", listener, false);
336
371
 
337
- userManager
372
+ oidcClientTsUserManager
338
373
  .signinSilent({ "silentRequestTimeoutInSeconds": timeoutDelayMs / 1000 })
339
374
  .catch(() => {
340
375
  /* error expected */
@@ -346,19 +381,24 @@ export async function createOidc(params: {
346
381
  break restore_from_http_only_cookie;
347
382
  }
348
383
 
349
- const user = await userManager.signinRedirectCallback(loginSuccessUrl);
384
+ const oidcClientTsUser = await oidcClientTsUserManager.signinRedirectCallback(
385
+ loginSuccessUrl
386
+ );
350
387
 
351
- return user;
388
+ return oidcClientTsUser;
352
389
  }
353
390
 
354
391
  return undefined;
355
392
  })().then(
356
- user => {
357
- if (user === undefined) {
393
+ oidcClientTsUser => {
394
+ if (oidcClientTsUser === undefined) {
358
395
  return undefined;
359
396
  }
360
397
 
361
- const tokens = userToTokens(user);
398
+ const tokens = oidcClientTsUserToTokens({
399
+ oidcClientTsUser,
400
+ decodedIdTokenSchema
401
+ });
362
402
 
363
403
  if (tokens.refreshTokenExpirationTime < tokens.accessTokenExpirationTime) {
364
404
  console.warn(
@@ -385,8 +425,8 @@ export async function createOidc(params: {
385
425
  }
386
426
  };
387
427
 
388
- if (currentTokens instanceof Error) {
389
- const error = currentTokens;
428
+ if (initialTokens instanceof Error) {
429
+ const error = initialTokens;
390
430
 
391
431
  console.error(`The OIDC server is down or misconfigured: ${error.message}`);
392
432
 
@@ -400,7 +440,7 @@ export async function createOidc(params: {
400
440
  });
401
441
  }
402
442
 
403
- if (currentTokens === undefined) {
443
+ if (initialTokens === undefined) {
404
444
  return id<Oidc.NotLoggedIn>({
405
445
  ...common,
406
446
  "isUserLoggedIn": false,
@@ -408,20 +448,16 @@ export async function createOidc(params: {
408
448
  });
409
449
  }
410
450
 
451
+ let currentTokens = initialTokens;
452
+
411
453
  const onTokenChanges = new Set<() => void>();
412
454
 
413
- const oidc = id<Oidc.LoggedIn>({
455
+ const oidc = id<Oidc.LoggedIn<DecodedIdToken>>({
414
456
  ...common,
415
457
  "isUserLoggedIn": true,
416
- "getTokens": () => ({
417
- "accessToken": currentTokens.accessToken,
418
- "idToken": currentTokens.idToken,
419
- "refreshToken": currentTokens.refreshToken,
420
- "refreshTokenExpirationTime": currentTokens.refreshTokenExpirationTime,
421
- "accessTokenExpirationTime": currentTokens.accessTokenExpirationTime
422
- }),
458
+ "getTokens": () => currentTokens,
423
459
  "logout": async params => {
424
- await userManager.signoutRedirect({
460
+ await oidcClientTsUserManager.signoutRedirect({
425
461
  "post_logout_redirect_uri": (() => {
426
462
  switch (params.redirectTo) {
427
463
  case "current page":
@@ -437,11 +473,24 @@ export async function createOidc(params: {
437
473
  return new Promise<never>(() => {});
438
474
  },
439
475
  "renewTokens": async () => {
440
- const user = await userManager.signinSilent();
476
+ const oidcClientTsUser = await oidcClientTsUserManager.signinSilent();
477
+
478
+ assert(oidcClientTsUser !== null);
441
479
 
442
- assert(user !== null);
480
+ const decodedIdTokenPropertyDescriptor = Object.getOwnPropertyDescriptor(
481
+ currentTokens,
482
+ "decodedIdToken"
483
+ );
443
484
 
444
- Object.assign(currentTokens, userToTokens(user));
485
+ assert(decodedIdTokenPropertyDescriptor !== undefined);
486
+
487
+ currentTokens = oidcClientTsUserToTokens({
488
+ oidcClientTsUser,
489
+ decodedIdTokenSchema
490
+ });
491
+
492
+ // NOTE: We do that to preserve the cache and the object reference.
493
+ Object.defineProperty(currentTokens, "decodedIdToken", decodedIdTokenPropertyDescriptor);
445
494
 
446
495
  onTokenChanges.forEach(onTokenChange => onTokenChange());
447
496
  },
@@ -475,12 +524,17 @@ export async function createOidc(params: {
475
524
  return oidc;
476
525
  }
477
526
 
478
- function userToTokens(user: User): Oidc.Tokens {
479
- const accessToken = user.access_token;
527
+ function oidcClientTsUserToTokens<DecodedIdToken extends Record<string, unknown>>(params: {
528
+ oidcClientTsUser: OidcClientTsUser;
529
+ decodedIdTokenSchema?: { parse: (data: unknown) => DecodedIdToken };
530
+ }): Oidc.Tokens<DecodedIdToken> {
531
+ const { oidcClientTsUser, decodedIdTokenSchema } = params;
532
+
533
+ const accessToken = oidcClientTsUser.access_token;
480
534
 
481
535
  const accessTokenExpirationTime = (() => {
482
536
  read_from_metadata: {
483
- const { expires_at } = user;
537
+ const { expires_at } = oidcClientTsUser;
484
538
 
485
539
  if (expires_at === undefined) {
486
540
  break read_from_metadata;
@@ -502,7 +556,7 @@ function userToTokens(user: User): Oidc.Tokens {
502
556
  assert(false, "Failed to get access token expiration time");
503
557
  })();
504
558
 
505
- const refreshToken = user.refresh_token;
559
+ const refreshToken = oidcClientTsUser.refresh_token;
506
560
 
507
561
  assert(refreshToken !== undefined, "No refresh token provided by the oidc server");
508
562
 
@@ -520,15 +574,48 @@ function userToTokens(user: User): Oidc.Tokens {
520
574
  assert(false, "Failed to get refresh token expiration time");
521
575
  })();
522
576
 
523
- const idToken = user.id_token;
577
+ const idToken = oidcClientTsUser.id_token;
524
578
 
525
579
  assert(idToken !== undefined, "No id token provided by the oidc server");
526
580
 
527
- return {
581
+ const tokens: Oidc.Tokens<DecodedIdToken> = {
528
582
  accessToken,
529
583
  accessTokenExpirationTime,
530
584
  refreshToken,
531
585
  refreshTokenExpirationTime,
532
- idToken
586
+ idToken,
587
+ "decodedIdToken": null as any
533
588
  };
589
+
590
+ let cache:
591
+ | {
592
+ idToken: string;
593
+ decodedIdToken: DecodedIdToken;
594
+ }
595
+ | undefined = undefined;
596
+
597
+ Object.defineProperty(tokens, "decodedIdToken", {
598
+ "get": function (this: Oidc.Tokens<DecodedIdToken>) {
599
+ if (cache !== undefined && cache.idToken === this.idToken) {
600
+ return cache.decodedIdToken;
601
+ }
602
+
603
+ let decodedIdToken = decodeJwt(this.idToken) as DecodedIdToken;
604
+
605
+ if (decodedIdTokenSchema !== undefined) {
606
+ decodedIdToken = decodedIdTokenSchema.parse(decodedIdToken);
607
+ }
608
+
609
+ cache = {
610
+ "idToken": this.idToken,
611
+ decodedIdToken
612
+ };
613
+
614
+ return decodedIdToken;
615
+ },
616
+ "configurable": true,
617
+ "enumerable": true
618
+ });
619
+
620
+ return tokens;
534
621
  }