@axa-fr/react-oidc 6.0.0-beta12 → 6.0.0-beta15
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 +35 -3
- 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 +301 -445
- 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 +35 -3
- package/src/oidc/vanilla/initWorker.ts +5 -4
- package/src/oidc/vanilla/oidc.ts +150 -238
- 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,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
|
-
if(!tokens.issued_at) {
|
|
52
|
-
const currentTimeUnixSecond = new Date().getTime() /1000;
|
|
53
|
-
tokens.issued_at = currentTimeUnixSecond;
|
|
54
|
-
}
|
|
55
|
-
|
|
51
|
+
console.log(tokens);
|
|
56
52
|
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
|
-
}
|
|
53
|
+
data: parseOriginalTokens(tokens)
|
|
66
54
|
};
|
|
67
55
|
}
|
|
68
56
|
|
|
@@ -108,36 +96,6 @@ export class OidcAuthorizationServiceConfiguration extends AuthorizationServiceC
|
|
|
108
96
|
|
|
109
97
|
}
|
|
110
98
|
|
|
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
99
|
|
|
142
100
|
export interface StringMap {
|
|
143
101
|
[key: string]: string;
|
|
@@ -193,34 +151,41 @@ const loginCallbackWithAutoTokensRenewAsync = async (oidc) => {
|
|
|
193
151
|
}
|
|
194
152
|
|
|
195
153
|
const autoRenewTokens = (oidc, refreshToken, expiresAt) => {
|
|
196
|
-
const refreshTimeBeforeTokensExpirationInSecond = oidc.configuration.refresh_time_before_tokens_expiration_in_second
|
|
154
|
+
const refreshTimeBeforeTokensExpirationInSecond = oidc.configuration.refresh_time_before_tokens_expiration_in_second;
|
|
197
155
|
return timer.setTimeout(async () => {
|
|
198
|
-
const
|
|
199
|
-
const timeInfo = { timeLeft
|
|
156
|
+
const timeLeft = computeTimeLeft(refreshTimeBeforeTokensExpirationInSecond, expiresAt);
|
|
157
|
+
const timeInfo = { timeLeft };
|
|
200
158
|
oidc.publishEvent(Oidc.eventNames.token_timer, timeInfo);
|
|
201
|
-
|
|
202
|
-
const tokens = await oidc.
|
|
203
|
-
oidc.tokens=
|
|
159
|
+
// if(timeLeft <= 0) {
|
|
160
|
+
const tokens = await oidc.synchroniseTokensAsync(refreshToken);
|
|
161
|
+
oidc.tokens= tokens;
|
|
204
162
|
if(!oidc.serviceWorker){
|
|
205
163
|
await oidc.session.setTokens(oidc.tokens);
|
|
206
164
|
}
|
|
207
165
|
if(!oidc.tokens){
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
oidc.checkSessionIFrame = null;
|
|
211
|
-
}
|
|
166
|
+
await oidc.destroyAsync();
|
|
167
|
+
oidc.publishEvent(eventNames.refreshTokensAsync_error, {message: `refresh token` });
|
|
212
168
|
return;
|
|
213
169
|
}
|
|
214
|
-
|
|
170
|
+
|
|
215
171
|
if(oidc.timeoutId) {
|
|
216
172
|
oidc.timeoutId = autoRenewTokens(oidc, tokens.refreshToken, oidc.tokens.expiresAt);
|
|
217
173
|
}
|
|
218
|
-
} else{
|
|
174
|
+
/*} else{
|
|
219
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
|
+
}
|
|
220
185
|
if(tokens && oidc.timeoutId) {
|
|
221
186
|
oidc.timeoutId = autoRenewTokens(oidc, tokens.refreshToken, tokens.expiresAt);
|
|
222
187
|
}
|
|
223
|
-
}
|
|
188
|
+
}*/
|
|
224
189
|
}, 1000);
|
|
225
190
|
}
|
|
226
191
|
|
|
@@ -238,11 +203,15 @@ const userInfoAsync = async (oidc) => {
|
|
|
238
203
|
if(!oidc.tokens){
|
|
239
204
|
return null;
|
|
240
205
|
}
|
|
241
|
-
if(oidc.syncTokensAsyncPromise){
|
|
242
|
-
await oidc.syncTokensAsyncPromise;
|
|
243
|
-
}
|
|
244
206
|
const accessToken = oidc.tokens.accessToken;
|
|
245
|
-
|
|
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
|
+
|
|
246
215
|
const oidcServerConfiguration = await oidc.initAsync(oidc.configuration.authority, oidc.configuration.authority_configuration);
|
|
247
216
|
const url = oidcServerConfiguration.userInfoEndpoint;
|
|
248
217
|
const fetchUserInfo = async (accessToken) => {
|
|
@@ -264,28 +233,6 @@ const userInfoAsync = async (oidc) => {
|
|
|
264
233
|
return userInfo;
|
|
265
234
|
}
|
|
266
235
|
|
|
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
236
|
const eventNames = {
|
|
290
237
|
service_worker_not_supported_by_browser: "service_worker_not_supported_by_browser",
|
|
291
238
|
token_aquired: "token_aquired",
|
|
@@ -383,7 +330,12 @@ export class Oidc {
|
|
|
383
330
|
silent_login_uri = `${configuration.silent_redirect_uri.replace("-callback", "").replace("callback", "")}-login`;
|
|
384
331
|
}
|
|
385
332
|
|
|
386
|
-
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
|
+
};
|
|
387
339
|
this.configurationName= configurationName;
|
|
388
340
|
this.tokens = null
|
|
389
341
|
this.userInfo = null;
|
|
@@ -391,7 +343,7 @@ export class Oidc {
|
|
|
391
343
|
this.timeoutId = null;
|
|
392
344
|
this.serviceWorker = null;
|
|
393
345
|
this.session = null;
|
|
394
|
-
this.
|
|
346
|
+
this.synchroniseTokensAsync.bind(this);
|
|
395
347
|
this.loginCallbackWithAutoTokensRenewAsync.bind(this);
|
|
396
348
|
this.initAsync.bind(this);
|
|
397
349
|
this.loginCallbackAsync.bind(this);
|
|
@@ -461,17 +413,6 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
461
413
|
if (!this.configuration.silent_redirect_uri || !this.configuration.silent_login_uri) {
|
|
462
414
|
return Promise.resolve(null);
|
|
463
415
|
}
|
|
464
|
-
while (document.hidden) {
|
|
465
|
-
await sleepAsync(1000);
|
|
466
|
-
this.publishEvent(eventNames.silentLoginAsync, {message:"wait because document is hidden"});
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
let numberTryOnline = 6;
|
|
470
|
-
while (!navigator.onLine && numberTryOnline > 0) {
|
|
471
|
-
await sleepAsync(1000);
|
|
472
|
-
numberTryOnline--;
|
|
473
|
-
this.publishEvent(eventNames.refreshTokensAsync, {message: `wait because navigator is offline try ${numberTryOnline}` });
|
|
474
|
-
}
|
|
475
416
|
|
|
476
417
|
try {
|
|
477
418
|
this.publishEvent(eventNames.silentLoginAsync_begin, {});
|
|
@@ -542,7 +483,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
542
483
|
}
|
|
543
484
|
}
|
|
544
485
|
};
|
|
545
|
-
const silentSigninTimeout = configuration.silent_login_timeout
|
|
486
|
+
const silentSigninTimeout = configuration.silent_login_timeout;
|
|
546
487
|
setTimeout(() => {
|
|
547
488
|
if (!isResolved) {
|
|
548
489
|
self.publishEvent(eventNames.silentLoginAsync_error, {reason: "timeout"});
|
|
@@ -576,8 +517,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
576
517
|
|
|
577
518
|
const serviceWorker = await initWorkerAsync(this.configuration.service_worker_relative_url, this.configurationName);
|
|
578
519
|
const storage = serviceWorker ? window.localStorage : null;
|
|
579
|
-
|
|
580
|
-
return initAsyncPromise;
|
|
520
|
+
return await fetchFromIssuer(authority, this.configuration.authority_time_cache_wellknowurl_in_second ?? 60 * 60, storage);
|
|
581
521
|
}
|
|
582
522
|
|
|
583
523
|
tryKeepExistingSessionPromise = null;
|
|
@@ -601,16 +541,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
601
541
|
if (tokens) {
|
|
602
542
|
serviceWorker.startKeepAliveServiceWorker();
|
|
603
543
|
// @ts-ignore
|
|
604
|
-
|
|
605
|
-
accessToken : tokens.access_token,
|
|
606
|
-
refreshToken : tokens.refresh_token,
|
|
607
|
-
expiresIn: tokens.expires_in,
|
|
608
|
-
idToken: tokens.id_token,
|
|
609
|
-
scope: tokens.scope,
|
|
610
|
-
tokenType: tokens.token_type,
|
|
611
|
-
issuedAt: tokens.issued_at
|
|
612
|
-
}
|
|
613
|
-
this.tokens = await setTokensAsync(serviceWorker, reformattedToken);
|
|
544
|
+
this.tokens = tokens;
|
|
614
545
|
this.serviceWorker = serviceWorker;
|
|
615
546
|
// @ts-ignore
|
|
616
547
|
this.timeoutId = autoRenewTokens(this, this.tokens.refreshToken, this.tokens.expiresAt);
|
|
@@ -637,7 +568,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
637
568
|
const {tokens} = await session.initAsync();
|
|
638
569
|
if (tokens) {
|
|
639
570
|
// @ts-ignore
|
|
640
|
-
this.tokens =
|
|
571
|
+
this.tokens = setTokens(tokens);
|
|
641
572
|
//session.setTokens(this.tokens);
|
|
642
573
|
this.session = session;
|
|
643
574
|
// @ts-ignore
|
|
@@ -675,7 +606,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
675
606
|
}
|
|
676
607
|
|
|
677
608
|
loginPromise: Promise<any>=null;
|
|
678
|
-
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) {
|
|
679
610
|
if(this.loginPromise !== null){
|
|
680
611
|
return this.loginPromise;
|
|
681
612
|
}
|
|
@@ -801,7 +732,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
801
732
|
const response = await this._loginCallbackAsync(isSilenSignin);
|
|
802
733
|
// @ts-ignore
|
|
803
734
|
const tokens = response.tokens;
|
|
804
|
-
const parsedTokens =
|
|
735
|
+
const parsedTokens = setTokens(tokens);
|
|
805
736
|
this.tokens = parsedTokens;
|
|
806
737
|
if(!this.serviceWorker){
|
|
807
738
|
await this.session.setTokens(parsedTokens);
|
|
@@ -936,158 +867,140 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
936
867
|
}
|
|
937
868
|
}
|
|
938
869
|
|
|
939
|
-
async
|
|
870
|
+
async synchroniseTokensAsync(refreshToken, index=0) {
|
|
940
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;
|
|
941
885
|
const localsilentLoginAsync= async () => {
|
|
942
886
|
try {
|
|
943
887
|
const loginParams = getLoginParams(this.configurationName, configuration.redirect_uri);
|
|
944
|
-
const silent_token_response = await this.silentLoginAsync(
|
|
888
|
+
const silent_token_response = await this.silentLoginAsync({
|
|
889
|
+
...loginParams.extras,
|
|
890
|
+
prompt: "none"
|
|
891
|
+
}, loginParams.state);
|
|
945
892
|
if (silent_token_response) {
|
|
893
|
+
this.publishEvent(Oidc.eventNames.token_renewed, {});
|
|
946
894
|
return silent_token_response.tokens;
|
|
947
895
|
}
|
|
948
896
|
} catch (exceptionSilent) {
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
this.timeoutId=null;
|
|
897
|
+
if(exceptionSilent && exceptionSilent.message && exceptionSilent.message.startsWith("oidc")){
|
|
898
|
+
return null;
|
|
899
|
+
}
|
|
900
|
+
throw exceptionSilent;
|
|
954
901
|
}
|
|
955
|
-
this.publishEvent(eventNames.refreshTokensAsync_error, {message: "refresh token and silent refresh failed"});
|
|
956
902
|
return null;
|
|
957
903
|
}
|
|
958
|
-
|
|
959
|
-
const configuration = this.configuration;
|
|
960
|
-
const clientId = configuration.client_id;
|
|
961
|
-
const redirectUri = configuration.redirect_uri;
|
|
962
|
-
const authority = configuration.authority;
|
|
963
|
-
|
|
964
|
-
if(!refreshToken)
|
|
965
|
-
{
|
|
966
|
-
return await localsilentLoginAsync();
|
|
967
|
-
}
|
|
968
904
|
|
|
969
|
-
|
|
970
|
-
if(configuration.token_request_extras) {
|
|
971
|
-
for (let [key, value] of Object.entries(configuration.token_request_extras)) {
|
|
972
|
-
extras[key] = value;
|
|
973
|
-
}
|
|
974
|
-
}
|
|
975
|
-
const oidcServerConfiguration = await this.initAsync(authority, configuration.authority_configuration);
|
|
976
|
-
|
|
977
|
-
const details = {
|
|
978
|
-
client_id: clientId,
|
|
979
|
-
redirect_uri: redirectUri,
|
|
980
|
-
grant_type: GRANT_TYPE_REFRESH_TOKEN,
|
|
981
|
-
refresh_token: refreshToken,
|
|
982
|
-
};
|
|
983
|
-
|
|
984
|
-
let index = 0;
|
|
985
|
-
while (index <=4) {
|
|
905
|
+
if (index <=4) {
|
|
986
906
|
try {
|
|
987
|
-
|
|
988
|
-
if(
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
this.publishEvent(eventNames.refreshTokensAsync, {message: "wait because document is hidden"});
|
|
992
|
-
}
|
|
993
|
-
let numberTryOnline = 6;
|
|
994
|
-
while (!navigator.onLine && numberTryOnline > 0) {
|
|
995
|
-
await sleepAsync(1000);
|
|
996
|
-
numberTryOnline--;
|
|
997
|
-
this.publishEvent(eventNames.refreshTokensAsync, {message: `wait because navigator is offline try ${numberTryOnline}` });
|
|
998
|
-
}
|
|
999
|
-
}
|
|
1000
|
-
const tokenResponse = await performTokenRequestAsync(oidcServerConfiguration.tokenEndpoint, details, extras)
|
|
1001
|
-
if (tokenResponse.success) {
|
|
1002
|
-
this.publishEvent(eventNames.refreshTokensAsync_end, {success: tokenResponse.success});
|
|
1003
|
-
return tokenResponse.data;
|
|
1004
|
-
} else {
|
|
1005
|
-
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});
|
|
1006
911
|
return await localsilentLoginAsync();
|
|
1007
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
|
+
}
|
|
1008
958
|
} catch (exception) {
|
|
1009
959
|
console.error(exception);
|
|
1010
960
|
this.publishEvent(eventNames.refreshTokensAsync_silent_error, {message: "exception" ,exception: exception.message});
|
|
961
|
+
return this.synchroniseTokensAsync(refreshToken, index+1);
|
|
1011
962
|
}
|
|
1012
|
-
index++;
|
|
1013
963
|
}
|
|
1014
|
-
|
|
964
|
+
return null;
|
|
1015
965
|
}
|
|
1016
966
|
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
if (!this.tokens) {
|
|
1024
|
-
return null;
|
|
1025
|
-
}
|
|
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
|
+
}
|
|
1026
973
|
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
}
|
|
1050
|
-
this.publishEvent(eventNames.syncTokensAsync_end, {});
|
|
1051
|
-
return null;
|
|
1052
|
-
}
|
|
1053
|
-
} catch (exceptionSilent) {
|
|
1054
|
-
console.error(exceptionSilent);
|
|
1055
|
-
this.publishEvent(eventNames.syncTokensAsync_error, exceptionSilent);
|
|
1056
|
-
if (this.timeoutId) {
|
|
1057
|
-
timer.clearTimeout(this.timeoutId);
|
|
1058
|
-
this.timeoutId = null;
|
|
1059
|
-
}
|
|
1060
|
-
this.publishEvent(eventNames.syncTokensAsync_end, {});
|
|
1061
|
-
return null;
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
} else {
|
|
1065
|
-
const session = initSession(this.configurationName, configuration.redirect_uri, configuration.storage ?? sessionStorage);
|
|
1066
|
-
const {tokens} = await session.initAsync();
|
|
1067
|
-
if (!tokens) {
|
|
1068
|
-
this.publishEvent(eventNames.logout_from_another_tab, {"message": "session syncTokensAsync"});
|
|
1069
|
-
await this.destroyAsync();
|
|
1070
|
-
return null;
|
|
1071
|
-
}
|
|
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 };
|
|
1072
996
|
}
|
|
1073
|
-
return this.tokens;
|
|
1074
|
-
}
|
|
1075
|
-
|
|
1076
|
-
if(this.syncTokensAsyncPromise){
|
|
1077
|
-
return this.syncTokensAsyncPromise;
|
|
1078
997
|
}
|
|
1079
998
|
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
}
|
|
1084
|
-
return result;
|
|
1085
|
-
});
|
|
1086
|
-
|
|
1087
|
-
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};
|
|
1088
1002
|
}
|
|
1089
1003
|
|
|
1090
|
-
|
|
1091
1004
|
loginCallbackWithAutoTokensRenewPromise:Promise<loginCallbackResult> = null;
|
|
1092
1005
|
loginCallbackWithAutoTokensRenewAsync():Promise<loginCallbackResult>{
|
|
1093
1006
|
if(this.loginCallbackWithAutoTokensRenewPromise !== null){
|
|
@@ -1131,7 +1044,6 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
1131
1044
|
|
|
1132
1045
|
async logoutOtherTabAsync(sub){
|
|
1133
1046
|
// @ts-ignore
|
|
1134
|
-
|
|
1135
1047
|
if(this.configuration.monitor_session && sub && this.tokens && this.tokens.idTokenPayload && this.tokens.idTokenPayload.sub === sub) {
|
|
1136
1048
|
await this.destroyAsync();
|
|
1137
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
|
+
}
|