oidc-spa 3.0.3 → 4.1.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":"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"}
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,47 @@ 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;
61
+ clientSecret?: string;
52
62
  transformUrlBeforeRedirect?: (url: string) => string;
53
- getExtraQueryParams?: () => Record<string, string>;
63
+ /**
64
+ * Extra query params to be added on the login url.
65
+ * You can provide a function that returns those extra query params, it will be called
66
+ * when login() is called.
67
+ *
68
+ * Example: extraQueryParams: ()=> ({ ui_locales: "fr" })
69
+ */
70
+ extraQueryParams?: Record<string, string> | (() => Record<string, string>);
54
71
  /**
55
72
  * This parameter have to be provided if your App is not hosted at the origin of the subdomain.
56
73
  * For example if your site is hosted by navigating to `https://www.example.com`
@@ -64,15 +81,35 @@ export async function createOidc(params: {
64
81
  * you are supposed to have created in your `public/` directory.
65
82
  */
66
83
  publicUrl?: string;
67
- }): Promise<Oidc> {
84
+ decodedIdTokenSchema?: { parse: (data: unknown) => DecodedIdToken };
85
+ };
86
+
87
+ /** @see: https://github.com/garronej/oidc-spa#option-1-usage-without-involving-the-ui-framework */
88
+ export async function createOidc<
89
+ DecodedIdToken extends Record<string, unknown> = Record<string, unknown>
90
+ >(params: ParamsOfCreateOidc<DecodedIdToken>): Promise<Oidc<DecodedIdToken>> {
68
91
  const {
69
92
  issuerUri,
70
93
  clientId,
94
+ clientSecret,
71
95
  transformUrlBeforeRedirect = url => url,
72
- getExtraQueryParams,
73
- publicUrl: publicUrl_params
96
+ extraQueryParams: extraQueryParamsOrGetter,
97
+ publicUrl: publicUrl_params,
98
+ decodedIdTokenSchema
74
99
  } = params;
75
100
 
101
+ const getExtraQueryParams = (() => {
102
+ if (typeof extraQueryParamsOrGetter === "function") {
103
+ return extraQueryParamsOrGetter;
104
+ }
105
+
106
+ if (extraQueryParamsOrGetter !== undefined) {
107
+ return () => extraQueryParamsOrGetter;
108
+ }
109
+
110
+ return undefined;
111
+ })();
112
+
76
113
  const publicUrl = (() => {
77
114
  if (publicUrl_params === undefined) {
78
115
  return window.location.origin;
@@ -88,9 +125,10 @@ export async function createOidc(params: {
88
125
  const configHash = fnv1aHashToHex(`${issuerUri} ${clientId}`);
89
126
  const configHashKey = "configHash";
90
127
 
91
- const userManager = new UserManager({
128
+ const oidcClientTsUserManager = new OidcClientTsUserManager({
92
129
  "authority": issuerUri,
93
130
  "client_id": clientId,
131
+ "client_secret": clientSecret,
94
132
  "redirect_uri": "" /* provided when calling login */,
95
133
  "response_type": "code",
96
134
  "scope": "openid profile",
@@ -181,14 +219,14 @@ export async function createOidc(params: {
181
219
  document.addEventListener("visibilitychange", callback);
182
220
  }
183
221
 
184
- await userManager.signinRedirect({
222
+ await oidcClientTsUserManager.signinRedirect({
185
223
  redirect_uri,
186
224
  "redirectMethod": doesCurrentHrefRequiresAuth ? "replace" : "assign"
187
225
  });
188
226
  return new Promise<never>(() => {});
189
227
  };
190
228
 
191
- const currentTokens = await (async function getUser() {
229
+ const initialTokens = await (async function getUser() {
192
230
  read_successful_login_query_params: {
193
231
  let url = window.location.href;
194
232
 
@@ -233,33 +271,33 @@ export async function createOidc(params: {
233
271
 
234
272
  window.history.pushState(null, "", url);
235
273
 
236
- let user: User | undefined = undefined;
274
+ let oidcClientTsUser: OidcClientTsUser | undefined = undefined;
237
275
 
238
276
  try {
239
- user = await userManager.signinRedirectCallback(loginSuccessUrl);
277
+ oidcClientTsUser = await oidcClientTsUserManager.signinRedirectCallback(loginSuccessUrl);
240
278
  } catch {
241
279
  //NOTE: The user has likely pressed the back button just after logging in.
242
280
  return undefined;
243
281
  }
244
282
 
245
- return user;
283
+ return oidcClientTsUser;
246
284
  }
247
285
 
248
286
  restore_from_session: {
249
- const user = await userManager.getUser();
287
+ const oidcClientTsUser = await oidcClientTsUserManager.getUser();
250
288
 
251
- if (user === null) {
289
+ if (oidcClientTsUser === null) {
252
290
  break restore_from_session;
253
291
  }
254
292
 
255
293
  // The server might have restarted and the session might have been lost.
256
294
  try {
257
- await userManager.signinSilent();
295
+ await oidcClientTsUserManager.signinSilent();
258
296
  } catch {
259
297
  return undefined;
260
298
  }
261
299
 
262
- return user;
300
+ return oidcClientTsUser;
263
301
  }
264
302
 
265
303
  restore_from_http_only_cookie: {
@@ -334,7 +372,7 @@ export async function createOidc(params: {
334
372
 
335
373
  window.addEventListener("message", listener, false);
336
374
 
337
- userManager
375
+ oidcClientTsUserManager
338
376
  .signinSilent({ "silentRequestTimeoutInSeconds": timeoutDelayMs / 1000 })
339
377
  .catch(() => {
340
378
  /* error expected */
@@ -346,19 +384,24 @@ export async function createOidc(params: {
346
384
  break restore_from_http_only_cookie;
347
385
  }
348
386
 
349
- const user = await userManager.signinRedirectCallback(loginSuccessUrl);
387
+ const oidcClientTsUser = await oidcClientTsUserManager.signinRedirectCallback(
388
+ loginSuccessUrl
389
+ );
350
390
 
351
- return user;
391
+ return oidcClientTsUser;
352
392
  }
353
393
 
354
394
  return undefined;
355
395
  })().then(
356
- user => {
357
- if (user === undefined) {
396
+ oidcClientTsUser => {
397
+ if (oidcClientTsUser === undefined) {
358
398
  return undefined;
359
399
  }
360
400
 
361
- const tokens = userToTokens(user);
401
+ const tokens = oidcClientTsUserToTokens({
402
+ oidcClientTsUser,
403
+ decodedIdTokenSchema
404
+ });
362
405
 
363
406
  if (tokens.refreshTokenExpirationTime < tokens.accessTokenExpirationTime) {
364
407
  console.warn(
@@ -385,8 +428,8 @@ export async function createOidc(params: {
385
428
  }
386
429
  };
387
430
 
388
- if (currentTokens instanceof Error) {
389
- const error = currentTokens;
431
+ if (initialTokens instanceof Error) {
432
+ const error = initialTokens;
390
433
 
391
434
  console.error(`The OIDC server is down or misconfigured: ${error.message}`);
392
435
 
@@ -400,7 +443,7 @@ export async function createOidc(params: {
400
443
  });
401
444
  }
402
445
 
403
- if (currentTokens === undefined) {
446
+ if (initialTokens === undefined) {
404
447
  return id<Oidc.NotLoggedIn>({
405
448
  ...common,
406
449
  "isUserLoggedIn": false,
@@ -408,20 +451,16 @@ export async function createOidc(params: {
408
451
  });
409
452
  }
410
453
 
454
+ let currentTokens = initialTokens;
455
+
411
456
  const onTokenChanges = new Set<() => void>();
412
457
 
413
- const oidc = id<Oidc.LoggedIn>({
458
+ const oidc = id<Oidc.LoggedIn<DecodedIdToken>>({
414
459
  ...common,
415
460
  "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
- }),
461
+ "getTokens": () => currentTokens,
423
462
  "logout": async params => {
424
- await userManager.signoutRedirect({
463
+ await oidcClientTsUserManager.signoutRedirect({
425
464
  "post_logout_redirect_uri": (() => {
426
465
  switch (params.redirectTo) {
427
466
  case "current page":
@@ -437,11 +476,24 @@ export async function createOidc(params: {
437
476
  return new Promise<never>(() => {});
438
477
  },
439
478
  "renewTokens": async () => {
440
- const user = await userManager.signinSilent();
479
+ const oidcClientTsUser = await oidcClientTsUserManager.signinSilent();
480
+
481
+ assert(oidcClientTsUser !== null);
441
482
 
442
- assert(user !== null);
483
+ const decodedIdTokenPropertyDescriptor = Object.getOwnPropertyDescriptor(
484
+ currentTokens,
485
+ "decodedIdToken"
486
+ );
443
487
 
444
- Object.assign(currentTokens, userToTokens(user));
488
+ assert(decodedIdTokenPropertyDescriptor !== undefined);
489
+
490
+ currentTokens = oidcClientTsUserToTokens({
491
+ oidcClientTsUser,
492
+ decodedIdTokenSchema
493
+ });
494
+
495
+ // NOTE: We do that to preserve the cache and the object reference.
496
+ Object.defineProperty(currentTokens, "decodedIdToken", decodedIdTokenPropertyDescriptor);
445
497
 
446
498
  onTokenChanges.forEach(onTokenChange => onTokenChange());
447
499
  },
@@ -475,12 +527,17 @@ export async function createOidc(params: {
475
527
  return oidc;
476
528
  }
477
529
 
478
- function userToTokens(user: User): Oidc.Tokens {
479
- const accessToken = user.access_token;
530
+ function oidcClientTsUserToTokens<DecodedIdToken extends Record<string, unknown>>(params: {
531
+ oidcClientTsUser: OidcClientTsUser;
532
+ decodedIdTokenSchema?: { parse: (data: unknown) => DecodedIdToken };
533
+ }): Oidc.Tokens<DecodedIdToken> {
534
+ const { oidcClientTsUser, decodedIdTokenSchema } = params;
535
+
536
+ const accessToken = oidcClientTsUser.access_token;
480
537
 
481
538
  const accessTokenExpirationTime = (() => {
482
539
  read_from_metadata: {
483
- const { expires_at } = user;
540
+ const { expires_at } = oidcClientTsUser;
484
541
 
485
542
  if (expires_at === undefined) {
486
543
  break read_from_metadata;
@@ -502,7 +559,7 @@ function userToTokens(user: User): Oidc.Tokens {
502
559
  assert(false, "Failed to get access token expiration time");
503
560
  })();
504
561
 
505
- const refreshToken = user.refresh_token;
562
+ const refreshToken = oidcClientTsUser.refresh_token;
506
563
 
507
564
  assert(refreshToken !== undefined, "No refresh token provided by the oidc server");
508
565
 
@@ -520,15 +577,48 @@ function userToTokens(user: User): Oidc.Tokens {
520
577
  assert(false, "Failed to get refresh token expiration time");
521
578
  })();
522
579
 
523
- const idToken = user.id_token;
580
+ const idToken = oidcClientTsUser.id_token;
524
581
 
525
582
  assert(idToken !== undefined, "No id token provided by the oidc server");
526
583
 
527
- return {
584
+ const tokens: Oidc.Tokens<DecodedIdToken> = {
528
585
  accessToken,
529
586
  accessTokenExpirationTime,
530
587
  refreshToken,
531
588
  refreshTokenExpirationTime,
532
- idToken
589
+ idToken,
590
+ "decodedIdToken": null as any
533
591
  };
592
+
593
+ let cache:
594
+ | {
595
+ idToken: string;
596
+ decodedIdToken: DecodedIdToken;
597
+ }
598
+ | undefined = undefined;
599
+
600
+ Object.defineProperty(tokens, "decodedIdToken", {
601
+ "get": function (this: Oidc.Tokens<DecodedIdToken>) {
602
+ if (cache !== undefined && cache.idToken === this.idToken) {
603
+ return cache.decodedIdToken;
604
+ }
605
+
606
+ let decodedIdToken = decodeJwt(this.idToken) as DecodedIdToken;
607
+
608
+ if (decodedIdTokenSchema !== undefined) {
609
+ decodedIdToken = decodedIdTokenSchema.parse(decodedIdToken);
610
+ }
611
+
612
+ cache = {
613
+ "idToken": this.idToken,
614
+ decodedIdToken
615
+ };
616
+
617
+ return decodedIdToken;
618
+ },
619
+ "configurable": true,
620
+ "enumerable": true
621
+ });
622
+
623
+ return tokens;
534
624
  }