@axa-fr/react-oidc 6.0.0-beta8 → 6.0.1
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 +13 -4
- package/dist/FetchToken.d.ts.map +1 -1
- package/dist/FetchToken.js +10 -6
- package/dist/FetchToken.js.map +1 -1
- package/dist/OidcProvider.d.ts +1 -0
- package/dist/OidcProvider.d.ts.map +1 -1
- package/dist/OidcProvider.js +11 -4
- package/dist/OidcProvider.js.map +1 -1
- package/dist/OidcSecure.js +2 -2
- package/dist/OidcSecure.js.map +1 -1
- package/dist/OidcServiceWorker.js +62 -32
- package/dist/OidcTrustedDomains.js +7 -2
- package/dist/ReactOidc.d.ts.map +1 -1
- package/dist/ReactOidc.js +4 -3
- package/dist/ReactOidc.js.map +1 -1
- package/dist/core/default-component/SilentLogin.component.js +1 -1
- package/dist/core/default-component/SilentLogin.component.js.map +1 -1
- package/dist/core/routes/OidcRoutes.d.ts.map +1 -1
- package/dist/core/routes/OidcRoutes.js +1 -4
- package/dist/core/routes/OidcRoutes.js.map +1 -1
- package/dist/vanilla/initSession.d.ts +2 -1
- package/dist/vanilla/initSession.d.ts.map +1 -1
- package/dist/vanilla/initSession.js +7 -7
- package/dist/vanilla/initSession.js.map +1 -1
- package/dist/vanilla/initWorker.d.ts +2 -3
- package/dist/vanilla/initWorker.d.ts.map +1 -1
- package/dist/vanilla/initWorker.js +6 -21
- package/dist/vanilla/initWorker.js.map +1 -1
- package/dist/vanilla/oidc.d.ts +10 -5
- package/dist/vanilla/oidc.d.ts.map +1 -1
- package/dist/vanilla/oidc.js +462 -469
- package/dist/vanilla/oidc.js.map +1 -1
- package/dist/vanilla/parseTokens.d.ts +5 -0
- package/dist/vanilla/parseTokens.d.ts.map +1 -0
- package/dist/vanilla/parseTokens.js +107 -0
- package/dist/vanilla/parseTokens.js.map +1 -0
- package/package.json +3 -3
- package/src/oidc/FetchToken.tsx +7 -4
- package/src/oidc/OidcProvider.tsx +9 -0
- package/src/oidc/OidcSecure.tsx +2 -2
- package/src/oidc/ReactOidc.tsx +4 -3
- package/src/oidc/core/default-component/SilentLogin.component.tsx +1 -1
- package/src/oidc/core/routes/OidcRoutes.tsx +0 -4
- package/src/oidc/vanilla/OidcServiceWorker.js +62 -32
- package/src/oidc/vanilla/OidcTrustedDomains.js +7 -2
- package/src/oidc/vanilla/initSession.ts +6 -7
- package/src/oidc/vanilla/initWorker.ts +6 -15
- package/src/oidc/vanilla/oidc.ts +221 -265
- package/src/oidc/vanilla/parseTokens.ts +107 -0
- package/dist/core/default-component/ServiceWorkerInstall.component.d.ts +0 -4
- package/dist/core/default-component/ServiceWorkerInstall.component.d.ts.map +0 -1
- package/dist/core/default-component/ServiceWorkerInstall.component.js +0 -131
- package/dist/core/default-component/ServiceWorkerInstall.component.js.map +0 -1
- package/src/oidc/core/default-component/ServiceWorkerInstall.component.tsx +0 -60
package/src/oidc/vanilla/oidc.ts
CHANGED
|
@@ -19,6 +19,7 @@ import timer from './timer';
|
|
|
19
19
|
import {CheckSessionIFrame} from "./checkSessionIFrame"
|
|
20
20
|
import {getParseQueryStringFromLocation} from "./route-utils";
|
|
21
21
|
import {AuthorizationServiceConfigurationJson} from "@openid/appauth/src/authorization_service_configuration";
|
|
22
|
+
import {computeTimeLeft, isTokensValid, parseOriginalTokens, setTokens} from "./parseTokens";
|
|
22
23
|
|
|
23
24
|
const performTokenRequestAsync= async (url, details, extras) => {
|
|
24
25
|
|
|
@@ -47,22 +48,9 @@ const performTokenRequestAsync= async (url, details, extras) => {
|
|
|
47
48
|
return {success:false, status: response.status}
|
|
48
49
|
}
|
|
49
50
|
const tokens = await response.json();
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
tokens.issued_at = currentTimeUnixSecond;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return { success : true,
|
|
57
|
-
data : {
|
|
58
|
-
accessToken: tokens.access_token,
|
|
59
|
-
expiresIn: tokens.expires_in,
|
|
60
|
-
idToken: tokens.id_token,
|
|
61
|
-
refreshToken: tokens.refresh_token,
|
|
62
|
-
scope: tokens.scope,
|
|
63
|
-
tokenType: tokens.token_type,
|
|
64
|
-
issuedAt: tokens.issued_at
|
|
65
|
-
}
|
|
51
|
+
return {
|
|
52
|
+
success : true,
|
|
53
|
+
data: parseOriginalTokens(tokens)
|
|
66
54
|
};
|
|
67
55
|
}
|
|
68
56
|
|
|
@@ -82,7 +70,6 @@ const internalFetch = async (url, headers, numberRetry=0) => {
|
|
|
82
70
|
throw e;
|
|
83
71
|
}
|
|
84
72
|
} else {
|
|
85
|
-
|
|
86
73
|
console.error(e.message);
|
|
87
74
|
throw e; // rethrow other unexpected errors
|
|
88
75
|
}
|
|
@@ -108,36 +95,6 @@ export class OidcAuthorizationServiceConfiguration extends AuthorizationServiceC
|
|
|
108
95
|
|
|
109
96
|
}
|
|
110
97
|
|
|
111
|
-
const idTokenPayload = (token) => {
|
|
112
|
-
const base64Url = token.split('.')[1];
|
|
113
|
-
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
|
114
|
-
const jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
|
|
115
|
-
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
|
116
|
-
}).join(''));
|
|
117
|
-
|
|
118
|
-
return JSON.parse(jsonPayload);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const countLetter = (str, find)=> {
|
|
122
|
-
return (str.split(find)).length - 1;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const extractAccessTokenPayload = tokens => {
|
|
126
|
-
if(tokens.accessTokenPayload)
|
|
127
|
-
{
|
|
128
|
-
return tokens.accessTokenPayload;
|
|
129
|
-
}
|
|
130
|
-
const accessToken = tokens.accessToken;
|
|
131
|
-
try{
|
|
132
|
-
if (!accessToken || countLetter(accessToken,'.') != 2) {
|
|
133
|
-
return null;
|
|
134
|
-
}
|
|
135
|
-
return JSON.parse(atob(accessToken.split('.')[1]));
|
|
136
|
-
} catch (e) {
|
|
137
|
-
console.warn(e);
|
|
138
|
-
}
|
|
139
|
-
return null;
|
|
140
|
-
};
|
|
141
98
|
|
|
142
99
|
export interface StringMap {
|
|
143
100
|
[key: string]: string;
|
|
@@ -193,42 +150,45 @@ const loginCallbackWithAutoTokensRenewAsync = async (oidc) => {
|
|
|
193
150
|
}
|
|
194
151
|
|
|
195
152
|
const autoRenewTokens = (oidc, refreshToken, expiresAt) => {
|
|
196
|
-
const refreshTimeBeforeTokensExpirationInSecond = oidc.configuration.refresh_time_before_tokens_expiration_in_second
|
|
153
|
+
const refreshTimeBeforeTokensExpirationInSecond = oidc.configuration.refresh_time_before_tokens_expiration_in_second;
|
|
197
154
|
return timer.setTimeout(async () => {
|
|
198
|
-
const
|
|
199
|
-
const timeInfo = { timeLeft
|
|
155
|
+
const timeLeft = computeTimeLeft(refreshTimeBeforeTokensExpirationInSecond, expiresAt);
|
|
156
|
+
const timeInfo = { timeLeft };
|
|
200
157
|
oidc.publishEvent(Oidc.eventNames.token_timer, timeInfo);
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
oidc.tokens= await setTokensAsync(oidc.serviceWorker, tokens);
|
|
158
|
+
const {tokens, status} = await oidc.synchroniseTokensAsync(refreshToken);
|
|
159
|
+
oidc.tokens= tokens;
|
|
204
160
|
if(!oidc.serviceWorker){
|
|
205
161
|
await oidc.session.setTokens(oidc.tokens);
|
|
206
162
|
}
|
|
207
163
|
if(!oidc.tokens){
|
|
208
|
-
|
|
209
|
-
oidc.checkSessionIFrame.stop();
|
|
210
|
-
oidc.checkSessionIFrame = null;
|
|
211
|
-
}
|
|
164
|
+
await oidc.destroyAsync(status);
|
|
212
165
|
return;
|
|
213
166
|
}
|
|
214
|
-
|
|
167
|
+
|
|
215
168
|
if(oidc.timeoutId) {
|
|
216
169
|
oidc.timeoutId = autoRenewTokens(oidc, tokens.refreshToken, oidc.tokens.expiresAt);
|
|
217
170
|
}
|
|
218
|
-
|
|
219
|
-
const tokens = await oidc.syncTokensAsync();
|
|
220
|
-
if(tokens && oidc.timeoutId) {
|
|
221
|
-
oidc.timeoutId = autoRenewTokens(oidc, tokens.refreshToken, expiresAt);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
171
|
+
|
|
224
172
|
}, 1000);
|
|
225
173
|
}
|
|
226
174
|
|
|
227
175
|
const getLoginSessionKey = (configurationName:string, redirectUri:string) => {
|
|
228
176
|
return `oidc_login.${configurationName}:${redirectUri}`;
|
|
229
177
|
}
|
|
178
|
+
|
|
179
|
+
const setLoginParams = (configurationName:string, redirectUri:string, data) =>{
|
|
180
|
+
const sessionKey = getLoginSessionKey(configurationName, redirectUri);
|
|
181
|
+
getLoginParamsCache = data
|
|
182
|
+
sessionStorage[sessionKey] = JSON.stringify(data);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
let getLoginParamsCache = null;
|
|
230
186
|
const getLoginParams = (configurationName, redirectUri) => {
|
|
231
|
-
|
|
187
|
+
const dataString = sessionStorage[getLoginSessionKey(configurationName, redirectUri)];
|
|
188
|
+
if(!getLoginParamsCache){
|
|
189
|
+
getLoginParamsCache = JSON.parse(dataString);
|
|
190
|
+
}
|
|
191
|
+
return getLoginParamsCache;
|
|
232
192
|
}
|
|
233
193
|
|
|
234
194
|
const userInfoAsync = async (oidc) => {
|
|
@@ -238,11 +198,15 @@ const userInfoAsync = async (oidc) => {
|
|
|
238
198
|
if(!oidc.tokens){
|
|
239
199
|
return null;
|
|
240
200
|
}
|
|
241
|
-
if(oidc.syncTokensAsyncPromise){
|
|
242
|
-
await oidc.syncTokensAsyncPromise;
|
|
243
|
-
}
|
|
244
201
|
const accessToken = oidc.tokens.accessToken;
|
|
245
|
-
|
|
202
|
+
if(!accessToken){
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
// We wait the synchronisation before making a request
|
|
206
|
+
while (oidc.tokens && !isTokensValid(oidc.tokens)){
|
|
207
|
+
await sleepAsync(200);
|
|
208
|
+
}
|
|
209
|
+
|
|
246
210
|
const oidcServerConfiguration = await oidc.initAsync(oidc.configuration.authority, oidc.configuration.authority_configuration);
|
|
247
211
|
const url = oidcServerConfiguration.userInfoEndpoint;
|
|
248
212
|
const fetchUserInfo = async (accessToken) => {
|
|
@@ -264,32 +228,11 @@ const userInfoAsync = async (oidc) => {
|
|
|
264
228
|
return userInfo;
|
|
265
229
|
}
|
|
266
230
|
|
|
267
|
-
const setTokensAsync = async (serviceWorker, tokens) =>{
|
|
268
|
-
let accessTokenPayload;
|
|
269
|
-
if(tokens == null){
|
|
270
|
-
if(serviceWorker){
|
|
271
|
-
await serviceWorker.clearAsync();
|
|
272
|
-
}
|
|
273
|
-
return null;
|
|
274
|
-
}
|
|
275
|
-
if(serviceWorker){
|
|
276
|
-
accessTokenPayload = await serviceWorker.getAccessTokenPayloadAsync();
|
|
277
|
-
}
|
|
278
|
-
else {
|
|
279
|
-
accessTokenPayload = extractAccessTokenPayload(tokens);
|
|
280
|
-
}
|
|
281
|
-
const _idTokenPayload = idTokenPayload(tokens.idToken);
|
|
282
|
-
|
|
283
|
-
const idTokenExipreAt =(_idTokenPayload && _idTokenPayload.exp) ? _idTokenPayload.exp: Number.MAX_VALUE;
|
|
284
|
-
const accessTokenExpiresAt = (accessTokenPayload && accessTokenPayload.exp)? accessTokenPayload.exp : tokens.issuedAt + tokens.expiresIn;
|
|
285
|
-
const expiresAt = idTokenExipreAt < accessTokenExpiresAt ? idTokenExipreAt : accessTokenExpiresAt;
|
|
286
|
-
return {...tokens, idTokenPayload: _idTokenPayload, accessTokenPayload, expiresAt};
|
|
287
|
-
}
|
|
288
|
-
|
|
289
231
|
const eventNames = {
|
|
290
232
|
service_worker_not_supported_by_browser: "service_worker_not_supported_by_browser",
|
|
291
233
|
token_aquired: "token_aquired",
|
|
292
234
|
logout_from_another_tab: "logout_from_another_tab",
|
|
235
|
+
logout_from_same_tab: "logout_from_same_tab",
|
|
293
236
|
token_renewed: "token_renewed",
|
|
294
237
|
token_timer: "token_timer",
|
|
295
238
|
loginAsync_begin:"loginAsync_begin",
|
|
@@ -382,7 +325,12 @@ export class Oidc {
|
|
|
382
325
|
silent_login_uri = `${configuration.silent_redirect_uri.replace("-callback", "").replace("callback", "")}-login`;
|
|
383
326
|
}
|
|
384
327
|
|
|
385
|
-
this.configuration = {...configuration,
|
|
328
|
+
this.configuration = {...configuration,
|
|
329
|
+
silent_login_uri,
|
|
330
|
+
monitor_session: configuration.monitor_session ?? true,
|
|
331
|
+
refresh_time_before_tokens_expiration_in_second : configuration.refresh_time_before_tokens_expiration_in_second ?? 60,
|
|
332
|
+
silent_login_timeout: configuration.silent_login_timeout ?? 12000,
|
|
333
|
+
};
|
|
386
334
|
this.configurationName= configurationName;
|
|
387
335
|
this.tokens = null
|
|
388
336
|
this.userInfo = null;
|
|
@@ -390,7 +338,7 @@ export class Oidc {
|
|
|
390
338
|
this.timeoutId = null;
|
|
391
339
|
this.serviceWorker = null;
|
|
392
340
|
this.session = null;
|
|
393
|
-
this.
|
|
341
|
+
this.synchroniseTokensAsync.bind(this);
|
|
394
342
|
this.loginCallbackWithAutoTokensRenewAsync.bind(this);
|
|
395
343
|
this.initAsync.bind(this);
|
|
396
344
|
this.loginCallbackAsync.bind(this);
|
|
@@ -460,10 +408,6 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
460
408
|
if (!this.configuration.silent_redirect_uri || !this.configuration.silent_login_uri) {
|
|
461
409
|
return Promise.resolve(null);
|
|
462
410
|
}
|
|
463
|
-
while (document.hidden) {
|
|
464
|
-
await sleepAsync(1000);
|
|
465
|
-
this.publishEvent(eventNames.silentLoginAsync, {message:"wait because document is hidden"});
|
|
466
|
-
}
|
|
467
411
|
|
|
468
412
|
try {
|
|
469
413
|
this.publishEvent(eventNames.silentLoginAsync_begin, {});
|
|
@@ -528,13 +472,13 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
528
472
|
self.publishEvent(eventNames.silentLoginAsync_error, result);
|
|
529
473
|
iframe.remove();
|
|
530
474
|
isResolved = true;
|
|
531
|
-
reject(new Error("
|
|
475
|
+
reject(new Error("oidc_"+result.error));
|
|
532
476
|
}
|
|
533
477
|
}
|
|
534
478
|
}
|
|
535
479
|
}
|
|
536
480
|
};
|
|
537
|
-
const silentSigninTimeout = configuration.silent_login_timeout
|
|
481
|
+
const silentSigninTimeout = configuration.silent_login_timeout;
|
|
538
482
|
setTimeout(() => {
|
|
539
483
|
if (!isResolved) {
|
|
540
484
|
self.publishEvent(eventNames.silentLoginAsync_error, {reason: "timeout"});
|
|
@@ -568,8 +512,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
568
512
|
|
|
569
513
|
const serviceWorker = await initWorkerAsync(this.configuration.service_worker_relative_url, this.configurationName);
|
|
570
514
|
const storage = serviceWorker ? window.localStorage : null;
|
|
571
|
-
|
|
572
|
-
return initAsyncPromise;
|
|
515
|
+
return await fetchFromIssuer(authority, this.configuration.authority_time_cache_wellknowurl_in_second ?? 60 * 60, storage);
|
|
573
516
|
}
|
|
574
517
|
|
|
575
518
|
tryKeepExistingSessionPromise = null;
|
|
@@ -593,16 +536,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
593
536
|
if (tokens) {
|
|
594
537
|
serviceWorker.startKeepAliveServiceWorker();
|
|
595
538
|
// @ts-ignore
|
|
596
|
-
|
|
597
|
-
accessToken : tokens.access_token,
|
|
598
|
-
refreshToken : tokens.refresh_token,
|
|
599
|
-
expiresIn: tokens.expires_in,
|
|
600
|
-
idToken: tokens.id_token,
|
|
601
|
-
scope: tokens.scope,
|
|
602
|
-
tokenType: tokens.token_type,
|
|
603
|
-
issuedAt: tokens.issued_at
|
|
604
|
-
}
|
|
605
|
-
this.tokens = await setTokensAsync(serviceWorker, reformattedToken);
|
|
539
|
+
this.tokens = tokens;
|
|
606
540
|
this.serviceWorker = serviceWorker;
|
|
607
541
|
// @ts-ignore
|
|
608
542
|
this.timeoutId = autoRenewTokens(this, this.tokens.refreshToken, this.tokens.expiresAt);
|
|
@@ -629,7 +563,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
629
563
|
const {tokens} = await session.initAsync();
|
|
630
564
|
if (tokens) {
|
|
631
565
|
// @ts-ignore
|
|
632
|
-
this.tokens =
|
|
566
|
+
this.tokens = setTokens(tokens);
|
|
633
567
|
//session.setTokens(this.tokens);
|
|
634
568
|
this.session = session;
|
|
635
569
|
// @ts-ignore
|
|
@@ -667,7 +601,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
667
601
|
}
|
|
668
602
|
|
|
669
603
|
loginPromise: Promise<any>=null;
|
|
670
|
-
async loginAsync(callbackPath:string=undefined, extras:StringMap=null,
|
|
604
|
+
async loginAsync(callbackPath:string=undefined, extras:StringMap=null, state:string=undefined, isSilentSignin:boolean=false, scope:string=undefined) {
|
|
671
605
|
if(this.loginPromise !== null){
|
|
672
606
|
return this.loginPromise;
|
|
673
607
|
}
|
|
@@ -684,28 +618,10 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
684
618
|
scope = configuration.scope;
|
|
685
619
|
}
|
|
686
620
|
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
621
|
+
setLoginParams(this.configurationName, redirectUri, {callbackPath: url, extras, state});
|
|
622
|
+
|
|
690
623
|
let serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, this.configurationName);
|
|
691
624
|
const oidcServerConfiguration = await this.initAsync(configuration.authority, configuration.authority_configuration);
|
|
692
|
-
/*if (serviceWorker && installServiceWorker) {
|
|
693
|
-
const isServiceWorkerProxyActive = await serviceWorker.isServiceWorkerProxyActiveAsync();
|
|
694
|
-
if (!isServiceWorkerProxyActive) {
|
|
695
|
-
const isUnregistered = await serviceWorker.unregisterAsync();
|
|
696
|
-
console.log("isUnregistered")
|
|
697
|
-
console.log(isUnregistered)
|
|
698
|
-
if(isUnregistered){
|
|
699
|
-
serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, this.configurationName);
|
|
700
|
-
}
|
|
701
|
-
const extrasQueries = extras != null ? {...extras}: {};
|
|
702
|
-
extrasQueries.callbackPath = url;
|
|
703
|
-
extrasQueries.state = state;
|
|
704
|
-
const queryString = buildQueries(extrasQueries);
|
|
705
|
-
window.location.href = `${redirectUri}/service-worker-install${queryString}`;
|
|
706
|
-
//return;
|
|
707
|
-
}
|
|
708
|
-
}*/
|
|
709
625
|
let storage;
|
|
710
626
|
if (serviceWorker) {
|
|
711
627
|
serviceWorker.startKeepAliveServiceWorker();
|
|
@@ -774,9 +690,16 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
774
690
|
else {
|
|
775
691
|
console.debug("SessionMonitor._callback: Different subject signed into OP:", iFrameIdTokenPayload.sub);
|
|
776
692
|
}
|
|
777
|
-
}).catch((e) => {
|
|
778
|
-
|
|
779
|
-
|
|
693
|
+
}).catch(async (e) => {
|
|
694
|
+
for (const [key, oidc] of Object.entries(oidcDatabase)) {
|
|
695
|
+
//if(oidc !== this) {
|
|
696
|
+
// @ts-ignore
|
|
697
|
+
await oidc.logoutOtherTabAsync(this.configuration.client_id, idTokenPayload.sub);
|
|
698
|
+
//}
|
|
699
|
+
}
|
|
700
|
+
//await this.destroyAsync();
|
|
701
|
+
//this.publishEvent(eventNames.logout_from_another_tab, {message : "SessionMonitor"});
|
|
702
|
+
|
|
780
703
|
});
|
|
781
704
|
};
|
|
782
705
|
|
|
@@ -803,7 +726,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
803
726
|
const response = await this._loginCallbackAsync(isSilenSignin);
|
|
804
727
|
// @ts-ignore
|
|
805
728
|
const tokens = response.tokens;
|
|
806
|
-
const parsedTokens =
|
|
729
|
+
const parsedTokens = setTokens(tokens);
|
|
807
730
|
this.tokens = parsedTokens;
|
|
808
731
|
if(!this.serviceWorker){
|
|
809
732
|
await this.session.setTokens(parsedTokens);
|
|
@@ -903,13 +826,19 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
903
826
|
}, tokenRequestTimeout ?? 12000);
|
|
904
827
|
try {
|
|
905
828
|
const tokenHandler = new BaseTokenRequestHandler(new FetchRequestor());
|
|
906
|
-
tokenHandler.performTokenRequest(oidcServerConfiguration, tokenRequest).then((tokenResponse)=>{
|
|
907
|
-
if(timeoutId) {
|
|
829
|
+
tokenHandler.performTokenRequest(oidcServerConfiguration, tokenRequest).then(async (tokenResponse) => {
|
|
830
|
+
if (timeoutId) {
|
|
908
831
|
clearTimeout(timeoutId);
|
|
909
|
-
this.timeoutId=null;
|
|
832
|
+
this.timeoutId = null;
|
|
910
833
|
const loginParams = getLoginParams(this.configurationName, redirectUri);
|
|
834
|
+
|
|
835
|
+
if (serviceWorker) {
|
|
836
|
+
const {tokens} = await serviceWorker.initAsync(oidcServerConfiguration, "syncTokensAsync");
|
|
837
|
+
tokenResponse = tokens;
|
|
838
|
+
}
|
|
839
|
+
|
|
911
840
|
// @ts-ignore
|
|
912
|
-
this.startCheckSessionAsync(oidcServerConfiguration.check_session_iframe, clientId, sessionState, isSilentSignin).then(() =>{
|
|
841
|
+
this.startCheckSessionAsync(oidcServerConfiguration.check_session_iframe, clientId, sessionState, isSilentSignin).then(() => {
|
|
913
842
|
this.publishEvent(eventNames.loginCallbackAsync_end, {});
|
|
914
843
|
resolve({
|
|
915
844
|
tokens: tokenResponse,
|
|
@@ -938,151 +867,154 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
938
867
|
}
|
|
939
868
|
}
|
|
940
869
|
|
|
941
|
-
async
|
|
870
|
+
async synchroniseTokensAsync(refreshToken, index=0) {
|
|
942
871
|
|
|
872
|
+
if (document.hidden) {
|
|
873
|
+
await sleepAsync(1000);
|
|
874
|
+
this.publishEvent(eventNames.refreshTokensAsync, {message: "wait because document is hidden"});
|
|
875
|
+
return await this.synchroniseTokensAsync(refreshToken, index);
|
|
876
|
+
}
|
|
877
|
+
let numberTryOnline = 6;
|
|
878
|
+
while (!navigator.onLine && numberTryOnline > 0) {
|
|
879
|
+
await sleepAsync(1000);
|
|
880
|
+
numberTryOnline--;
|
|
881
|
+
this.publishEvent(eventNames.refreshTokensAsync, {message: `wait because navigator is offline try ${numberTryOnline}` });
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
const configuration = this.configuration;
|
|
943
885
|
const localsilentLoginAsync= async () => {
|
|
944
886
|
try {
|
|
945
|
-
const
|
|
887
|
+
const loginParams = getLoginParams(this.configurationName, configuration.redirect_uri);
|
|
888
|
+
const silent_token_response = await this.silentLoginAsync({
|
|
889
|
+
...loginParams.extras,
|
|
890
|
+
prompt: "none"
|
|
891
|
+
}, loginParams.state);
|
|
946
892
|
if (silent_token_response) {
|
|
947
|
-
|
|
893
|
+
this.publishEvent(Oidc.eventNames.token_renewed, {});
|
|
894
|
+
return {tokens:silent_token_response.tokens, status:"LOGGED"};
|
|
948
895
|
}
|
|
949
896
|
} catch (exceptionSilent) {
|
|
950
897
|
console.error(exceptionSilent);
|
|
898
|
+
this.publishEvent(eventNames.refreshTokensAsync_silent_error, {message: "exceptionSilent" ,exception: exceptionSilent.message});
|
|
899
|
+
if(exceptionSilent && exceptionSilent.message && exceptionSilent.message.startsWith("oidc")){
|
|
900
|
+
this.publishEvent(eventNames.refreshTokensAsync_error, {message: `refresh token silent` });
|
|
901
|
+
return {tokens:null, status:"SESSION_LOST"};
|
|
902
|
+
}
|
|
903
|
+
await sleepAsync(1000);
|
|
904
|
+
throw exceptionSilent;
|
|
951
905
|
}
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
this.timeoutId=null;
|
|
955
|
-
}
|
|
956
|
-
this.publishEvent(eventNames.refreshTokensAsync_error, {message: "refresh token and silent refresh failed"});
|
|
957
|
-
return null;
|
|
906
|
+
this.publishEvent(eventNames.refreshTokensAsync_error, {message: `refresh token silent return` });
|
|
907
|
+
return {tokens:null, status:"SESSION_LOST"};
|
|
958
908
|
}
|
|
959
|
-
|
|
960
|
-
const configuration = this.configuration;
|
|
961
|
-
const clientId = configuration.client_id;
|
|
962
|
-
const redirectUri = configuration.redirect_uri;
|
|
963
|
-
const authority = configuration.authority;
|
|
964
|
-
|
|
965
|
-
if(!refreshToken)
|
|
966
|
-
{
|
|
967
|
-
return await localsilentLoginAsync();
|
|
968
|
-
}
|
|
969
909
|
|
|
970
|
-
|
|
971
|
-
if(configuration.token_request_extras) {
|
|
972
|
-
for (let [key, value] of Object.entries(configuration.token_request_extras)) {
|
|
973
|
-
extras[key] = value;
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
|
-
const oidcServerConfiguration = await this.initAsync(authority, configuration.authority_configuration);
|
|
977
|
-
|
|
978
|
-
const details = {
|
|
979
|
-
client_id: clientId,
|
|
980
|
-
redirect_uri: redirectUri,
|
|
981
|
-
grant_type: GRANT_TYPE_REFRESH_TOKEN,
|
|
982
|
-
refresh_token: refreshToken,
|
|
983
|
-
};
|
|
984
|
-
|
|
985
|
-
let index = 0;
|
|
986
|
-
while (index <=4) {
|
|
910
|
+
if (index <=4) {
|
|
987
911
|
try {
|
|
988
|
-
|
|
989
|
-
if(
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
this.publishEvent(eventNames.refreshTokensAsync, {message: "wait because document is hidden"});
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
const tokenResponse = await performTokenRequestAsync(oidcServerConfiguration.tokenEndpoint, details, extras)
|
|
996
|
-
if (tokenResponse.success) {
|
|
997
|
-
this.publishEvent(eventNames.refreshTokensAsync_end, {success: tokenResponse.success});
|
|
998
|
-
return tokenResponse.data;
|
|
999
|
-
} else {
|
|
1000
|
-
this.publishEvent(eventNames.refreshTokensAsync_silent_error, {message: "bad request" , tokenResponse: tokenResponse});
|
|
912
|
+
|
|
913
|
+
if(!refreshToken)
|
|
914
|
+
{
|
|
915
|
+
this.publishEvent(eventNames.refreshTokensAsync_begin, {refreshToken:refreshToken, tryNumber: index});
|
|
1001
916
|
return await localsilentLoginAsync();
|
|
1002
917
|
}
|
|
918
|
+
const { status, tokens } = await this.syncTokensInfoAsync(configuration, this.configurationName, this.tokens);
|
|
919
|
+
switch (status) {
|
|
920
|
+
case "SESSION_LOST":
|
|
921
|
+
this.publishEvent(eventNames.refreshTokensAsync_error, {message: `refresh token session lost` });
|
|
922
|
+
return {tokens:null, status:"SESSION_LOST"};
|
|
923
|
+
case "NOT_CONNECTED":
|
|
924
|
+
return {tokens:null, status:null};
|
|
925
|
+
case "TOKENS_VALID":
|
|
926
|
+
case "TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_VALID":
|
|
927
|
+
return {tokens, status:"LOGGED_IN"};
|
|
928
|
+
case "LOGOUT_FROM_ANOTHER_TAB":
|
|
929
|
+
this.publishEvent(eventNames.logout_from_another_tab, {"status": "session syncTokensAsync"});
|
|
930
|
+
return {tokens:null, status:"LOGGED_OUT"};
|
|
931
|
+
case "REQUIRE_SYNC_TOKENS":
|
|
932
|
+
this.publishEvent(eventNames.refreshTokensAsync_begin, {refreshToken:refreshToken, status, tryNumber: index});
|
|
933
|
+
return await localsilentLoginAsync();
|
|
934
|
+
default:
|
|
935
|
+
this.publishEvent(eventNames.refreshTokensAsync_begin, {refreshToken:refreshToken, status, tryNumber: index});
|
|
936
|
+
const clientId = configuration.client_id;
|
|
937
|
+
const redirectUri = configuration.redirect_uri;
|
|
938
|
+
const authority = configuration.authority;
|
|
939
|
+
let extras = {};
|
|
940
|
+
if(configuration.token_request_extras) {
|
|
941
|
+
for (let [key, value] of Object.entries(configuration.token_request_extras)) {
|
|
942
|
+
extras[key] = value;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
const details = {
|
|
946
|
+
client_id: clientId,
|
|
947
|
+
redirect_uri: redirectUri,
|
|
948
|
+
grant_type: GRANT_TYPE_REFRESH_TOKEN,
|
|
949
|
+
refresh_token: tokens.refreshToken,
|
|
950
|
+
};
|
|
951
|
+
const oidcServerConfiguration = await this.initAsync(authority, configuration.authority_configuration);
|
|
952
|
+
const tokenResponse = await performTokenRequestAsync(oidcServerConfiguration.tokenEndpoint, details, extras)
|
|
953
|
+
if (tokenResponse.success) {
|
|
954
|
+
this.publishEvent(eventNames.refreshTokensAsync_end, {success: tokenResponse.success});
|
|
955
|
+
this.publishEvent(Oidc.eventNames.token_renewed, {});
|
|
956
|
+
return {tokens: tokenResponse.data, status:"LOGGED_IN"};
|
|
957
|
+
} else {
|
|
958
|
+
this.publishEvent(eventNames.refreshTokensAsync_silent_error, {
|
|
959
|
+
message: "bad request",
|
|
960
|
+
tokenResponse: tokenResponse
|
|
961
|
+
});
|
|
962
|
+
return await this.synchroniseTokensAsync(null, index+1);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
1003
965
|
} catch (exception) {
|
|
1004
966
|
console.error(exception);
|
|
1005
967
|
this.publishEvent(eventNames.refreshTokensAsync_silent_error, {message: "exception" ,exception: exception.message});
|
|
968
|
+
return this.synchroniseTokensAsync(refreshToken, index+1);
|
|
1006
969
|
}
|
|
1007
|
-
index++;
|
|
1008
970
|
}
|
|
1009
|
-
|
|
1010
|
-
}
|
|
1011
971
|
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
const localSyncTokensAsync = async () => {
|
|
1016
|
-
// Service Worker can be killed by the browser (when it wants,for example after 10 seconds of inactivity, so we retreieve the session if it happen)
|
|
1017
|
-
const configuration = this.configuration;
|
|
1018
|
-
if (!this.tokens) {
|
|
1019
|
-
return null;
|
|
1020
|
-
}
|
|
972
|
+
this.publishEvent(eventNames.refreshTokensAsync_error, {message: `refresh token` });
|
|
973
|
+
return {tokens:null, status:"SESSION_LOST"};
|
|
974
|
+
}
|
|
1021
975
|
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
await this.destroyAsync();
|
|
1029
|
-
return null;
|
|
1030
|
-
} else if (isLogin == null) {
|
|
1031
|
-
try {
|
|
1032
|
-
this.publishEvent(eventNames.syncTokensAsync_begin, {});
|
|
1033
|
-
const silent_token_response = await this.silentLoginAsync({prompt: "none"});
|
|
1034
|
-
if (silent_token_response && silent_token_response.tokens) {
|
|
1035
|
-
this.tokens = await setTokensAsync(serviceWorker, silent_token_response.tokens);
|
|
1036
|
-
this.publishEvent(eventNames.syncTokensAsync_end, {});
|
|
1037
|
-
return this.tokens;
|
|
1038
|
-
} else {
|
|
1039
|
-
this.publishEvent(eventNames.syncTokensAsync_error, {message: "no token found in result"});
|
|
1040
|
-
if (this.timeoutId) {
|
|
1041
|
-
timer.clearTimeout(this.timeoutId);
|
|
1042
|
-
this.timeoutId = null;
|
|
1043
|
-
}
|
|
1044
|
-
this.publishEvent(eventNames.syncTokensAsync_end, {});
|
|
1045
|
-
return null;
|
|
1046
|
-
}
|
|
1047
|
-
} catch (exceptionSilent) {
|
|
1048
|
-
console.error(exceptionSilent);
|
|
1049
|
-
this.publishEvent(eventNames.syncTokensAsync_error, exceptionSilent);
|
|
1050
|
-
if (this.timeoutId) {
|
|
1051
|
-
timer.clearTimeout(this.timeoutId);
|
|
1052
|
-
this.timeoutId = null;
|
|
1053
|
-
}
|
|
1054
|
-
this.publishEvent(eventNames.syncTokensAsync_end, {});
|
|
1055
|
-
return null;
|
|
1056
|
-
}
|
|
976
|
+
async syncTokensInfoAsync(configuration, configurationName, currentTokens) {
|
|
977
|
+
// Service Worker can be killed by the browser (when it wants,for example after 10 seconds of inactivity, so we retreieve the session if it happen)
|
|
978
|
+
//const configuration = this.configuration;
|
|
979
|
+
if (!currentTokens) {
|
|
980
|
+
return { tokens : null, status: "NOT_CONNECTED"};
|
|
981
|
+
}
|
|
1057
982
|
|
|
983
|
+
const oidcServerConfiguration = await this.initAsync(configuration.authority, configuration.authority_configuration);
|
|
984
|
+
const serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, configurationName);
|
|
985
|
+
if (serviceWorker) {
|
|
986
|
+
const {status, tokens} = await serviceWorker.initAsync(oidcServerConfiguration, "syncTokensAsync");
|
|
987
|
+
if (status == "LOGGED_OUT") {
|
|
988
|
+
return {tokens: null, status: "LOGOUT_FROM_ANOTHER_TAB"};
|
|
989
|
+
}else if (status == "SESSIONS_LOST") {
|
|
990
|
+
return { tokens : null, status: "SESSIONS_LOST"};
|
|
991
|
+
} else if (!status || !tokens) {
|
|
992
|
+
return { tokens : null, status: "REQUIRE_SYNC_TOKENS"};
|
|
993
|
+
} else if(tokens.issuedAt !== currentTokens.issuedAt) {
|
|
994
|
+
const timeLeft = computeTimeLeft(configuration.refresh_time_before_tokens_expiration_in_second, tokens.expiresAt);
|
|
995
|
+
const status = (timeLeft > 0) ? "TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_VALID" : "TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_INVALID";
|
|
996
|
+
return { tokens : tokens, status };
|
|
997
|
+
}
|
|
998
|
+
} else {
|
|
999
|
+
const session = initSession(configurationName, configuration.redirect_uri, configuration.storage ?? sessionStorage);
|
|
1000
|
+
const {tokens, status } = await session.initAsync();
|
|
1001
|
+
if (!tokens) {
|
|
1002
|
+
return {tokens: null, status: "LOGOUT_FROM_ANOTHER_TAB"};
|
|
1003
|
+
} else if (status == "SESSIONS_LOST") {
|
|
1004
|
+
return { tokens : null, status: "SESSIONS_LOST"};
|
|
1058
1005
|
}
|
|
1059
|
-
|
|
1060
|
-
const
|
|
1061
|
-
const
|
|
1062
|
-
|
|
1063
|
-
this.publishEvent(eventNames.logout_from_another_tab, {});
|
|
1064
|
-
await this.destroyAsync();
|
|
1065
|
-
return null;
|
|
1066
|
-
}
|
|
1006
|
+
else if(tokens.issuedAt !== currentTokens.issuedAt){
|
|
1007
|
+
const timeLeft = computeTimeLeft(configuration.refresh_time_before_tokens_expiration_in_second, tokens.expiresAt);
|
|
1008
|
+
const status = (timeLeft > 0) ? "TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_VALID" : "TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_INVALID";
|
|
1009
|
+
return { tokens : tokens, status };
|
|
1067
1010
|
}
|
|
1068
|
-
return this.tokens;
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
if(this.syncTokensAsyncPromise){
|
|
1072
|
-
return this.syncTokensAsyncPromise;
|
|
1073
1011
|
}
|
|
1074
1012
|
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
}
|
|
1079
|
-
return result;
|
|
1080
|
-
});
|
|
1081
|
-
|
|
1082
|
-
return this.syncTokensAsyncPromise
|
|
1013
|
+
const timeLeft = computeTimeLeft(configuration.refresh_time_before_tokens_expiration_in_second, currentTokens.expiresAt);
|
|
1014
|
+
const status = (timeLeft > 0) ? "TOKENS_VALID" : "TOKENS_INVALID";
|
|
1015
|
+
return { tokens:currentTokens, status};
|
|
1083
1016
|
}
|
|
1084
1017
|
|
|
1085
|
-
|
|
1086
1018
|
loginCallbackWithAutoTokensRenewPromise:Promise<loginCallbackResult> = null;
|
|
1087
1019
|
loginCallbackWithAutoTokensRenewAsync():Promise<loginCallbackResult>{
|
|
1088
1020
|
if(this.loginCallbackWithAutoTokensRenewPromise !== null){
|
|
@@ -1099,24 +1031,39 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
1099
1031
|
return userInfoAsync(this);
|
|
1100
1032
|
}
|
|
1101
1033
|
|
|
1102
|
-
async destroyAsync() {
|
|
1034
|
+
async destroyAsync(status) {
|
|
1103
1035
|
timer.clearTimeout(this.timeoutId);
|
|
1104
1036
|
this.timeoutId=null;
|
|
1105
1037
|
if(this.checkSessionIFrame){
|
|
1106
1038
|
this.checkSessionIFrame.stop();
|
|
1107
1039
|
}
|
|
1108
1040
|
if(this.serviceWorker){
|
|
1109
|
-
await this.serviceWorker.clearAsync();
|
|
1041
|
+
await this.serviceWorker.clearAsync(status);
|
|
1110
1042
|
}
|
|
1111
1043
|
if(this.session){
|
|
1112
|
-
await this.session.clearAsync();
|
|
1044
|
+
await this.session.clearAsync(status);
|
|
1113
1045
|
}
|
|
1114
1046
|
this.tokens = null;
|
|
1115
1047
|
this.userInfo = null;
|
|
1116
|
-
|
|
1117
|
-
|
|
1048
|
+
// this.events = [];
|
|
1118
1049
|
}
|
|
1119
1050
|
|
|
1051
|
+
async logoutSameTabAsync(clientId, sub){
|
|
1052
|
+
// @ts-ignore
|
|
1053
|
+
if(this.configuration.monitor_session&& this.configuration.client_id === clientId && sub && this.tokens && this.tokens.idTokenPayload && this.tokens.idTokenPayload.sub === sub) {
|
|
1054
|
+
this.publishEvent(eventNames.logout_from_same_tab, {"message": sub});
|
|
1055
|
+
await this.destroyAsync("LOGGED_OUT");
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
async logoutOtherTabAsync(clientId, sub){
|
|
1060
|
+
// @ts-ignore
|
|
1061
|
+
if(this.configuration.monitor_session && this.configuration.client_id === clientId && sub && this.tokens && this.tokens.idTokenPayload && this.tokens.idTokenPayload.sub === sub) {
|
|
1062
|
+
await this.destroyAsync("LOGGED_OUT");
|
|
1063
|
+
this.publishEvent(eventNames.logout_from_another_tab, {message : "SessionMonitor", "sub": sub});
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1120
1067
|
async logoutAsync(callbackPathOrUrl: string | undefined = undefined, extras: StringMap = null) {
|
|
1121
1068
|
const configuration = this.configuration;
|
|
1122
1069
|
const oidcServerConfiguration = await this.initAsync(configuration.authority, configuration.authority_configuration);
|
|
@@ -1133,7 +1080,16 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
1133
1080
|
const url = isUri ? callbackPathOrUrl : window.location.origin + path;
|
|
1134
1081
|
// @ts-ignore
|
|
1135
1082
|
const idToken = this.tokens ? this.tokens.idToken : "";
|
|
1136
|
-
|
|
1083
|
+
// @ts-ignore
|
|
1084
|
+
const sub = this.tokens && this.tokens.idTokenPayload ? this.tokens.idTokenPayload.sub : null;
|
|
1085
|
+
await this.destroyAsync("LOGGED_OUT");
|
|
1086
|
+
for (const [key, oidc] of Object.entries(oidcDatabase)) {
|
|
1087
|
+
if(oidc !== this) {
|
|
1088
|
+
// @ts-ignore
|
|
1089
|
+
await oidc.logoutSameTabAsync(this.configuration.client_id, sub);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1137
1093
|
if(oidcServerConfiguration.endSessionEndpoint) {
|
|
1138
1094
|
let extraQueryString = "";
|
|
1139
1095
|
if(extras){
|