oidc-spa 3.0.2 → 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/README.md +11 -3
- package/oidc.d.ts +21 -9
- package/oidc.js +94 -47
- 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 +161 -64
- 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,46 @@ 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;
|
|
52
61
|
transformUrlBeforeRedirect?: (url: string) => string;
|
|
53
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
226
|
+
const initialTokens = await (async function getUser() {
|
|
192
227
|
read_successful_login_query_params: {
|
|
193
228
|
let url = window.location.href;
|
|
194
229
|
|
|
@@ -215,7 +250,12 @@ export async function createOidc(params: {
|
|
|
215
250
|
for (const name of paramsToRetrieveFromSuccessfulLogin) {
|
|
216
251
|
const result = retrieveQueryParamFromUrl({ name, url });
|
|
217
252
|
|
|
218
|
-
|
|
253
|
+
if (!result.wasPresent) {
|
|
254
|
+
if (name === "iss") {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
throw new Error(`Missing query param: ${name}`);
|
|
258
|
+
}
|
|
219
259
|
|
|
220
260
|
loginSuccessUrl = addQueryParamToUrl({
|
|
221
261
|
"url": loginSuccessUrl,
|
|
@@ -228,33 +268,33 @@ export async function createOidc(params: {
|
|
|
228
268
|
|
|
229
269
|
window.history.pushState(null, "", url);
|
|
230
270
|
|
|
231
|
-
let
|
|
271
|
+
let oidcClientTsUser: OidcClientTsUser | undefined = undefined;
|
|
232
272
|
|
|
233
273
|
try {
|
|
234
|
-
|
|
274
|
+
oidcClientTsUser = await oidcClientTsUserManager.signinRedirectCallback(loginSuccessUrl);
|
|
235
275
|
} catch {
|
|
236
276
|
//NOTE: The user has likely pressed the back button just after logging in.
|
|
237
277
|
return undefined;
|
|
238
278
|
}
|
|
239
279
|
|
|
240
|
-
return
|
|
280
|
+
return oidcClientTsUser;
|
|
241
281
|
}
|
|
242
282
|
|
|
243
283
|
restore_from_session: {
|
|
244
|
-
const
|
|
284
|
+
const oidcClientTsUser = await oidcClientTsUserManager.getUser();
|
|
245
285
|
|
|
246
|
-
if (
|
|
286
|
+
if (oidcClientTsUser === null) {
|
|
247
287
|
break restore_from_session;
|
|
248
288
|
}
|
|
249
289
|
|
|
250
290
|
// The server might have restarted and the session might have been lost.
|
|
251
291
|
try {
|
|
252
|
-
await
|
|
292
|
+
await oidcClientTsUserManager.signinSilent();
|
|
253
293
|
} catch {
|
|
254
294
|
return undefined;
|
|
255
295
|
}
|
|
256
296
|
|
|
257
|
-
return
|
|
297
|
+
return oidcClientTsUser;
|
|
258
298
|
}
|
|
259
299
|
|
|
260
300
|
restore_from_http_only_cookie: {
|
|
@@ -310,7 +350,12 @@ export async function createOidc(params: {
|
|
|
310
350
|
for (const name of paramsToRetrieveFromSuccessfulLogin) {
|
|
311
351
|
const result = retrieveQueryParamFromUrl({ name, url });
|
|
312
352
|
|
|
313
|
-
|
|
353
|
+
if (!result.wasPresent) {
|
|
354
|
+
if (name === "iss") {
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
throw new Error(`Missing query param: ${name}`);
|
|
358
|
+
}
|
|
314
359
|
|
|
315
360
|
loginSuccessUrl = addQueryParamToUrl({
|
|
316
361
|
"url": loginSuccessUrl,
|
|
@@ -324,7 +369,7 @@ export async function createOidc(params: {
|
|
|
324
369
|
|
|
325
370
|
window.addEventListener("message", listener, false);
|
|
326
371
|
|
|
327
|
-
|
|
372
|
+
oidcClientTsUserManager
|
|
328
373
|
.signinSilent({ "silentRequestTimeoutInSeconds": timeoutDelayMs / 1000 })
|
|
329
374
|
.catch(() => {
|
|
330
375
|
/* error expected */
|
|
@@ -336,19 +381,24 @@ export async function createOidc(params: {
|
|
|
336
381
|
break restore_from_http_only_cookie;
|
|
337
382
|
}
|
|
338
383
|
|
|
339
|
-
const
|
|
384
|
+
const oidcClientTsUser = await oidcClientTsUserManager.signinRedirectCallback(
|
|
385
|
+
loginSuccessUrl
|
|
386
|
+
);
|
|
340
387
|
|
|
341
|
-
return
|
|
388
|
+
return oidcClientTsUser;
|
|
342
389
|
}
|
|
343
390
|
|
|
344
391
|
return undefined;
|
|
345
392
|
})().then(
|
|
346
|
-
|
|
347
|
-
if (
|
|
393
|
+
oidcClientTsUser => {
|
|
394
|
+
if (oidcClientTsUser === undefined) {
|
|
348
395
|
return undefined;
|
|
349
396
|
}
|
|
350
397
|
|
|
351
|
-
const tokens =
|
|
398
|
+
const tokens = oidcClientTsUserToTokens({
|
|
399
|
+
oidcClientTsUser,
|
|
400
|
+
decodedIdTokenSchema
|
|
401
|
+
});
|
|
352
402
|
|
|
353
403
|
if (tokens.refreshTokenExpirationTime < tokens.accessTokenExpirationTime) {
|
|
354
404
|
console.warn(
|
|
@@ -375,8 +425,8 @@ export async function createOidc(params: {
|
|
|
375
425
|
}
|
|
376
426
|
};
|
|
377
427
|
|
|
378
|
-
if (
|
|
379
|
-
const error =
|
|
428
|
+
if (initialTokens instanceof Error) {
|
|
429
|
+
const error = initialTokens;
|
|
380
430
|
|
|
381
431
|
console.error(`The OIDC server is down or misconfigured: ${error.message}`);
|
|
382
432
|
|
|
@@ -390,7 +440,7 @@ export async function createOidc(params: {
|
|
|
390
440
|
});
|
|
391
441
|
}
|
|
392
442
|
|
|
393
|
-
if (
|
|
443
|
+
if (initialTokens === undefined) {
|
|
394
444
|
return id<Oidc.NotLoggedIn>({
|
|
395
445
|
...common,
|
|
396
446
|
"isUserLoggedIn": false,
|
|
@@ -398,20 +448,16 @@ export async function createOidc(params: {
|
|
|
398
448
|
});
|
|
399
449
|
}
|
|
400
450
|
|
|
451
|
+
let currentTokens = initialTokens;
|
|
452
|
+
|
|
401
453
|
const onTokenChanges = new Set<() => void>();
|
|
402
454
|
|
|
403
|
-
const oidc = id<Oidc.LoggedIn
|
|
455
|
+
const oidc = id<Oidc.LoggedIn<DecodedIdToken>>({
|
|
404
456
|
...common,
|
|
405
457
|
"isUserLoggedIn": true,
|
|
406
|
-
"getTokens": () =>
|
|
407
|
-
"accessToken": currentTokens.accessToken,
|
|
408
|
-
"idToken": currentTokens.idToken,
|
|
409
|
-
"refreshToken": currentTokens.refreshToken,
|
|
410
|
-
"refreshTokenExpirationTime": currentTokens.refreshTokenExpirationTime,
|
|
411
|
-
"accessTokenExpirationTime": currentTokens.accessTokenExpirationTime
|
|
412
|
-
}),
|
|
458
|
+
"getTokens": () => currentTokens,
|
|
413
459
|
"logout": async params => {
|
|
414
|
-
await
|
|
460
|
+
await oidcClientTsUserManager.signoutRedirect({
|
|
415
461
|
"post_logout_redirect_uri": (() => {
|
|
416
462
|
switch (params.redirectTo) {
|
|
417
463
|
case "current page":
|
|
@@ -427,11 +473,24 @@ export async function createOidc(params: {
|
|
|
427
473
|
return new Promise<never>(() => {});
|
|
428
474
|
},
|
|
429
475
|
"renewTokens": async () => {
|
|
430
|
-
const
|
|
476
|
+
const oidcClientTsUser = await oidcClientTsUserManager.signinSilent();
|
|
477
|
+
|
|
478
|
+
assert(oidcClientTsUser !== null);
|
|
479
|
+
|
|
480
|
+
const decodedIdTokenPropertyDescriptor = Object.getOwnPropertyDescriptor(
|
|
481
|
+
currentTokens,
|
|
482
|
+
"decodedIdToken"
|
|
483
|
+
);
|
|
431
484
|
|
|
432
|
-
assert(
|
|
485
|
+
assert(decodedIdTokenPropertyDescriptor !== undefined);
|
|
433
486
|
|
|
434
|
-
|
|
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);
|
|
435
494
|
|
|
436
495
|
onTokenChanges.forEach(onTokenChange => onTokenChange());
|
|
437
496
|
},
|
|
@@ -465,12 +524,17 @@ export async function createOidc(params: {
|
|
|
465
524
|
return oidc;
|
|
466
525
|
}
|
|
467
526
|
|
|
468
|
-
function
|
|
469
|
-
|
|
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;
|
|
470
534
|
|
|
471
535
|
const accessTokenExpirationTime = (() => {
|
|
472
536
|
read_from_metadata: {
|
|
473
|
-
const { expires_at } =
|
|
537
|
+
const { expires_at } = oidcClientTsUser;
|
|
474
538
|
|
|
475
539
|
if (expires_at === undefined) {
|
|
476
540
|
break read_from_metadata;
|
|
@@ -492,7 +556,7 @@ function userToTokens(user: User): Oidc.Tokens {
|
|
|
492
556
|
assert(false, "Failed to get access token expiration time");
|
|
493
557
|
})();
|
|
494
558
|
|
|
495
|
-
const refreshToken =
|
|
559
|
+
const refreshToken = oidcClientTsUser.refresh_token;
|
|
496
560
|
|
|
497
561
|
assert(refreshToken !== undefined, "No refresh token provided by the oidc server");
|
|
498
562
|
|
|
@@ -510,15 +574,48 @@ function userToTokens(user: User): Oidc.Tokens {
|
|
|
510
574
|
assert(false, "Failed to get refresh token expiration time");
|
|
511
575
|
})();
|
|
512
576
|
|
|
513
|
-
const idToken =
|
|
577
|
+
const idToken = oidcClientTsUser.id_token;
|
|
514
578
|
|
|
515
579
|
assert(idToken !== undefined, "No id token provided by the oidc server");
|
|
516
580
|
|
|
517
|
-
|
|
581
|
+
const tokens: Oidc.Tokens<DecodedIdToken> = {
|
|
518
582
|
accessToken,
|
|
519
583
|
accessTokenExpirationTime,
|
|
520
584
|
refreshToken,
|
|
521
585
|
refreshTokenExpirationTime,
|
|
522
|
-
idToken
|
|
586
|
+
idToken,
|
|
587
|
+
"decodedIdToken": null as any
|
|
523
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;
|
|
524
621
|
}
|