@axa-fr/react-oidc 6.0.0-beta13 → 6.0.0-beta14
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/dist/FetchToken.d.ts.map +1 -1
- package/dist/FetchToken.js +10 -6
- package/dist/FetchToken.js.map +1 -1
- package/dist/OidcSecure.js +2 -2
- package/dist/OidcSecure.js.map +1 -1
- package/dist/OidcServiceWorker.js +34 -4
- package/dist/ReactOidc.js +1 -1
- 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/vanilla/initWorker.d.ts +0 -1
- package/dist/vanilla/initWorker.d.ts.map +1 -1
- package/dist/vanilla/initWorker.js +4 -19
- package/dist/vanilla/initWorker.js.map +1 -1
- package/dist/vanilla/oidc.d.ts +6 -4
- package/dist/vanilla/oidc.d.ts.map +1 -1
- package/dist/vanilla/oidc.js +302 -442
- package/dist/vanilla/oidc.js.map +1 -1
- package/package.json +1 -1
- package/src/oidc/FetchToken.tsx +7 -4
- package/src/oidc/OidcSecure.tsx +2 -2
- package/src/oidc/ReactOidc.tsx +1 -1
- package/src/oidc/core/default-component/SilentLogin.component.tsx +1 -1
- package/src/oidc/vanilla/OidcServiceWorker.js +34 -4
- package/src/oidc/vanilla/initWorker.ts +5 -4
- package/src/oidc/vanilla/oidc.ts +150 -245
- package/src/oidc/vanilla/parseTokens.js +104 -0
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,29 +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
|
-
if(!tokens.issued_at) {
|
|
52
|
-
const currentTimeUnixSecond = new Date().getTime() /1000;
|
|
53
|
-
tokens.issued_at = currentTimeUnixSecond;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const data = {
|
|
57
|
-
accessToken: tokens.access_token,
|
|
58
|
-
expiresIn: tokens.expires_in,
|
|
59
|
-
idToken: tokens.id_token,
|
|
60
|
-
refreshToken: tokens.refresh_token,
|
|
61
|
-
scope: tokens.scope,
|
|
62
|
-
tokenType: tokens.token_type,
|
|
63
|
-
issuedAt: tokens.issued_at
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
if(tokens.accessTokenPayload !== undefined){
|
|
67
|
-
// @ts-ignore
|
|
68
|
-
data.accessTokenPayload = tokens.accessTokenPayload;
|
|
69
|
-
}
|
|
70
|
-
|
|
51
|
+
console.log(tokens);
|
|
71
52
|
return { success : true,
|
|
72
|
-
data
|
|
53
|
+
data: parseOriginalTokens(tokens)
|
|
73
54
|
};
|
|
74
55
|
}
|
|
75
56
|
|
|
@@ -115,36 +96,6 @@ export class OidcAuthorizationServiceConfiguration extends AuthorizationServiceC
|
|
|
115
96
|
|
|
116
97
|
}
|
|
117
98
|
|
|
118
|
-
const idTokenPayload = (token) => {
|
|
119
|
-
const base64Url = token.split('.')[1];
|
|
120
|
-
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
|
121
|
-
const jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
|
|
122
|
-
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
|
123
|
-
}).join(''));
|
|
124
|
-
|
|
125
|
-
return JSON.parse(jsonPayload);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const countLetter = (str, find)=> {
|
|
129
|
-
return (str.split(find)).length - 1;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const extractAccessTokenPayload = tokens => {
|
|
133
|
-
if(tokens.accessTokenPayload)
|
|
134
|
-
{
|
|
135
|
-
return tokens.accessTokenPayload;
|
|
136
|
-
}
|
|
137
|
-
const accessToken = tokens.accessToken;
|
|
138
|
-
try{
|
|
139
|
-
if (!accessToken || countLetter(accessToken,'.') != 2) {
|
|
140
|
-
return null;
|
|
141
|
-
}
|
|
142
|
-
return JSON.parse(atob(accessToken.split('.')[1]));
|
|
143
|
-
} catch (e) {
|
|
144
|
-
console.warn(e);
|
|
145
|
-
}
|
|
146
|
-
return null;
|
|
147
|
-
};
|
|
148
99
|
|
|
149
100
|
export interface StringMap {
|
|
150
101
|
[key: string]: string;
|
|
@@ -200,34 +151,41 @@ const loginCallbackWithAutoTokensRenewAsync = async (oidc) => {
|
|
|
200
151
|
}
|
|
201
152
|
|
|
202
153
|
const autoRenewTokens = (oidc, refreshToken, expiresAt) => {
|
|
203
|
-
const refreshTimeBeforeTokensExpirationInSecond = oidc.configuration.refresh_time_before_tokens_expiration_in_second
|
|
154
|
+
const refreshTimeBeforeTokensExpirationInSecond = oidc.configuration.refresh_time_before_tokens_expiration_in_second;
|
|
204
155
|
return timer.setTimeout(async () => {
|
|
205
|
-
const
|
|
206
|
-
const timeInfo = { timeLeft
|
|
156
|
+
const timeLeft = computeTimeLeft(refreshTimeBeforeTokensExpirationInSecond, expiresAt);
|
|
157
|
+
const timeInfo = { timeLeft };
|
|
207
158
|
oidc.publishEvent(Oidc.eventNames.token_timer, timeInfo);
|
|
208
|
-
|
|
209
|
-
const tokens = await oidc.
|
|
210
|
-
oidc.tokens=
|
|
159
|
+
// if(timeLeft <= 0) {
|
|
160
|
+
const tokens = await oidc.synchroniseTokensAsync(refreshToken);
|
|
161
|
+
oidc.tokens= tokens;
|
|
211
162
|
if(!oidc.serviceWorker){
|
|
212
163
|
await oidc.session.setTokens(oidc.tokens);
|
|
213
164
|
}
|
|
214
165
|
if(!oidc.tokens){
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
oidc.checkSessionIFrame = null;
|
|
218
|
-
}
|
|
166
|
+
await oidc.destroyAsync();
|
|
167
|
+
oidc.publishEvent(eventNames.refreshTokensAsync_error, {message: `refresh token` });
|
|
219
168
|
return;
|
|
220
169
|
}
|
|
221
|
-
|
|
170
|
+
|
|
222
171
|
if(oidc.timeoutId) {
|
|
223
172
|
oidc.timeoutId = autoRenewTokens(oidc, tokens.refreshToken, oidc.tokens.expiresAt);
|
|
224
173
|
}
|
|
225
|
-
} else{
|
|
174
|
+
/*} else{
|
|
226
175
|
const tokens = await oidc.syncTokensAsync();
|
|
176
|
+
oidc.tokens = tokens;
|
|
177
|
+
if(!oidc.serviceWorker){
|
|
178
|
+
await oidc.session.setTokens(oidc.tokens);
|
|
179
|
+
}
|
|
180
|
+
if(!oidc.tokens){
|
|
181
|
+
oidc.publishEvent(eventNames.refreshTokensAsync_error, {message: `sync` });
|
|
182
|
+
await oidc.destroyAsync();
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
227
185
|
if(tokens && oidc.timeoutId) {
|
|
228
186
|
oidc.timeoutId = autoRenewTokens(oidc, tokens.refreshToken, tokens.expiresAt);
|
|
229
187
|
}
|
|
230
|
-
}
|
|
188
|
+
}*/
|
|
231
189
|
}, 1000);
|
|
232
190
|
}
|
|
233
191
|
|
|
@@ -245,11 +203,15 @@ const userInfoAsync = async (oidc) => {
|
|
|
245
203
|
if(!oidc.tokens){
|
|
246
204
|
return null;
|
|
247
205
|
}
|
|
248
|
-
if(oidc.syncTokensAsyncPromise){
|
|
249
|
-
await oidc.syncTokensAsyncPromise;
|
|
250
|
-
}
|
|
251
206
|
const accessToken = oidc.tokens.accessToken;
|
|
252
|
-
|
|
207
|
+
if(!accessToken){
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
// We wait the synchronisation before making a request
|
|
211
|
+
while (oidc.tokens && !isTokensValid(oidc.tokens)){
|
|
212
|
+
await sleepAsync(200);
|
|
213
|
+
}
|
|
214
|
+
|
|
253
215
|
const oidcServerConfiguration = await oidc.initAsync(oidc.configuration.authority, oidc.configuration.authority_configuration);
|
|
254
216
|
const url = oidcServerConfiguration.userInfoEndpoint;
|
|
255
217
|
const fetchUserInfo = async (accessToken) => {
|
|
@@ -271,28 +233,6 @@ const userInfoAsync = async (oidc) => {
|
|
|
271
233
|
return userInfo;
|
|
272
234
|
}
|
|
273
235
|
|
|
274
|
-
const setTokensAsync = async (serviceWorker, tokens) =>{
|
|
275
|
-
let accessTokenPayload;
|
|
276
|
-
/*if(tokens == null){
|
|
277
|
-
if(serviceWorker){
|
|
278
|
-
await serviceWorker.clearAsync();
|
|
279
|
-
}
|
|
280
|
-
return null;
|
|
281
|
-
}*/
|
|
282
|
-
if(tokens.accessTokenPayload !== undefined) {
|
|
283
|
-
accessTokenPayload = tokens.accessTokenPayload;//await serviceWorker.getAccessTokenPayloadAsync();
|
|
284
|
-
}
|
|
285
|
-
else {
|
|
286
|
-
accessTokenPayload = extractAccessTokenPayload(tokens);
|
|
287
|
-
}
|
|
288
|
-
const _idTokenPayload = idTokenPayload(tokens.idToken);
|
|
289
|
-
|
|
290
|
-
const idTokenExipreAt =(_idTokenPayload && _idTokenPayload.exp) ? _idTokenPayload.exp: Number.MAX_VALUE;
|
|
291
|
-
const accessTokenExpiresAt = (accessTokenPayload && accessTokenPayload.exp)? accessTokenPayload.exp : tokens.issuedAt + tokens.expiresIn;
|
|
292
|
-
const expiresAt = idTokenExipreAt < accessTokenExpiresAt ? idTokenExipreAt : accessTokenExpiresAt;
|
|
293
|
-
return {...tokens, idTokenPayload: _idTokenPayload, accessTokenPayload, expiresAt};
|
|
294
|
-
}
|
|
295
|
-
|
|
296
236
|
const eventNames = {
|
|
297
237
|
service_worker_not_supported_by_browser: "service_worker_not_supported_by_browser",
|
|
298
238
|
token_aquired: "token_aquired",
|
|
@@ -390,7 +330,12 @@ export class Oidc {
|
|
|
390
330
|
silent_login_uri = `${configuration.silent_redirect_uri.replace("-callback", "").replace("callback", "")}-login`;
|
|
391
331
|
}
|
|
392
332
|
|
|
393
|
-
this.configuration = {...configuration,
|
|
333
|
+
this.configuration = {...configuration,
|
|
334
|
+
silent_login_uri,
|
|
335
|
+
monitor_session: configuration.monitor_session ?? true,
|
|
336
|
+
refresh_time_before_tokens_expiration_in_second : configuration.refresh_time_before_tokens_expiration_in_second ?? 60,
|
|
337
|
+
silent_login_timeout: configuration.silent_login_timeout ?? 12000,
|
|
338
|
+
};
|
|
394
339
|
this.configurationName= configurationName;
|
|
395
340
|
this.tokens = null
|
|
396
341
|
this.userInfo = null;
|
|
@@ -398,7 +343,7 @@ export class Oidc {
|
|
|
398
343
|
this.timeoutId = null;
|
|
399
344
|
this.serviceWorker = null;
|
|
400
345
|
this.session = null;
|
|
401
|
-
this.
|
|
346
|
+
this.synchroniseTokensAsync.bind(this);
|
|
402
347
|
this.loginCallbackWithAutoTokensRenewAsync.bind(this);
|
|
403
348
|
this.initAsync.bind(this);
|
|
404
349
|
this.loginCallbackAsync.bind(this);
|
|
@@ -468,17 +413,6 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
468
413
|
if (!this.configuration.silent_redirect_uri || !this.configuration.silent_login_uri) {
|
|
469
414
|
return Promise.resolve(null);
|
|
470
415
|
}
|
|
471
|
-
while (document.hidden) {
|
|
472
|
-
await sleepAsync(1000);
|
|
473
|
-
this.publishEvent(eventNames.silentLoginAsync, {message:"wait because document is hidden"});
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
let numberTryOnline = 6;
|
|
477
|
-
while (!navigator.onLine && numberTryOnline > 0) {
|
|
478
|
-
await sleepAsync(1000);
|
|
479
|
-
numberTryOnline--;
|
|
480
|
-
this.publishEvent(eventNames.refreshTokensAsync, {message: `wait because navigator is offline try ${numberTryOnline}` });
|
|
481
|
-
}
|
|
482
416
|
|
|
483
417
|
try {
|
|
484
418
|
this.publishEvent(eventNames.silentLoginAsync_begin, {});
|
|
@@ -549,7 +483,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
549
483
|
}
|
|
550
484
|
}
|
|
551
485
|
};
|
|
552
|
-
const silentSigninTimeout = configuration.silent_login_timeout
|
|
486
|
+
const silentSigninTimeout = configuration.silent_login_timeout;
|
|
553
487
|
setTimeout(() => {
|
|
554
488
|
if (!isResolved) {
|
|
555
489
|
self.publishEvent(eventNames.silentLoginAsync_error, {reason: "timeout"});
|
|
@@ -583,8 +517,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
583
517
|
|
|
584
518
|
const serviceWorker = await initWorkerAsync(this.configuration.service_worker_relative_url, this.configurationName);
|
|
585
519
|
const storage = serviceWorker ? window.localStorage : null;
|
|
586
|
-
|
|
587
|
-
return initAsyncPromise;
|
|
520
|
+
return await fetchFromIssuer(authority, this.configuration.authority_time_cache_wellknowurl_in_second ?? 60 * 60, storage);
|
|
588
521
|
}
|
|
589
522
|
|
|
590
523
|
tryKeepExistingSessionPromise = null;
|
|
@@ -608,16 +541,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
608
541
|
if (tokens) {
|
|
609
542
|
serviceWorker.startKeepAliveServiceWorker();
|
|
610
543
|
// @ts-ignore
|
|
611
|
-
|
|
612
|
-
accessToken : tokens.access_token,
|
|
613
|
-
refreshToken : tokens.refresh_token,
|
|
614
|
-
expiresIn: tokens.expires_in,
|
|
615
|
-
idToken: tokens.id_token,
|
|
616
|
-
scope: tokens.scope,
|
|
617
|
-
tokenType: tokens.token_type,
|
|
618
|
-
issuedAt: tokens.issued_at
|
|
619
|
-
}
|
|
620
|
-
this.tokens = await setTokensAsync(serviceWorker, reformattedToken);
|
|
544
|
+
this.tokens = tokens;
|
|
621
545
|
this.serviceWorker = serviceWorker;
|
|
622
546
|
// @ts-ignore
|
|
623
547
|
this.timeoutId = autoRenewTokens(this, this.tokens.refreshToken, this.tokens.expiresAt);
|
|
@@ -644,7 +568,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
644
568
|
const {tokens} = await session.initAsync();
|
|
645
569
|
if (tokens) {
|
|
646
570
|
// @ts-ignore
|
|
647
|
-
this.tokens =
|
|
571
|
+
this.tokens = setTokens(tokens);
|
|
648
572
|
//session.setTokens(this.tokens);
|
|
649
573
|
this.session = session;
|
|
650
574
|
// @ts-ignore
|
|
@@ -682,7 +606,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
682
606
|
}
|
|
683
607
|
|
|
684
608
|
loginPromise: Promise<any>=null;
|
|
685
|
-
async loginAsync(callbackPath:string=undefined, extras:StringMap=null,
|
|
609
|
+
async loginAsync(callbackPath:string=undefined, extras:StringMap=null, state:string=undefined, isSilentSignin:boolean=false, scope:string=undefined) {
|
|
686
610
|
if(this.loginPromise !== null){
|
|
687
611
|
return this.loginPromise;
|
|
688
612
|
}
|
|
@@ -808,7 +732,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
808
732
|
const response = await this._loginCallbackAsync(isSilenSignin);
|
|
809
733
|
// @ts-ignore
|
|
810
734
|
const tokens = response.tokens;
|
|
811
|
-
const parsedTokens =
|
|
735
|
+
const parsedTokens = setTokens(tokens);
|
|
812
736
|
this.tokens = parsedTokens;
|
|
813
737
|
if(!this.serviceWorker){
|
|
814
738
|
await this.session.setTokens(parsedTokens);
|
|
@@ -943,158 +867,140 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
943
867
|
}
|
|
944
868
|
}
|
|
945
869
|
|
|
946
|
-
async
|
|
870
|
+
async synchroniseTokensAsync(refreshToken, index=0) {
|
|
947
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;
|
|
948
885
|
const localsilentLoginAsync= async () => {
|
|
949
886
|
try {
|
|
950
887
|
const loginParams = getLoginParams(this.configurationName, configuration.redirect_uri);
|
|
951
|
-
const silent_token_response = await this.silentLoginAsync(
|
|
888
|
+
const silent_token_response = await this.silentLoginAsync({
|
|
889
|
+
...loginParams.extras,
|
|
890
|
+
prompt: "none"
|
|
891
|
+
}, loginParams.state);
|
|
952
892
|
if (silent_token_response) {
|
|
893
|
+
this.publishEvent(Oidc.eventNames.token_renewed, {});
|
|
953
894
|
return silent_token_response.tokens;
|
|
954
895
|
}
|
|
955
896
|
} catch (exceptionSilent) {
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
this.timeoutId=null;
|
|
897
|
+
if(exceptionSilent && exceptionSilent.message && exceptionSilent.message.startsWith("oidc")){
|
|
898
|
+
return null;
|
|
899
|
+
}
|
|
900
|
+
throw exceptionSilent;
|
|
961
901
|
}
|
|
962
|
-
this.publishEvent(eventNames.refreshTokensAsync_error, {message: "refresh token and silent refresh failed"});
|
|
963
902
|
return null;
|
|
964
903
|
}
|
|
965
|
-
|
|
966
|
-
const configuration = this.configuration;
|
|
967
|
-
const clientId = configuration.client_id;
|
|
968
|
-
const redirectUri = configuration.redirect_uri;
|
|
969
|
-
const authority = configuration.authority;
|
|
970
|
-
|
|
971
|
-
if(!refreshToken)
|
|
972
|
-
{
|
|
973
|
-
return await localsilentLoginAsync();
|
|
974
|
-
}
|
|
975
904
|
|
|
976
|
-
|
|
977
|
-
if(configuration.token_request_extras) {
|
|
978
|
-
for (let [key, value] of Object.entries(configuration.token_request_extras)) {
|
|
979
|
-
extras[key] = value;
|
|
980
|
-
}
|
|
981
|
-
}
|
|
982
|
-
const oidcServerConfiguration = await this.initAsync(authority, configuration.authority_configuration);
|
|
983
|
-
|
|
984
|
-
const details = {
|
|
985
|
-
client_id: clientId,
|
|
986
|
-
redirect_uri: redirectUri,
|
|
987
|
-
grant_type: GRANT_TYPE_REFRESH_TOKEN,
|
|
988
|
-
refresh_token: refreshToken,
|
|
989
|
-
};
|
|
990
|
-
|
|
991
|
-
let index = 0;
|
|
992
|
-
while (index <=4) {
|
|
905
|
+
if (index <=4) {
|
|
993
906
|
try {
|
|
994
|
-
|
|
995
|
-
if(
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
this.publishEvent(eventNames.refreshTokensAsync, {message: "wait because document is hidden"});
|
|
999
|
-
}
|
|
1000
|
-
let numberTryOnline = 6;
|
|
1001
|
-
while (!navigator.onLine && numberTryOnline > 0) {
|
|
1002
|
-
await sleepAsync(1000);
|
|
1003
|
-
numberTryOnline--;
|
|
1004
|
-
this.publishEvent(eventNames.refreshTokensAsync, {message: `wait because navigator is offline try ${numberTryOnline}` });
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
const tokenResponse = await performTokenRequestAsync(oidcServerConfiguration.tokenEndpoint, details, extras)
|
|
1008
|
-
if (tokenResponse.success) {
|
|
1009
|
-
this.publishEvent(eventNames.refreshTokensAsync_end, {success: tokenResponse.success});
|
|
1010
|
-
return tokenResponse.data;
|
|
1011
|
-
} else {
|
|
1012
|
-
this.publishEvent(eventNames.refreshTokensAsync_silent_error, {message: "bad request" , tokenResponse: tokenResponse});
|
|
907
|
+
|
|
908
|
+
if(!refreshToken)
|
|
909
|
+
{
|
|
910
|
+
this.publishEvent(eventNames.refreshTokensAsync_begin, {refreshToken:refreshToken, tryNumber: index});
|
|
1013
911
|
return await localsilentLoginAsync();
|
|
1014
912
|
}
|
|
913
|
+
const { status, tokens } = await this.syncTokensInfoAsync(configuration, this.configurationName, this.tokens);
|
|
914
|
+
// this.publishEvent(eventNames.refreshTokensAsync, {message: `status ${status}` });
|
|
915
|
+
switch (status) {
|
|
916
|
+
case "NOT_CONNECTED":
|
|
917
|
+
return null;
|
|
918
|
+
case "TOKENS_VALID":
|
|
919
|
+
case "TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_VALID":
|
|
920
|
+
return tokens;
|
|
921
|
+
case "LOGOUT_FROM_ANOTHER_TAB":
|
|
922
|
+
this.publishEvent(eventNames.logout_from_another_tab, {"status": "session syncTokensAsync"});
|
|
923
|
+
return null;
|
|
924
|
+
case "REQUIRE_SYNC_TOKENS":
|
|
925
|
+
this.publishEvent(eventNames.refreshTokensAsync_begin, {refreshToken:refreshToken, status, tryNumber: index});
|
|
926
|
+
return await localsilentLoginAsync();
|
|
927
|
+
default:
|
|
928
|
+
this.publishEvent(eventNames.refreshTokensAsync_begin, {refreshToken:refreshToken, status, tryNumber: index});
|
|
929
|
+
const clientId = configuration.client_id;
|
|
930
|
+
const redirectUri = configuration.redirect_uri;
|
|
931
|
+
const authority = configuration.authority;
|
|
932
|
+
let extras = {};
|
|
933
|
+
if(configuration.token_request_extras) {
|
|
934
|
+
for (let [key, value] of Object.entries(configuration.token_request_extras)) {
|
|
935
|
+
extras[key] = value;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
const details = {
|
|
939
|
+
client_id: clientId,
|
|
940
|
+
redirect_uri: redirectUri,
|
|
941
|
+
grant_type: GRANT_TYPE_REFRESH_TOKEN,
|
|
942
|
+
refresh_token: tokens.refreshToken,
|
|
943
|
+
};
|
|
944
|
+
const oidcServerConfiguration = await this.initAsync(authority, configuration.authority_configuration);
|
|
945
|
+
const tokenResponse = await performTokenRequestAsync(oidcServerConfiguration.tokenEndpoint, details, extras)
|
|
946
|
+
if (tokenResponse.success) {
|
|
947
|
+
this.publishEvent(eventNames.refreshTokensAsync_end, {success: tokenResponse.success});
|
|
948
|
+
this.publishEvent(Oidc.eventNames.token_renewed, {});
|
|
949
|
+
return tokenResponse.data;
|
|
950
|
+
} else {
|
|
951
|
+
this.publishEvent(eventNames.refreshTokensAsync_silent_error, {
|
|
952
|
+
message: "bad request",
|
|
953
|
+
tokenResponse: tokenResponse
|
|
954
|
+
});
|
|
955
|
+
return await this.synchroniseTokensAsync(null, index+1);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
1015
958
|
} catch (exception) {
|
|
1016
959
|
console.error(exception);
|
|
1017
960
|
this.publishEvent(eventNames.refreshTokensAsync_silent_error, {message: "exception" ,exception: exception.message});
|
|
961
|
+
return this.synchroniseTokensAsync(refreshToken, index+1);
|
|
1018
962
|
}
|
|
1019
|
-
index++;
|
|
1020
963
|
}
|
|
1021
|
-
|
|
964
|
+
return null;
|
|
1022
965
|
}
|
|
1023
966
|
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
if (!this.tokens) {
|
|
1031
|
-
return null;
|
|
1032
|
-
}
|
|
967
|
+
async syncTokensInfoAsync(configuration, configurationName, currentTokens) {
|
|
968
|
+
// 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)
|
|
969
|
+
//const configuration = this.configuration;
|
|
970
|
+
if (!currentTokens) {
|
|
971
|
+
return { tokens : null, status: "NOT_CONNECTED"};
|
|
972
|
+
}
|
|
1033
973
|
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
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
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
} else {
|
|
1072
|
-
const session = initSession(this.configurationName, configuration.redirect_uri, configuration.storage ?? sessionStorage);
|
|
1073
|
-
const {tokens} = await session.initAsync();
|
|
1074
|
-
if (!tokens) {
|
|
1075
|
-
this.publishEvent(eventNames.logout_from_another_tab, {"message": "session syncTokensAsync"});
|
|
1076
|
-
await this.destroyAsync();
|
|
1077
|
-
return null;
|
|
1078
|
-
}
|
|
974
|
+
const oidcServerConfiguration = await this.initAsync(configuration.authority, configuration.authority_configuration);
|
|
975
|
+
const serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, configurationName);
|
|
976
|
+
if (serviceWorker) {
|
|
977
|
+
const {isLogin, tokens} = await serviceWorker.initAsync(oidcServerConfiguration, "syncTokensAsync");
|
|
978
|
+
if (isLogin == false) {
|
|
979
|
+
return { tokens : null, status: "LOGOUT_FROM_ANOTHER_TAB"};
|
|
980
|
+
} else if (isLogin == null) {
|
|
981
|
+
return { tokens : null, status: "REQUIRE_SYNC_TOKENS"};
|
|
982
|
+
} else if(tokens.issuedAt !== currentTokens.issuedAt) {
|
|
983
|
+
const timeLeft = computeTimeLeft(configuration.refresh_time_before_tokens_expiration_in_second, tokens.expiresAt);
|
|
984
|
+
const status = (timeLeft > 0) ? "TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_VALID" : "TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_INVALID";
|
|
985
|
+
return { tokens : tokens, status };
|
|
986
|
+
}
|
|
987
|
+
} else {
|
|
988
|
+
const session = initSession(configurationName, configuration.redirect_uri, configuration.storage ?? sessionStorage);
|
|
989
|
+
const {tokens} = await session.initAsync();
|
|
990
|
+
if (!tokens) {
|
|
991
|
+
return { tokens : null, status: "LOGOUT_FROM_ANOTHER_TAB"};
|
|
992
|
+
} else if(tokens.issuedAt !== currentTokens.issuedAt){
|
|
993
|
+
const timeLeft = computeTimeLeft(configuration.refresh_time_before_tokens_expiration_in_second, tokens.expiresAt);
|
|
994
|
+
const status = (timeLeft > 0) ? "TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_VALID" : "TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_INVALID";
|
|
995
|
+
return { tokens : tokens, status };
|
|
1079
996
|
}
|
|
1080
|
-
return this.tokens;
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
|
-
if(this.syncTokensAsyncPromise){
|
|
1084
|
-
return this.syncTokensAsyncPromise;
|
|
1085
997
|
}
|
|
1086
998
|
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
}
|
|
1091
|
-
return result;
|
|
1092
|
-
});
|
|
1093
|
-
|
|
1094
|
-
return this.syncTokensAsyncPromise
|
|
999
|
+
const timeLeft = computeTimeLeft(configuration.refresh_time_before_tokens_expiration_in_second, currentTokens.expiresAt);
|
|
1000
|
+
const status = (timeLeft > 0) ? "TOKENS_VALID" : "TOKENS_INVALID";
|
|
1001
|
+
return { tokens:currentTokens, status};
|
|
1095
1002
|
}
|
|
1096
1003
|
|
|
1097
|
-
|
|
1098
1004
|
loginCallbackWithAutoTokensRenewPromise:Promise<loginCallbackResult> = null;
|
|
1099
1005
|
loginCallbackWithAutoTokensRenewAsync():Promise<loginCallbackResult>{
|
|
1100
1006
|
if(this.loginCallbackWithAutoTokensRenewPromise !== null){
|
|
@@ -1138,7 +1044,6 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
1138
1044
|
|
|
1139
1045
|
async logoutOtherTabAsync(sub){
|
|
1140
1046
|
// @ts-ignore
|
|
1141
|
-
|
|
1142
1047
|
if(this.configuration.monitor_session && sub && this.tokens && this.tokens.idTokenPayload && this.tokens.idTokenPayload.sub === sub) {
|
|
1143
1048
|
await this.destroyAsync();
|
|
1144
1049
|
console.log("logoutOtherTabAsync(sub)" +this.configurationName);
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const idTokenPayload = (token) => {
|
|
2
|
+
const base64Url = token.split('.')[1];
|
|
3
|
+
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
|
4
|
+
const jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
|
|
5
|
+
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
|
6
|
+
}).join(''));
|
|
7
|
+
|
|
8
|
+
return JSON.parse(jsonPayload);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const countLetter = (str, find)=> {
|
|
12
|
+
return (str.split(find)).length - 1;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const extractAccessTokenPayload = tokens => {
|
|
16
|
+
if(tokens.accessTokenPayload)
|
|
17
|
+
{
|
|
18
|
+
return tokens.accessTokenPayload;
|
|
19
|
+
}
|
|
20
|
+
const accessToken = tokens.accessToken;
|
|
21
|
+
try{
|
|
22
|
+
if (!accessToken || countLetter(accessToken,'.') !== 2) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
return JSON.parse(atob(accessToken.split('.')[1]));
|
|
26
|
+
} catch (e) {
|
|
27
|
+
console.warn(e);
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
export const setTokens = (tokens) =>{
|
|
34
|
+
|
|
35
|
+
if(!tokens){
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
let accessTokenPayload;
|
|
39
|
+
|
|
40
|
+
if(!tokens.issuedAt) {
|
|
41
|
+
const currentTimeUnixSecond = new Date().getTime() /1000;
|
|
42
|
+
tokens.issuedAt = currentTimeUnixSecond;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if(tokens.accessTokenPayload !== undefined) {
|
|
46
|
+
accessTokenPayload = tokens.accessTokenPayload;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
accessTokenPayload = extractAccessTokenPayload(tokens);
|
|
50
|
+
}
|
|
51
|
+
const _idTokenPayload = idTokenPayload(tokens.idToken);
|
|
52
|
+
|
|
53
|
+
const idTokenExipreAt =(_idTokenPayload && _idTokenPayload.exp) ? _idTokenPayload.exp: Number.MAX_VALUE;
|
|
54
|
+
const accessTokenExpiresAt = (accessTokenPayload && accessTokenPayload.exp)? accessTokenPayload.exp : tokens.issuedAt + tokens.expiresIn;
|
|
55
|
+
const expiresAt = idTokenExipreAt < accessTokenExpiresAt ? idTokenExipreAt : accessTokenExpiresAt;
|
|
56
|
+
|
|
57
|
+
return {...tokens, idTokenPayload: _idTokenPayload, accessTokenPayload, expiresAt};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
export const parseOriginalTokens= (tokens) =>{
|
|
62
|
+
if(!tokens){
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
if(!tokens.issued_at) {
|
|
66
|
+
const currentTimeUnixSecond = new Date().getTime() /1000;
|
|
67
|
+
tokens.issued_at = currentTimeUnixSecond;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const data = {
|
|
71
|
+
accessToken: tokens.access_token,
|
|
72
|
+
expiresIn: tokens.expires_in,
|
|
73
|
+
idToken: tokens.id_token,
|
|
74
|
+
refreshToken: tokens.refresh_token,
|
|
75
|
+
scope: tokens.scope,
|
|
76
|
+
tokenType: tokens.token_type,
|
|
77
|
+
issuedAt: tokens.issued_at
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
if(tokens.accessTokenPayload !== undefined){
|
|
82
|
+
// @ts-ignore
|
|
83
|
+
data.accessTokenPayload = tokens.accessTokenPayload;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if(tokens.idTokenPayload !== undefined){
|
|
87
|
+
// @ts-ignore
|
|
88
|
+
data.idTokenPayload = tokens.idTokenPayload;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return setTokens(data);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export const computeTimeLeft = (refreshTimeBeforeTokensExpirationInSecond, expiresAt)=>{
|
|
95
|
+
const currentTimeUnixSecond = new Date().getTime() /1000;
|
|
96
|
+
return Math.round(((expiresAt - refreshTimeBeforeTokensExpirationInSecond) - currentTimeUnixSecond));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export const isTokensValid= (tokens) =>{
|
|
100
|
+
if(!tokens){
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
return computeTimeLeft(0, tokens.expiresAt) > 0;
|
|
104
|
+
}
|