@axa-fr/react-oidc 6.11.4-alpha2 → 6.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/OidcProvider.d.ts +1 -1
- package/dist/OidcProvider.d.ts.map +1 -1
- package/dist/OidcSecure.d.ts +1 -1
- package/dist/OidcSecure.d.ts.map +1 -1
- package/dist/OidcServiceWorker.js +16 -3
- package/dist/ReactOidc.d.ts +1 -1
- package/dist/ReactOidc.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/vanilla/initSession.d.ts +3 -3
- package/dist/vanilla/initSession.d.ts.map +1 -1
- package/dist/vanilla/initSession.js +20 -20
- package/dist/vanilla/initSession.js.map +1 -1
- package/dist/vanilla/initWorker.d.ts +4 -4
- package/dist/vanilla/initWorker.d.ts.map +1 -1
- package/dist/vanilla/initWorker.js +13 -13
- package/dist/vanilla/initWorker.js.map +1 -1
- package/dist/vanilla/oidc.d.ts +36 -7
- package/dist/vanilla/oidc.d.ts.map +1 -1
- package/dist/vanilla/oidc.js +357 -82
- package/dist/vanilla/oidc.js.map +1 -1
- package/dist/vanilla/requests.d.ts +0 -2
- package/dist/vanilla/requests.d.ts.map +1 -1
- package/dist/vanilla/requests.js +1 -20
- package/dist/vanilla/requests.js.map +1 -1
- package/dist/vanilla/route-utils.js +1 -1
- package/dist/vanilla/route-utils.js.map +1 -1
- package/dist/vanilla/vanillaOidc.d.ts +1 -2
- package/dist/vanilla/vanillaOidc.d.ts.map +1 -1
- package/dist/vanilla/vanillaOidc.js.map +1 -1
- package/package.json +1 -1
- package/src/oidc/OidcProvider.tsx +1 -1
- package/src/oidc/OidcSecure.tsx +1 -1
- package/src/oidc/ReactOidc.tsx +1 -1
- package/src/oidc/index.ts +1 -1
- package/src/oidc/vanilla/OidcServiceWorker.js +16 -3
- package/src/oidc/vanilla/index.ts +1 -1
- package/src/oidc/vanilla/initSession.ts +20 -20
- package/src/oidc/vanilla/initWorker.ts +14 -14
- package/src/oidc/vanilla/oidc.ts +380 -52
- package/src/oidc/vanilla/requests.ts +0 -24
- package/src/oidc/vanilla/route-utils.ts +1 -1
- package/src/oidc/vanilla/vanillaOidc.ts +1 -2
- package/dist/vanilla/checkSession.d.ts +0 -5
- package/dist/vanilla/checkSession.d.ts.map +0 -1
- package/dist/vanilla/checkSession.js +0 -68
- package/dist/vanilla/checkSession.js.map +0 -1
- package/dist/vanilla/events.d.ts +0 -29
- package/dist/vanilla/events.d.ts.map +0 -1
- package/dist/vanilla/events.js +0 -32
- package/dist/vanilla/events.js.map +0 -1
- package/dist/vanilla/login.d.ts +0 -4
- package/dist/vanilla/login.d.ts.map +0 -1
- package/dist/vanilla/login.js +0 -125
- package/dist/vanilla/login.js.map +0 -1
- package/dist/vanilla/silentLogin.d.ts +0 -8
- package/dist/vanilla/silentLogin.d.ts.map +0 -1
- package/dist/vanilla/silentLogin.js +0 -95
- package/dist/vanilla/silentLogin.js.map +0 -1
- package/dist/vanilla/types.d.ts +0 -33
- package/dist/vanilla/types.d.ts.map +0 -1
- package/dist/vanilla/types.js +0 -3
- package/dist/vanilla/types.js.map +0 -1
- package/dist/vanilla/user.d.ts +0 -2
- package/dist/vanilla/user.d.ts.map +0 -1
- package/dist/vanilla/user.js +0 -48
- package/dist/vanilla/user.js.map +0 -1
- package/src/oidc/vanilla/checkSession.ts +0 -55
- package/src/oidc/vanilla/events.ts +0 -29
- package/src/oidc/vanilla/login.ts +0 -118
- package/src/oidc/vanilla/silentLogin.ts +0 -102
- package/src/oidc/vanilla/types.ts +0 -35
- package/src/oidc/vanilla/user.ts +0 -39
package/src/oidc/vanilla/oidc.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AuthorizationNotifier,
|
|
3
|
+
AuthorizationRequest,
|
|
3
4
|
AuthorizationServiceConfiguration,
|
|
4
5
|
BaseTokenRequestHandler,
|
|
5
6
|
DefaultCrypto,
|
|
@@ -11,26 +12,31 @@ import {
|
|
|
11
12
|
} from '@openid/appauth';
|
|
12
13
|
import { AuthorizationServiceConfigurationJson } from '@openid/appauth/src/authorization_service_configuration';
|
|
13
14
|
|
|
14
|
-
import {
|
|
15
|
+
import { getFromCache, setCache } from './cache';
|
|
15
16
|
import { CheckSessionIFrame } from './checkSessionIFrame';
|
|
16
|
-
import { eventNames } from './events';
|
|
17
17
|
import { initSession } from './initSession';
|
|
18
18
|
import { initWorkerAsync, sleepAsync } from './initWorker';
|
|
19
|
-
import { defaultLoginAsync, defaultSilentLoginAsync2 } from './login';
|
|
20
19
|
import { MemoryStorageBackend } from './memoryStorageBackend';
|
|
21
20
|
import { HashQueryStringUtils, NoHashQueryStringUtils } from './noHashQueryStringUtils';
|
|
22
21
|
import {
|
|
23
22
|
computeTimeLeft,
|
|
24
23
|
isTokensOidcValid,
|
|
24
|
+
isTokensValid,
|
|
25
25
|
setTokens, TokenRenewMode,
|
|
26
26
|
Tokens,
|
|
27
27
|
} from './parseTokens';
|
|
28
|
-
import {
|
|
28
|
+
import { performRevocationRequestAsync, performTokenRequestAsync, TOKEN_TYPE } from './requests';
|
|
29
29
|
import { getParseQueryStringFromLocation } from './route-utils';
|
|
30
|
-
import defaultSilentLoginAsync from './silentLogin';
|
|
31
30
|
import timer from './timer';
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
|
|
32
|
+
const randomString = function(length) {
|
|
33
|
+
let text = '';
|
|
34
|
+
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
35
|
+
for (let i = 0; i < length; i++) {
|
|
36
|
+
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
|
37
|
+
}
|
|
38
|
+
return text;
|
|
39
|
+
};
|
|
34
40
|
|
|
35
41
|
export interface OidcAuthorizationServiceConfigurationJson extends AuthorizationServiceConfigurationJson{
|
|
36
42
|
check_session_iframe?: string;
|
|
@@ -52,6 +58,41 @@ export class OidcAuthorizationServiceConfiguration extends AuthorizationServiceC
|
|
|
52
58
|
}
|
|
53
59
|
}
|
|
54
60
|
|
|
61
|
+
export interface StringMap {
|
|
62
|
+
[key: string]: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface AuthorityConfiguration {
|
|
66
|
+
authorization_endpoint: string;
|
|
67
|
+
token_endpoint: string;
|
|
68
|
+
revocation_endpoint: string;
|
|
69
|
+
end_session_endpoint?: string;
|
|
70
|
+
userinfo_endpoint?: string;
|
|
71
|
+
check_session_iframe?:string;
|
|
72
|
+
issuer:string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export type OidcConfiguration = {
|
|
76
|
+
client_id: string;
|
|
77
|
+
redirect_uri: string;
|
|
78
|
+
silent_redirect_uri?:string;
|
|
79
|
+
silent_login_uri?:string;
|
|
80
|
+
silent_login_timeout?:number;
|
|
81
|
+
scope: string;
|
|
82
|
+
authority: string;
|
|
83
|
+
authority_time_cache_wellknowurl_in_second?: number;
|
|
84
|
+
authority_configuration?: AuthorityConfiguration;
|
|
85
|
+
refresh_time_before_tokens_expiration_in_second?: number;
|
|
86
|
+
token_request_timeout?: number;
|
|
87
|
+
service_worker_relative_url?:string;
|
|
88
|
+
service_worker_only?:boolean;
|
|
89
|
+
extras?:StringMap;
|
|
90
|
+
token_request_extras?:StringMap;
|
|
91
|
+
storage?: Storage;
|
|
92
|
+
monitor_session?: boolean;
|
|
93
|
+
token_renew_mode?: string;
|
|
94
|
+
};
|
|
95
|
+
|
|
55
96
|
const oidcDatabase = {};
|
|
56
97
|
const oidcFactory = (configuration: OidcConfiguration, name = 'default') => {
|
|
57
98
|
if (oidcDatabase[name]) {
|
|
@@ -79,9 +120,9 @@ async function renewTokensAndStartTimerAsync(oidc, refreshToken, forceRefresh =
|
|
|
79
120
|
const updateTokens = (tokens) => { oidc.tokens = tokens; };
|
|
80
121
|
const { tokens, status } = await oidc.synchroniseTokensAsync(refreshToken, 0, forceRefresh, extras, updateTokens);
|
|
81
122
|
|
|
82
|
-
const serviceWorker = await initWorkerAsync(oidc.configuration.service_worker_relative_url, oidc.configurationName);
|
|
123
|
+
const serviceWorker = await initWorkerAsync(oidc.configuration.service_worker_relative_url, oidc.configurationName, oidc.configuration.redirect_uri);
|
|
83
124
|
if (!serviceWorker) {
|
|
84
|
-
const session = initSession(oidc.configurationName, oidc.configuration.storage);
|
|
125
|
+
const session = initSession(oidc.configurationName, oidc.configuration.redirect_uri, oidc.configuration.storage);
|
|
85
126
|
await session.setTokens(oidc.tokens);
|
|
86
127
|
}
|
|
87
128
|
|
|
@@ -105,17 +146,105 @@ const autoRenewTokens = (oidc, refreshToken, expiresAt, extras:StringMap = null)
|
|
|
105
146
|
}, 1000);
|
|
106
147
|
};
|
|
107
148
|
|
|
149
|
+
const userInfoAsync = async (oidc) => {
|
|
150
|
+
if (oidc.userInfo != null) {
|
|
151
|
+
return oidc.userInfo;
|
|
152
|
+
}
|
|
153
|
+
if (!oidc.tokens) {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
const accessToken = oidc.tokens.accessToken;
|
|
157
|
+
if (!accessToken) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// We wait the synchronisation before making a request
|
|
162
|
+
while (oidc.tokens && !isTokensValid(oidc.tokens)) {
|
|
163
|
+
await sleepAsync(200);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const oidcServerConfiguration = await oidc.initAsync(oidc.configuration.authority, oidc.configuration.authority_configuration);
|
|
167
|
+
const url = oidcServerConfiguration.userInfoEndpoint;
|
|
168
|
+
const fetchUserInfo = async (accessToken) => {
|
|
169
|
+
const res = await fetch(url, {
|
|
170
|
+
headers: {
|
|
171
|
+
authorization: `Bearer ${accessToken}`,
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
if (res.status !== 200) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return res.json();
|
|
180
|
+
};
|
|
181
|
+
const userInfo = await fetchUserInfo(accessToken);
|
|
182
|
+
oidc.userInfo = userInfo;
|
|
183
|
+
return userInfo;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const eventNames = {
|
|
187
|
+
service_worker_not_supported_by_browser: 'service_worker_not_supported_by_browser',
|
|
188
|
+
token_aquired: 'token_aquired',
|
|
189
|
+
logout_from_another_tab: 'logout_from_another_tab',
|
|
190
|
+
logout_from_same_tab: 'logout_from_same_tab',
|
|
191
|
+
token_renewed: 'token_renewed',
|
|
192
|
+
token_timer: 'token_timer',
|
|
193
|
+
loginAsync_begin: 'loginAsync_begin',
|
|
194
|
+
loginAsync_error: 'loginAsync_error',
|
|
195
|
+
loginCallbackAsync_begin: 'loginCallbackAsync_begin',
|
|
196
|
+
loginCallbackAsync_end: 'loginCallbackAsync_end',
|
|
197
|
+
loginCallbackAsync_error: 'loginCallbackAsync_error',
|
|
198
|
+
refreshTokensAsync_begin: 'refreshTokensAsync_begin',
|
|
199
|
+
refreshTokensAsync: 'refreshTokensAsync',
|
|
200
|
+
refreshTokensAsync_end: 'refreshTokensAsync_end',
|
|
201
|
+
refreshTokensAsync_error: 'refreshTokensAsync_error',
|
|
202
|
+
refreshTokensAsync_silent_error: 'refreshTokensAsync_silent_error',
|
|
203
|
+
tryKeepExistingSessionAsync_begin: 'tryKeepExistingSessionAsync_begin',
|
|
204
|
+
tryKeepExistingSessionAsync_end: 'tryKeepExistingSessionAsync_end',
|
|
205
|
+
tryKeepExistingSessionAsync_error: 'tryKeepExistingSessionAsync_error',
|
|
206
|
+
silentLoginAsync_begin: 'silentLoginAsync_begin',
|
|
207
|
+
silentLoginAsync: 'silentLoginAsync',
|
|
208
|
+
silentLoginAsync_end: 'silentLoginAsync_end',
|
|
209
|
+
silentLoginAsync_error: 'silentLoginAsync_error',
|
|
210
|
+
syncTokensAsync_begin: 'syncTokensAsync_begin',
|
|
211
|
+
syncTokensAsync_end: 'syncTokensAsync_end',
|
|
212
|
+
syncTokensAsync_error: 'syncTokensAsync_error',
|
|
213
|
+
};
|
|
214
|
+
|
|
108
215
|
const getRandomInt = (max) => {
|
|
109
216
|
return Math.floor(Math.random() * max);
|
|
110
217
|
};
|
|
111
218
|
|
|
219
|
+
const oneHourSecond = 60 * 60;
|
|
220
|
+
const fetchFromIssuer = async (openIdIssuerUrl: string, timeCacheSecond = oneHourSecond, storage = window.sessionStorage):
|
|
221
|
+
Promise<OidcAuthorizationServiceConfiguration> => {
|
|
222
|
+
const fullUrl = `${openIdIssuerUrl}/.well-known/openid-configuration`;
|
|
223
|
+
|
|
224
|
+
const localStorageKey = `oidc.server:${openIdIssuerUrl}`;
|
|
225
|
+
const data = getFromCache(localStorageKey, storage, timeCacheSecond);
|
|
226
|
+
if (data) {
|
|
227
|
+
return new OidcAuthorizationServiceConfiguration(data);
|
|
228
|
+
}
|
|
229
|
+
const response = await fetch(fullUrl);
|
|
230
|
+
|
|
231
|
+
if (response.status !== 200) {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const result = await response.json();
|
|
236
|
+
|
|
237
|
+
setCache(localStorageKey, result, storage);
|
|
238
|
+
return new OidcAuthorizationServiceConfiguration(result);
|
|
239
|
+
};
|
|
240
|
+
|
|
112
241
|
export class Oidc {
|
|
113
242
|
public configuration: OidcConfiguration;
|
|
114
243
|
public userInfo: null;
|
|
115
244
|
public tokens?: Tokens;
|
|
116
245
|
public events: Array<any>;
|
|
117
246
|
private timeoutId: NodeJS.Timeout;
|
|
118
|
-
|
|
247
|
+
private configurationName: string;
|
|
119
248
|
private checkSessionIFrame: CheckSessionIFrame;
|
|
120
249
|
constructor(configuration:OidcConfiguration, configurationName = 'default') {
|
|
121
250
|
let silent_login_uri = configuration.silent_login_uri;
|
|
@@ -206,7 +335,96 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
206
335
|
}
|
|
207
336
|
|
|
208
337
|
async silentLoginAsync(extras:StringMap = null, state:string = null, scope:string = null) {
|
|
209
|
-
|
|
338
|
+
if (!this.configuration.silent_redirect_uri || !this.configuration.silent_login_uri) {
|
|
339
|
+
return Promise.resolve(null);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
try {
|
|
343
|
+
this.publishEvent(eventNames.silentLoginAsync_begin, {});
|
|
344
|
+
const configuration = this.configuration;
|
|
345
|
+
let queries = '';
|
|
346
|
+
|
|
347
|
+
if (state) {
|
|
348
|
+
if (extras == null) {
|
|
349
|
+
extras = {};
|
|
350
|
+
}
|
|
351
|
+
extras.state = state;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (scope) {
|
|
355
|
+
if (extras == null) {
|
|
356
|
+
extras = {};
|
|
357
|
+
}
|
|
358
|
+
extras.scope = scope;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (extras != null) {
|
|
362
|
+
for (const [key, value] of Object.entries(extras)) {
|
|
363
|
+
if (queries === '') {
|
|
364
|
+
queries = `?${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
|
|
365
|
+
} else {
|
|
366
|
+
queries += `&${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
const link = configuration.silent_login_uri + queries;
|
|
371
|
+
const idx = link.indexOf('/', link.indexOf('//') + 2);
|
|
372
|
+
const iFrameOrigin = link.substr(0, idx);
|
|
373
|
+
const iframe = document.createElement('iframe');
|
|
374
|
+
iframe.width = '0px';
|
|
375
|
+
iframe.height = '0px';
|
|
376
|
+
|
|
377
|
+
iframe.id = `${this.configurationName}_oidc_iframe`;
|
|
378
|
+
iframe.setAttribute('src', link);
|
|
379
|
+
document.body.appendChild(iframe);
|
|
380
|
+
return new Promise((resolve, reject) => {
|
|
381
|
+
try {
|
|
382
|
+
let isResolved = false;
|
|
383
|
+
window.onmessage = (e: MessageEvent<any>) => {
|
|
384
|
+
if (e.origin === iFrameOrigin &&
|
|
385
|
+
e.source === iframe.contentWindow
|
|
386
|
+
) {
|
|
387
|
+
const key = `${this.configurationName}_oidc_tokens:`;
|
|
388
|
+
const key_error = `${this.configurationName}_oidc_error:`;
|
|
389
|
+
const data = e.data;
|
|
390
|
+
if (data && typeof (data) === 'string') {
|
|
391
|
+
if (!isResolved) {
|
|
392
|
+
if (data.startsWith(key)) {
|
|
393
|
+
const result = JSON.parse(e.data.replace(key, ''));
|
|
394
|
+
this.publishEvent(eventNames.silentLoginAsync_end, {});
|
|
395
|
+
iframe.remove();
|
|
396
|
+
isResolved = true;
|
|
397
|
+
resolve(result);
|
|
398
|
+
} else if (data.startsWith(key_error)) {
|
|
399
|
+
const result = JSON.parse(e.data.replace(key_error, ''));
|
|
400
|
+
this.publishEvent(eventNames.silentLoginAsync_error, result);
|
|
401
|
+
iframe.remove();
|
|
402
|
+
isResolved = true;
|
|
403
|
+
reject(new Error('oidc_' + result.error));
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
const silentSigninTimeout = configuration.silent_login_timeout;
|
|
410
|
+
setTimeout(() => {
|
|
411
|
+
if (!isResolved) {
|
|
412
|
+
this.publishEvent(eventNames.silentLoginAsync_error, { reason: 'timeout' });
|
|
413
|
+
iframe.remove();
|
|
414
|
+
isResolved = true;
|
|
415
|
+
reject(new Error('timeout'));
|
|
416
|
+
}
|
|
417
|
+
}, silentSigninTimeout);
|
|
418
|
+
} catch (e) {
|
|
419
|
+
iframe.remove();
|
|
420
|
+
this.publishEvent(eventNames.silentLoginAsync_error, e);
|
|
421
|
+
reject(e);
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
} catch (e) {
|
|
425
|
+
this.publishEvent(eventNames.silentLoginAsync_error, e);
|
|
426
|
+
throw e;
|
|
427
|
+
}
|
|
210
428
|
}
|
|
211
429
|
|
|
212
430
|
initPromise = null;
|
|
@@ -227,7 +445,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
227
445
|
});
|
|
228
446
|
}
|
|
229
447
|
|
|
230
|
-
const serviceWorker = await initWorkerAsync(this.configuration.service_worker_relative_url, this.configurationName);
|
|
448
|
+
const serviceWorker = await initWorkerAsync(this.configuration.service_worker_relative_url, this.configurationName, this.configuration.redirect_uri);
|
|
231
449
|
const storage = serviceWorker ? window.localStorage : null;
|
|
232
450
|
return await fetchFromIssuer(authority, this.configuration.authority_time_cache_wellknowurl_in_second ?? 60 * 60, storage);
|
|
233
451
|
};
|
|
@@ -252,7 +470,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
252
470
|
try {
|
|
253
471
|
const configuration = this.configuration;
|
|
254
472
|
const oidcServerConfiguration = await this.initAsync(configuration.authority, configuration.authority_configuration);
|
|
255
|
-
serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, this.configurationName);
|
|
473
|
+
serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, this.configurationName, configuration.redirect_uri);
|
|
256
474
|
if (serviceWorker) {
|
|
257
475
|
const { tokens } = await serviceWorker.initAsync(oidcServerConfiguration, 'tryKeepExistingSessionAsync', configuration);
|
|
258
476
|
if (tokens) {
|
|
@@ -280,7 +498,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
280
498
|
message: 'service worker is not supported by this browser',
|
|
281
499
|
});
|
|
282
500
|
}
|
|
283
|
-
const session = initSession(this.configurationName, configuration.storage ?? sessionStorage);
|
|
501
|
+
const session = initSession(this.configurationName, configuration.redirect_uri, configuration.storage ?? sessionStorage);
|
|
284
502
|
const { tokens } = await session.initAsync();
|
|
285
503
|
if (tokens) {
|
|
286
504
|
// @ts-ignore
|
|
@@ -319,26 +537,146 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
319
537
|
});
|
|
320
538
|
}
|
|
321
539
|
|
|
322
|
-
async startCheckSessionAsync(checkSessionIFrameUri, clientId, sessionState, isSilentSignin = false) {
|
|
323
|
-
const getCurrentTokens = () => this.tokens;
|
|
324
|
-
this.checkSessionIFrame = await defaultStartCheckSessionAsync(oidcDatabase, this.configuration, this.checkSessionIFrame, this.silentLoginAsync.bind(this), getCurrentTokens)(checkSessionIFrameUri, clientId, sessionState, isSilentSignin);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
540
|
loginPromise: Promise<void> = null;
|
|
328
541
|
async loginAsync(callbackPath:string = undefined, extras:StringMap = null, isSilentSignin = false, scope:string = undefined, silentLoginOnly = false) {
|
|
329
542
|
if (this.loginPromise !== null) {
|
|
330
543
|
return this.loginPromise;
|
|
331
544
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
545
|
+
const loginLocalAsync = async () => {
|
|
546
|
+
const location = window.location;
|
|
547
|
+
const url = callbackPath || location.pathname + (location.search || '') + (location.hash || '');
|
|
548
|
+
const configuration = this.configuration;
|
|
549
|
+
let state;
|
|
550
|
+
if (extras && 'state' in extras) {
|
|
551
|
+
state = extras.state;
|
|
552
|
+
delete extras.state;
|
|
553
|
+
}
|
|
554
|
+
if (silentLoginOnly) {
|
|
555
|
+
try {
|
|
556
|
+
const extraFinal = extras ?? configuration.extras ?? {};
|
|
557
|
+
const silentResult = await this.silentLoginAsync({
|
|
558
|
+
...extraFinal,
|
|
559
|
+
prompt: 'none',
|
|
560
|
+
}, state, scope);
|
|
561
|
+
|
|
562
|
+
if (silentResult) {
|
|
563
|
+
this.tokens = silentResult.tokens;
|
|
564
|
+
this.publishEvent(eventNames.token_aquired, {});
|
|
565
|
+
// @ts-ignore
|
|
566
|
+
this.timeoutId = autoRenewTokens(this, this.tokens.refreshToken, this.tokens.expiresAt, extras);
|
|
567
|
+
return {};
|
|
568
|
+
}
|
|
569
|
+
} catch (e) {
|
|
570
|
+
return e;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
this.publishEvent(eventNames.loginAsync_begin, {});
|
|
574
|
+
|
|
575
|
+
try {
|
|
576
|
+
const redirectUri = isSilentSignin ? configuration.silent_redirect_uri : configuration.redirect_uri;
|
|
577
|
+
if (!scope) {
|
|
578
|
+
scope = configuration.scope;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
const extraFinal = extras ?? configuration.extras ?? {};
|
|
582
|
+
if (!extraFinal.nonce) {
|
|
583
|
+
extraFinal.nonce = randomString(12);
|
|
584
|
+
}
|
|
585
|
+
const nonce = { nonce: extraFinal.nonce };
|
|
586
|
+
const serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, this.configurationName, this.configuration.redirect_uri);
|
|
587
|
+
const oidcServerConfiguration = await this.initAsync(configuration.authority, configuration.authority_configuration);
|
|
588
|
+
let storage;
|
|
589
|
+
if (serviceWorker) {
|
|
590
|
+
serviceWorker.setLoginParams(this.configurationName, redirectUri, { callbackPath: url, extras, state });
|
|
591
|
+
serviceWorker.startKeepAliveServiceWorker();
|
|
592
|
+
await serviceWorker.initAsync(oidcServerConfiguration, 'loginAsync', configuration);
|
|
593
|
+
await serviceWorker.setNonceAsync(nonce);
|
|
594
|
+
storage = new MemoryStorageBackend(serviceWorker.saveItemsAsync, {});
|
|
595
|
+
await storage.setItem('dummy', {});
|
|
596
|
+
} else {
|
|
597
|
+
const session = initSession(this.configurationName, redirectUri);
|
|
598
|
+
session.setLoginParams(this.configurationName, redirectUri, { callbackPath: url, extras, state });
|
|
599
|
+
await session.setNonceAsync(nonce);
|
|
600
|
+
storage = new MemoryStorageBackend(session.saveItemsAsync, {});
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// @ts-ignore
|
|
604
|
+
const queryStringUtil = redirectUri.includes('#') ? new HashQueryStringUtils() : new NoHashQueryStringUtils();
|
|
605
|
+
const authorizationHandler = new RedirectRequestHandler(storage, queryStringUtil, window.location, new DefaultCrypto());
|
|
606
|
+
const authRequest = new AuthorizationRequest({
|
|
607
|
+
client_id: configuration.client_id,
|
|
608
|
+
redirect_uri: redirectUri,
|
|
609
|
+
scope,
|
|
610
|
+
response_type: AuthorizationRequest.RESPONSE_TYPE_CODE,
|
|
611
|
+
state,
|
|
612
|
+
extras: extraFinal,
|
|
613
|
+
});
|
|
614
|
+
authorizationHandler.performAuthorizationRequest(oidcServerConfiguration, authRequest);
|
|
615
|
+
} catch (exception) {
|
|
616
|
+
this.publishEvent(eventNames.loginAsync_error, exception);
|
|
617
|
+
throw exception;
|
|
618
|
+
}
|
|
619
|
+
};
|
|
620
|
+
this.loginPromise = loginLocalAsync();
|
|
336
621
|
return this.loginPromise.then(result => {
|
|
337
622
|
this.loginPromise = null;
|
|
338
623
|
return result;
|
|
339
624
|
});
|
|
340
625
|
}
|
|
341
626
|
|
|
627
|
+
async startCheckSessionAsync(checkSessionIFrameUri, clientId, sessionState, isSilentSignin = false) {
|
|
628
|
+
return new Promise<void>((resolve, reject): void => {
|
|
629
|
+
if (this.configuration.silent_login_uri && this.configuration.silent_redirect_uri && this.configuration.monitor_session && checkSessionIFrameUri && sessionState && !isSilentSignin) {
|
|
630
|
+
const checkSessionCallback = () => {
|
|
631
|
+
this.checkSessionIFrame.stop();
|
|
632
|
+
|
|
633
|
+
if (this.tokens === null) {
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
// @ts-ignore
|
|
637
|
+
const idToken = this.tokens.idToken;
|
|
638
|
+
// @ts-ignore
|
|
639
|
+
const idTokenPayload = this.tokens.idTokenPayload;
|
|
640
|
+
this.silentLoginAsync({
|
|
641
|
+
prompt: 'none',
|
|
642
|
+
id_token_hint: idToken,
|
|
643
|
+
scope: 'openid',
|
|
644
|
+
}).then((silentSigninResponse) => {
|
|
645
|
+
const iFrameIdTokenPayload = silentSigninResponse.tokens.idTokenPayload;
|
|
646
|
+
if (idTokenPayload.sub === iFrameIdTokenPayload.sub) {
|
|
647
|
+
const sessionState = silentSigninResponse.sessionState;
|
|
648
|
+
this.checkSessionIFrame.start(silentSigninResponse.sessionState);
|
|
649
|
+
if (idTokenPayload.sid === iFrameIdTokenPayload.sid) {
|
|
650
|
+
console.debug('SessionMonitor._callback: Same sub still logged in at OP, restarting check session iframe; session_state:', sessionState);
|
|
651
|
+
} else {
|
|
652
|
+
console.debug('SessionMonitor._callback: Same sub still logged in at OP, session state has changed, restarting check session iframe; session_state:', sessionState);
|
|
653
|
+
}
|
|
654
|
+
} else {
|
|
655
|
+
console.debug('SessionMonitor._callback: Different subject signed into OP:', iFrameIdTokenPayload.sub);
|
|
656
|
+
}
|
|
657
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
658
|
+
}).catch(async (e) => {
|
|
659
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
660
|
+
for (const [key, oidc] of Object.entries(oidcDatabase)) {
|
|
661
|
+
// @ts-ignore
|
|
662
|
+
await oidc.logoutOtherTabAsync(this.configuration.client_id, idTokenPayload.sub);
|
|
663
|
+
}
|
|
664
|
+
});
|
|
665
|
+
};
|
|
666
|
+
|
|
667
|
+
this.checkSessionIFrame = new CheckSessionIFrame(checkSessionCallback, clientId, checkSessionIFrameUri);
|
|
668
|
+
this.checkSessionIFrame.load().then(() => {
|
|
669
|
+
this.checkSessionIFrame.start(sessionState);
|
|
670
|
+
resolve();
|
|
671
|
+
}).catch((e) => {
|
|
672
|
+
reject(e);
|
|
673
|
+
});
|
|
674
|
+
} else {
|
|
675
|
+
resolve();
|
|
676
|
+
}
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
|
|
342
680
|
loginCallbackPromise : Promise<any> = null;
|
|
343
681
|
async loginCallbackAsync(isSilenSignin = false) {
|
|
344
682
|
if (this.loginCallbackPromise !== null) {
|
|
@@ -351,9 +689,9 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
351
689
|
const parsedTokens = response.tokens;
|
|
352
690
|
// @ts-ignore
|
|
353
691
|
this.tokens = response.tokens;
|
|
354
|
-
const serviceWorker = await initWorkerAsync(this.configuration.service_worker_relative_url, this.configurationName);
|
|
692
|
+
const serviceWorker = await initWorkerAsync(this.configuration.service_worker_relative_url, this.configurationName, this.configuration.redirect_uri);
|
|
355
693
|
if (!serviceWorker) {
|
|
356
|
-
const session = initSession(this.configurationName, this.configuration.storage);
|
|
694
|
+
const session = initSession(this.configurationName, this.configuration.redirect_uri, this.configuration.storage);
|
|
357
695
|
session.setTokens(parsedTokens);
|
|
358
696
|
}
|
|
359
697
|
this.publishEvent(Oidc.eventNames.token_aquired, parsedTokens);
|
|
@@ -378,10 +716,9 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
378
716
|
const oidcServerConfiguration = await this.initAsync(authority, configuration.authority_configuration);
|
|
379
717
|
const queryParams = getParseQueryStringFromLocation(window.location.href);
|
|
380
718
|
const sessionState = queryParams.session_state;
|
|
381
|
-
const serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, this.configurationName);
|
|
719
|
+
const serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, this.configurationName, configuration.redirect_uri);
|
|
382
720
|
let storage = null;
|
|
383
721
|
let nonceData = null;
|
|
384
|
-
let getLoginParams = null;
|
|
385
722
|
if (serviceWorker) {
|
|
386
723
|
serviceWorker.startKeepAliveServiceWorker();
|
|
387
724
|
await serviceWorker.initAsync(oidcServerConfiguration, 'loginCallbackAsync', configuration);
|
|
@@ -394,14 +731,12 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
394
731
|
await storage.removeItem('dummy');
|
|
395
732
|
await serviceWorker.setSessionStateAsync(sessionState);
|
|
396
733
|
nonceData = await serviceWorker.getNonceAsync();
|
|
397
|
-
getLoginParams = serviceWorker.getLoginParams(this.configurationName);
|
|
398
734
|
} else {
|
|
399
|
-
const session = initSession(this.configurationName);
|
|
735
|
+
const session = initSession(this.configurationName, redirectUri);
|
|
400
736
|
session.setSessionState(sessionState);
|
|
401
737
|
const items = await session.loadItemsAsync();
|
|
402
738
|
storage = new MemoryStorageBackend(session.saveItemsAsync, items);
|
|
403
739
|
nonceData = await session.getNonceAsync();
|
|
404
|
-
getLoginParams = session.getLoginParams(this.configurationName);
|
|
405
740
|
}
|
|
406
741
|
|
|
407
742
|
return new Promise((resolve, reject) => {
|
|
@@ -426,28 +761,21 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
426
761
|
return;
|
|
427
762
|
}
|
|
428
763
|
|
|
429
|
-
|
|
764
|
+
let extras = null;
|
|
430
765
|
if (request && request.internal) {
|
|
431
|
-
|
|
766
|
+
extras = {};
|
|
432
767
|
extras.code_verifier = request.internal.code_verifier;
|
|
433
768
|
if (configuration.token_request_extras) {
|
|
434
769
|
for (const [key, value] of Object.entries(configuration.token_request_extras)) {
|
|
435
770
|
extras[key] = value;
|
|
436
771
|
}
|
|
437
772
|
}
|
|
438
|
-
if (getLoginParams && getLoginParams.extras) {
|
|
439
|
-
for (const [key, value] of Object.entries(getLoginParams.extras)) {
|
|
440
|
-
if (key.endsWith(':token_request')) {
|
|
441
|
-
extras[key.replace(':token_request', '')] = value;
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
773
|
}
|
|
446
774
|
|
|
447
775
|
const tokenRequest = new TokenRequest({
|
|
448
776
|
client_id: clientId,
|
|
449
|
-
redirect_uri: redirectUri,
|
|
450
|
-
grant_type:
|
|
777
|
+
redirect_uri: redirectUri,
|
|
778
|
+
grant_type: GRANT_TYPE_AUTHORIZATION_CODE,
|
|
451
779
|
code: response.code,
|
|
452
780
|
refresh_token: undefined,
|
|
453
781
|
extras,
|
|
@@ -467,11 +795,11 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
467
795
|
let formattedTokens = null;
|
|
468
796
|
if (serviceWorker) {
|
|
469
797
|
const { tokens } = await serviceWorker.initAsync(oidcServerConfiguration, 'syncTokensAsync', configuration);
|
|
470
|
-
loginParams = serviceWorker.getLoginParams(this.configurationName);
|
|
798
|
+
loginParams = serviceWorker.getLoginParams(this.configurationName, redirectUri);
|
|
471
799
|
formattedTokens = tokens;
|
|
472
800
|
} else {
|
|
473
|
-
const session = initSession(this.configurationName, configuration.storage);
|
|
474
|
-
loginParams = session.getLoginParams(this.configurationName);
|
|
801
|
+
const session = initSession(this.configurationName, redirectUri, configuration.storage);
|
|
802
|
+
loginParams = session.getLoginParams(this.configurationName, redirectUri);
|
|
475
803
|
formattedTokens = setTokens(tokenResponse, null, configuration.token_renew_mode);
|
|
476
804
|
}
|
|
477
805
|
if (!isTokensOidcValid(formattedTokens, nonceData.nonce, oidcServerConfiguration)) {
|
|
@@ -540,12 +868,12 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
540
868
|
const localsilentLoginAsync = async () => {
|
|
541
869
|
try {
|
|
542
870
|
let loginParams = null;
|
|
543
|
-
const serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, this.configurationName);
|
|
871
|
+
const serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, this.configurationName, configuration.redirect_uri);
|
|
544
872
|
if (serviceWorker) {
|
|
545
|
-
loginParams = serviceWorker.getLoginParams(this.configurationName);
|
|
873
|
+
loginParams = serviceWorker.getLoginParams(this.configurationName, configuration.redirect_uri);
|
|
546
874
|
} else {
|
|
547
|
-
const session = initSession(this.configurationName, configuration.storage);
|
|
548
|
-
loginParams = session.getLoginParams(this.configurationName);
|
|
875
|
+
const session = initSession(this.configurationName, configuration.redirect_uri, configuration.storage);
|
|
876
|
+
loginParams = session.getLoginParams(this.configurationName, configuration.redirect_uri);
|
|
549
877
|
}
|
|
550
878
|
const silent_token_response = await this.silentLoginAsync({
|
|
551
879
|
...loginParams.extras,
|
|
@@ -657,7 +985,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
657
985
|
}
|
|
658
986
|
let nonce = nullNonce;
|
|
659
987
|
const oidcServerConfiguration = await this.initAsync(configuration.authority, configuration.authority_configuration);
|
|
660
|
-
const serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, configurationName);
|
|
988
|
+
const serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, configurationName, configuration.redirect_uri);
|
|
661
989
|
if (serviceWorker) {
|
|
662
990
|
const { status, tokens } = await serviceWorker.initAsync(oidcServerConfiguration, 'syncTokensAsync', configuration);
|
|
663
991
|
if (status === 'LOGGED_OUT') {
|
|
@@ -674,7 +1002,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
674
1002
|
}
|
|
675
1003
|
nonce = await serviceWorker.getNonceAsync();
|
|
676
1004
|
} else {
|
|
677
|
-
const session = initSession(configurationName, configuration.storage ?? sessionStorage);
|
|
1005
|
+
const session = initSession(configurationName, configuration.redirect_uri, configuration.storage ?? sessionStorage);
|
|
678
1006
|
const { tokens, status } = await session.initAsync();
|
|
679
1007
|
if (!tokens) {
|
|
680
1008
|
return { tokens: null, status: 'LOGOUT_FROM_ANOTHER_TAB', nonce: nullNonce };
|
|
@@ -736,9 +1064,9 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
736
1064
|
if (this.checkSessionIFrame) {
|
|
737
1065
|
this.checkSessionIFrame.stop();
|
|
738
1066
|
}
|
|
739
|
-
const serviceWorker = await initWorkerAsync(this.configuration.service_worker_relative_url, this.configurationName);
|
|
1067
|
+
const serviceWorker = await initWorkerAsync(this.configuration.service_worker_relative_url, this.configurationName, this.configuration.redirect_uri);
|
|
740
1068
|
if (!serviceWorker) {
|
|
741
|
-
const session = initSession(this.configurationName, this.configuration.storage);
|
|
1069
|
+
const session = initSession(this.configurationName, this.configuration.redirect_uri, this.configuration.storage);
|
|
742
1070
|
await session.clearAsync(status);
|
|
743
1071
|
} else {
|
|
744
1072
|
await serviceWorker.clearAsync(status);
|
|
@@ -1,29 +1,5 @@
|
|
|
1
|
-
import { getFromCache, setCache } from './cache';
|
|
2
|
-
import { OidcAuthorizationServiceConfiguration } from './oidc';
|
|
3
1
|
import { parseOriginalTokens } from './parseTokens';
|
|
4
2
|
|
|
5
|
-
const oneHourSecond = 60 * 60;
|
|
6
|
-
export const fetchFromIssuer = async (openIdIssuerUrl: string, timeCacheSecond = oneHourSecond, storage = window.sessionStorage):
|
|
7
|
-
Promise<OidcAuthorizationServiceConfiguration> => {
|
|
8
|
-
const fullUrl = `${openIdIssuerUrl}/.well-known/openid-configuration`;
|
|
9
|
-
|
|
10
|
-
const localStorageKey = `oidc.server:${openIdIssuerUrl}`;
|
|
11
|
-
const data = getFromCache(localStorageKey, storage, timeCacheSecond);
|
|
12
|
-
if (data) {
|
|
13
|
-
return new OidcAuthorizationServiceConfiguration(data);
|
|
14
|
-
}
|
|
15
|
-
const response = await fetch(fullUrl);
|
|
16
|
-
|
|
17
|
-
if (response.status !== 200) {
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const result = await response.json();
|
|
22
|
-
|
|
23
|
-
setCache(localStorageKey, result, storage);
|
|
24
|
-
return new OidcAuthorizationServiceConfiguration(result);
|
|
25
|
-
};
|
|
26
|
-
|
|
27
3
|
const internalFetch = async (url, headers, numberRetry = 0, timeoutMs = 10000) => {
|
|
28
4
|
let response;
|
|
29
5
|
try {
|
|
@@ -72,7 +72,7 @@ const parseQueryString = (queryString:string) => {
|
|
|
72
72
|
// Convert the array of strings into an object
|
|
73
73
|
for (i = 0, l = queries.length; i < l; i++) {
|
|
74
74
|
temp = queries[i].split('=');
|
|
75
|
-
params[
|
|
75
|
+
params[temp[0]] = temp[1];
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
return params;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { LoginCallback, Oidc } from './oidc';
|
|
1
|
+
import { LoginCallback, Oidc, OidcConfiguration, StringMap } from './oidc';
|
|
2
2
|
import { getValidTokenAsync, Tokens, ValidToken } from './parseTokens';
|
|
3
|
-
import { OidcConfiguration, StringMap } from './types';
|
|
4
3
|
|
|
5
4
|
export interface EventSubscriber {
|
|
6
5
|
(name: string, data:any);
|