@axa-fr/react-oidc 6.0.0-beta9 → 6.0.2
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 -12
- 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 +463 -492
- 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 +220 -277
- 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,17 +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
|
-
|
|
468
|
-
let numberTryOnline = 6;
|
|
469
|
-
while (!navigator.onLine && numberTryOnline > 0) {
|
|
470
|
-
await sleepAsync(1000);
|
|
471
|
-
numberTryOnline--;
|
|
472
|
-
this.publishEvent(eventNames.refreshTokensAsync, {message: `wait because navigator is offline try ${numberTryOnline}` });
|
|
473
|
-
}
|
|
474
411
|
|
|
475
412
|
try {
|
|
476
413
|
this.publishEvent(eventNames.silentLoginAsync_begin, {});
|
|
@@ -541,7 +478,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
541
478
|
}
|
|
542
479
|
}
|
|
543
480
|
};
|
|
544
|
-
const silentSigninTimeout = configuration.silent_login_timeout
|
|
481
|
+
const silentSigninTimeout = configuration.silent_login_timeout;
|
|
545
482
|
setTimeout(() => {
|
|
546
483
|
if (!isResolved) {
|
|
547
484
|
self.publishEvent(eventNames.silentLoginAsync_error, {reason: "timeout"});
|
|
@@ -575,8 +512,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
575
512
|
|
|
576
513
|
const serviceWorker = await initWorkerAsync(this.configuration.service_worker_relative_url, this.configurationName);
|
|
577
514
|
const storage = serviceWorker ? window.localStorage : null;
|
|
578
|
-
|
|
579
|
-
return initAsyncPromise;
|
|
515
|
+
return await fetchFromIssuer(authority, this.configuration.authority_time_cache_wellknowurl_in_second ?? 60 * 60, storage);
|
|
580
516
|
}
|
|
581
517
|
|
|
582
518
|
tryKeepExistingSessionPromise = null;
|
|
@@ -600,16 +536,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
600
536
|
if (tokens) {
|
|
601
537
|
serviceWorker.startKeepAliveServiceWorker();
|
|
602
538
|
// @ts-ignore
|
|
603
|
-
|
|
604
|
-
accessToken : tokens.access_token,
|
|
605
|
-
refreshToken : tokens.refresh_token,
|
|
606
|
-
expiresIn: tokens.expires_in,
|
|
607
|
-
idToken: tokens.id_token,
|
|
608
|
-
scope: tokens.scope,
|
|
609
|
-
tokenType: tokens.token_type,
|
|
610
|
-
issuedAt: tokens.issued_at
|
|
611
|
-
}
|
|
612
|
-
this.tokens = await setTokensAsync(serviceWorker, reformattedToken);
|
|
539
|
+
this.tokens = tokens;
|
|
613
540
|
this.serviceWorker = serviceWorker;
|
|
614
541
|
// @ts-ignore
|
|
615
542
|
this.timeoutId = autoRenewTokens(this, this.tokens.refreshToken, this.tokens.expiresAt);
|
|
@@ -636,7 +563,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
636
563
|
const {tokens} = await session.initAsync();
|
|
637
564
|
if (tokens) {
|
|
638
565
|
// @ts-ignore
|
|
639
|
-
this.tokens =
|
|
566
|
+
this.tokens = setTokens(tokens);
|
|
640
567
|
//session.setTokens(this.tokens);
|
|
641
568
|
this.session = session;
|
|
642
569
|
// @ts-ignore
|
|
@@ -674,7 +601,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
674
601
|
}
|
|
675
602
|
|
|
676
603
|
loginPromise: Promise<any>=null;
|
|
677
|
-
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) {
|
|
678
605
|
if(this.loginPromise !== null){
|
|
679
606
|
return this.loginPromise;
|
|
680
607
|
}
|
|
@@ -691,28 +618,10 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
691
618
|
scope = configuration.scope;
|
|
692
619
|
}
|
|
693
620
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
621
|
+
setLoginParams(this.configurationName, redirectUri, {callbackPath: url, extras, state});
|
|
622
|
+
|
|
697
623
|
let serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, this.configurationName);
|
|
698
624
|
const oidcServerConfiguration = await this.initAsync(configuration.authority, configuration.authority_configuration);
|
|
699
|
-
/*if (serviceWorker && installServiceWorker) {
|
|
700
|
-
const isServiceWorkerProxyActive = await serviceWorker.isServiceWorkerProxyActiveAsync();
|
|
701
|
-
if (!isServiceWorkerProxyActive) {
|
|
702
|
-
const isUnregistered = await serviceWorker.unregisterAsync();
|
|
703
|
-
console.log("isUnregistered")
|
|
704
|
-
console.log(isUnregistered)
|
|
705
|
-
if(isUnregistered){
|
|
706
|
-
serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, this.configurationName);
|
|
707
|
-
}
|
|
708
|
-
const extrasQueries = extras != null ? {...extras}: {};
|
|
709
|
-
extrasQueries.callbackPath = url;
|
|
710
|
-
extrasQueries.state = state;
|
|
711
|
-
const queryString = buildQueries(extrasQueries);
|
|
712
|
-
window.location.href = `${redirectUri}/service-worker-install${queryString}`;
|
|
713
|
-
//return;
|
|
714
|
-
}
|
|
715
|
-
}*/
|
|
716
625
|
let storage;
|
|
717
626
|
if (serviceWorker) {
|
|
718
627
|
serviceWorker.startKeepAliveServiceWorker();
|
|
@@ -781,9 +690,16 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
781
690
|
else {
|
|
782
691
|
console.debug("SessionMonitor._callback: Different subject signed into OP:", iFrameIdTokenPayload.sub);
|
|
783
692
|
}
|
|
784
|
-
}).catch((e) => {
|
|
785
|
-
|
|
786
|
-
|
|
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
|
+
|
|
787
703
|
});
|
|
788
704
|
};
|
|
789
705
|
|
|
@@ -810,7 +726,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
810
726
|
const response = await this._loginCallbackAsync(isSilenSignin);
|
|
811
727
|
// @ts-ignore
|
|
812
728
|
const tokens = response.tokens;
|
|
813
|
-
const parsedTokens =
|
|
729
|
+
const parsedTokens = setTokens(tokens);
|
|
814
730
|
this.tokens = parsedTokens;
|
|
815
731
|
if(!this.serviceWorker){
|
|
816
732
|
await this.session.setTokens(parsedTokens);
|
|
@@ -910,13 +826,19 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
910
826
|
}, tokenRequestTimeout ?? 12000);
|
|
911
827
|
try {
|
|
912
828
|
const tokenHandler = new BaseTokenRequestHandler(new FetchRequestor());
|
|
913
|
-
tokenHandler.performTokenRequest(oidcServerConfiguration, tokenRequest).then((tokenResponse)=>{
|
|
914
|
-
if(timeoutId) {
|
|
829
|
+
tokenHandler.performTokenRequest(oidcServerConfiguration, tokenRequest).then(async (tokenResponse) => {
|
|
830
|
+
if (timeoutId) {
|
|
915
831
|
clearTimeout(timeoutId);
|
|
916
|
-
this.timeoutId=null;
|
|
832
|
+
this.timeoutId = null;
|
|
917
833
|
const loginParams = getLoginParams(this.configurationName, redirectUri);
|
|
834
|
+
|
|
835
|
+
if (serviceWorker) {
|
|
836
|
+
const {tokens} = await serviceWorker.initAsync(oidcServerConfiguration, "syncTokensAsync");
|
|
837
|
+
tokenResponse = tokens;
|
|
838
|
+
}
|
|
839
|
+
|
|
918
840
|
// @ts-ignore
|
|
919
|
-
this.startCheckSessionAsync(oidcServerConfiguration.check_session_iframe, clientId, sessionState, isSilentSignin).then(() =>{
|
|
841
|
+
this.startCheckSessionAsync(oidcServerConfiguration.check_session_iframe, clientId, sessionState, isSilentSignin).then(() => {
|
|
920
842
|
this.publishEvent(eventNames.loginCallbackAsync_end, {});
|
|
921
843
|
resolve({
|
|
922
844
|
tokens: tokenResponse,
|
|
@@ -945,157 +867,154 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
945
867
|
}
|
|
946
868
|
}
|
|
947
869
|
|
|
948
|
-
async
|
|
870
|
+
async synchroniseTokensAsync(refreshToken, index=0) {
|
|
949
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;
|
|
950
885
|
const localsilentLoginAsync= async () => {
|
|
951
886
|
try {
|
|
952
|
-
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);
|
|
953
892
|
if (silent_token_response) {
|
|
954
|
-
|
|
893
|
+
this.publishEvent(Oidc.eventNames.token_renewed, {});
|
|
894
|
+
return {tokens:silent_token_response.tokens, status:"LOGGED"};
|
|
955
895
|
}
|
|
956
896
|
} catch (exceptionSilent) {
|
|
957
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;
|
|
958
905
|
}
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
this.timeoutId=null;
|
|
962
|
-
}
|
|
963
|
-
this.publishEvent(eventNames.refreshTokensAsync_error, {message: "refresh token and silent refresh failed"});
|
|
964
|
-
return null;
|
|
906
|
+
this.publishEvent(eventNames.refreshTokensAsync_error, {message: `refresh token silent return` });
|
|
907
|
+
return {tokens:null, status:"SESSION_LOST"};
|
|
965
908
|
}
|
|
966
|
-
|
|
967
|
-
const configuration = this.configuration;
|
|
968
|
-
const clientId = configuration.client_id;
|
|
969
|
-
const redirectUri = configuration.redirect_uri;
|
|
970
|
-
const authority = configuration.authority;
|
|
971
|
-
|
|
972
|
-
if(!refreshToken)
|
|
973
|
-
{
|
|
974
|
-
return await localsilentLoginAsync();
|
|
975
|
-
}
|
|
976
909
|
|
|
977
|
-
|
|
978
|
-
if(configuration.token_request_extras) {
|
|
979
|
-
for (let [key, value] of Object.entries(configuration.token_request_extras)) {
|
|
980
|
-
extras[key] = value;
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
const oidcServerConfiguration = await this.initAsync(authority, configuration.authority_configuration);
|
|
984
|
-
|
|
985
|
-
const details = {
|
|
986
|
-
client_id: clientId,
|
|
987
|
-
redirect_uri: redirectUri,
|
|
988
|
-
grant_type: GRANT_TYPE_REFRESH_TOKEN,
|
|
989
|
-
refresh_token: refreshToken,
|
|
990
|
-
};
|
|
991
|
-
|
|
992
|
-
let index = 0;
|
|
993
|
-
while (index <=4) {
|
|
910
|
+
if (index <=4) {
|
|
994
911
|
try {
|
|
995
|
-
|
|
996
|
-
if(
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
this.publishEvent(eventNames.refreshTokensAsync, {message: "wait because document is hidden"});
|
|
1000
|
-
}
|
|
1001
|
-
let numberTryOnline = 6;
|
|
1002
|
-
while (!navigator.onLine && numberTryOnline > 0) {
|
|
1003
|
-
await sleepAsync(1000);
|
|
1004
|
-
numberTryOnline--;
|
|
1005
|
-
this.publishEvent(eventNames.refreshTokensAsync, {message: `wait because navigator is offline try ${numberTryOnline}` });
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
const tokenResponse = await performTokenRequestAsync(oidcServerConfiguration.tokenEndpoint, details, extras)
|
|
1009
|
-
if (tokenResponse.success) {
|
|
1010
|
-
this.publishEvent(eventNames.refreshTokensAsync_end, {success: tokenResponse.success});
|
|
1011
|
-
return tokenResponse.data;
|
|
1012
|
-
} else {
|
|
1013
|
-
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});
|
|
1014
916
|
return await localsilentLoginAsync();
|
|
1015
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
|
+
}
|
|
1016
965
|
} catch (exception) {
|
|
1017
966
|
console.error(exception);
|
|
1018
967
|
this.publishEvent(eventNames.refreshTokensAsync_silent_error, {message: "exception" ,exception: exception.message});
|
|
968
|
+
return this.synchroniseTokensAsync(refreshToken, index+1);
|
|
1019
969
|
}
|
|
1020
|
-
index++;
|
|
1021
970
|
}
|
|
1022
|
-
|
|
1023
|
-
}
|
|
1024
971
|
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
const localSyncTokensAsync = async () => {
|
|
1029
|
-
// 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)
|
|
1030
|
-
const configuration = this.configuration;
|
|
1031
|
-
if (!this.tokens) {
|
|
1032
|
-
return null;
|
|
1033
|
-
}
|
|
972
|
+
this.publishEvent(eventNames.refreshTokensAsync_error, {message: `refresh token` });
|
|
973
|
+
return {tokens:null, status:"SESSION_LOST"};
|
|
974
|
+
}
|
|
1034
975
|
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
await this.destroyAsync();
|
|
1042
|
-
return null;
|
|
1043
|
-
} else if (isLogin == null) {
|
|
1044
|
-
try {
|
|
1045
|
-
this.publishEvent(eventNames.syncTokensAsync_begin, {});
|
|
1046
|
-
const silent_token_response = await this.silentLoginAsync({prompt: "none"});
|
|
1047
|
-
if (silent_token_response && silent_token_response.tokens) {
|
|
1048
|
-
this.tokens = await setTokensAsync(serviceWorker, silent_token_response.tokens);
|
|
1049
|
-
this.publishEvent(eventNames.syncTokensAsync_end, {});
|
|
1050
|
-
return this.tokens;
|
|
1051
|
-
} else {
|
|
1052
|
-
this.publishEvent(eventNames.syncTokensAsync_error, {message: "no token found in result"});
|
|
1053
|
-
if (this.timeoutId) {
|
|
1054
|
-
timer.clearTimeout(this.timeoutId);
|
|
1055
|
-
this.timeoutId = null;
|
|
1056
|
-
}
|
|
1057
|
-
this.publishEvent(eventNames.syncTokensAsync_end, {});
|
|
1058
|
-
return null;
|
|
1059
|
-
}
|
|
1060
|
-
} catch (exceptionSilent) {
|
|
1061
|
-
console.error(exceptionSilent);
|
|
1062
|
-
this.publishEvent(eventNames.syncTokensAsync_error, exceptionSilent);
|
|
1063
|
-
if (this.timeoutId) {
|
|
1064
|
-
timer.clearTimeout(this.timeoutId);
|
|
1065
|
-
this.timeoutId = null;
|
|
1066
|
-
}
|
|
1067
|
-
this.publishEvent(eventNames.syncTokensAsync_end, {});
|
|
1068
|
-
return null;
|
|
1069
|
-
}
|
|
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
|
+
}
|
|
1070
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"};
|
|
1071
1005
|
}
|
|
1072
|
-
|
|
1073
|
-
const
|
|
1074
|
-
const
|
|
1075
|
-
|
|
1076
|
-
this.publishEvent(eventNames.logout_from_another_tab, {});
|
|
1077
|
-
await this.destroyAsync();
|
|
1078
|
-
return null;
|
|
1079
|
-
}
|
|
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 };
|
|
1080
1010
|
}
|
|
1081
|
-
return this.tokens;
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
|
-
if(this.syncTokensAsyncPromise){
|
|
1085
|
-
return this.syncTokensAsyncPromise;
|
|
1086
1011
|
}
|
|
1087
1012
|
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
}
|
|
1092
|
-
return result;
|
|
1093
|
-
});
|
|
1094
|
-
|
|
1095
|
-
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};
|
|
1096
1016
|
}
|
|
1097
1017
|
|
|
1098
|
-
|
|
1099
1018
|
loginCallbackWithAutoTokensRenewPromise:Promise<loginCallbackResult> = null;
|
|
1100
1019
|
loginCallbackWithAutoTokensRenewAsync():Promise<loginCallbackResult>{
|
|
1101
1020
|
if(this.loginCallbackWithAutoTokensRenewPromise !== null){
|
|
@@ -1112,24 +1031,39 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
1112
1031
|
return userInfoAsync(this);
|
|
1113
1032
|
}
|
|
1114
1033
|
|
|
1115
|
-
async destroyAsync() {
|
|
1034
|
+
async destroyAsync(status) {
|
|
1116
1035
|
timer.clearTimeout(this.timeoutId);
|
|
1117
1036
|
this.timeoutId=null;
|
|
1118
1037
|
if(this.checkSessionIFrame){
|
|
1119
1038
|
this.checkSessionIFrame.stop();
|
|
1120
1039
|
}
|
|
1121
1040
|
if(this.serviceWorker){
|
|
1122
|
-
await this.serviceWorker.clearAsync();
|
|
1041
|
+
await this.serviceWorker.clearAsync(status);
|
|
1123
1042
|
}
|
|
1124
1043
|
if(this.session){
|
|
1125
|
-
await this.session.clearAsync();
|
|
1044
|
+
await this.session.clearAsync(status);
|
|
1126
1045
|
}
|
|
1127
1046
|
this.tokens = null;
|
|
1128
1047
|
this.userInfo = null;
|
|
1129
|
-
|
|
1130
|
-
|
|
1048
|
+
// this.events = [];
|
|
1131
1049
|
}
|
|
1132
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
|
+
|
|
1133
1067
|
async logoutAsync(callbackPathOrUrl: string | undefined = undefined, extras: StringMap = null) {
|
|
1134
1068
|
const configuration = this.configuration;
|
|
1135
1069
|
const oidcServerConfiguration = await this.initAsync(configuration.authority, configuration.authority_configuration);
|
|
@@ -1146,7 +1080,16 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
1146
1080
|
const url = isUri ? callbackPathOrUrl : window.location.origin + path;
|
|
1147
1081
|
// @ts-ignore
|
|
1148
1082
|
const idToken = this.tokens ? this.tokens.idToken : "";
|
|
1149
|
-
|
|
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
|
+
|
|
1150
1093
|
if(oidcServerConfiguration.endSessionEndpoint) {
|
|
1151
1094
|
let extraQueryString = "";
|
|
1152
1095
|
if(extras){
|