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/README.md +11 -3
- package/oidc.d.ts +22 -9
- package/oidc.js +83 -45
- package/oidc.js.map +1 -1
- package/package.json +14 -9
- package/react.d.ts +16 -24
- package/react.js +54 -27
- package/react.js.map +1 -1
- package/src/oidc.ts +152 -62
- package/src/react.tsx +118 -85
- package/src/tools/powerhooks/useGuaranteedMemo.ts +18 -0
- package/tools/powerhooks/useGuaranteedMemo.d.ts +1 -0
- package/tools/powerhooks/useGuaranteedMemo.js +43 -0
- package/tools/powerhooks/useGuaranteedMemo.js.map +1 -0
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.
|
|
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
|
|
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
|
|
60
|
-
|
|
61
|
-
|
|
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
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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)(
|
|
88
|
-
: (0, id_1.id)(__assign(__assign({}, common), { "isUserLoggedIn": false, "login": oidc.login
|
|
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.
|
|
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,+
|
|
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 =
|
|
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 =
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
49
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
274
|
+
let oidcClientTsUser: OidcClientTsUser | undefined = undefined;
|
|
237
275
|
|
|
238
276
|
try {
|
|
239
|
-
|
|
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
|
|
283
|
+
return oidcClientTsUser;
|
|
246
284
|
}
|
|
247
285
|
|
|
248
286
|
restore_from_session: {
|
|
249
|
-
const
|
|
287
|
+
const oidcClientTsUser = await oidcClientTsUserManager.getUser();
|
|
250
288
|
|
|
251
|
-
if (
|
|
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
|
|
295
|
+
await oidcClientTsUserManager.signinSilent();
|
|
258
296
|
} catch {
|
|
259
297
|
return undefined;
|
|
260
298
|
}
|
|
261
299
|
|
|
262
|
-
return
|
|
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
|
-
|
|
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
|
|
387
|
+
const oidcClientTsUser = await oidcClientTsUserManager.signinRedirectCallback(
|
|
388
|
+
loginSuccessUrl
|
|
389
|
+
);
|
|
350
390
|
|
|
351
|
-
return
|
|
391
|
+
return oidcClientTsUser;
|
|
352
392
|
}
|
|
353
393
|
|
|
354
394
|
return undefined;
|
|
355
395
|
})().then(
|
|
356
|
-
|
|
357
|
-
if (
|
|
396
|
+
oidcClientTsUser => {
|
|
397
|
+
if (oidcClientTsUser === undefined) {
|
|
358
398
|
return undefined;
|
|
359
399
|
}
|
|
360
400
|
|
|
361
|
-
const tokens =
|
|
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 (
|
|
389
|
-
const error =
|
|
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 (
|
|
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
|
|
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
|
|
479
|
+
const oidcClientTsUser = await oidcClientTsUserManager.signinSilent();
|
|
480
|
+
|
|
481
|
+
assert(oidcClientTsUser !== null);
|
|
441
482
|
|
|
442
|
-
|
|
483
|
+
const decodedIdTokenPropertyDescriptor = Object.getOwnPropertyDescriptor(
|
|
484
|
+
currentTokens,
|
|
485
|
+
"decodedIdToken"
|
|
486
|
+
);
|
|
443
487
|
|
|
444
|
-
|
|
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
|
|
479
|
-
|
|
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 } =
|
|
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 =
|
|
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 =
|
|
580
|
+
const idToken = oidcClientTsUser.id_token;
|
|
524
581
|
|
|
525
582
|
assert(idToken !== undefined, "No id token provided by the oidc server");
|
|
526
583
|
|
|
527
|
-
|
|
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
|
}
|