@axa-fr/react-oidc 6.13.4 → 6.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/OidcServiceWorker.js +36 -9
  2. package/dist/vanilla/crypto.d.ts +4 -0
  3. package/dist/vanilla/crypto.d.ts.map +1 -0
  4. package/dist/vanilla/crypto.js +81 -0
  5. package/dist/vanilla/crypto.js.map +1 -0
  6. package/dist/vanilla/initSession.d.ts +6 -4
  7. package/dist/vanilla/initSession.d.ts.map +1 -1
  8. package/dist/vanilla/initSession.js +22 -15
  9. package/dist/vanilla/initSession.js.map +1 -1
  10. package/dist/vanilla/initWorker.d.ts +4 -2
  11. package/dist/vanilla/initWorker.d.ts.map +1 -1
  12. package/dist/vanilla/initWorker.js +39 -18
  13. package/dist/vanilla/initWorker.js.map +1 -1
  14. package/dist/vanilla/login.d.ts +5 -1
  15. package/dist/vanilla/login.d.ts.map +1 -1
  16. package/dist/vanilla/login.js +70 -143
  17. package/dist/vanilla/login.js.map +1 -1
  18. package/dist/vanilla/logout.d.ts +4 -0
  19. package/dist/vanilla/logout.d.ts.map +1 -0
  20. package/dist/vanilla/logout.js +113 -0
  21. package/dist/vanilla/logout.js.map +1 -0
  22. package/dist/vanilla/oidc.d.ts +11 -6
  23. package/dist/vanilla/oidc.d.ts.map +1 -1
  24. package/dist/vanilla/oidc.js +26 -94
  25. package/dist/vanilla/oidc.js.map +1 -1
  26. package/dist/vanilla/requests.d.ts +14 -0
  27. package/dist/vanilla/requests.d.ts.map +1 -1
  28. package/dist/vanilla/requests.js +56 -1
  29. package/dist/vanilla/requests.js.map +1 -1
  30. package/dist/vanilla/route-utils.js +2 -2
  31. package/dist/vanilla/route-utils.js.map +1 -1
  32. package/package.json +2 -2
  33. package/src/oidc/vanilla/OidcServiceWorker.js +36 -9
  34. package/src/oidc/vanilla/crypto.ts +57 -0
  35. package/src/oidc/vanilla/initSession.ts +25 -15
  36. package/src/oidc/vanilla/initWorker.ts +43 -18
  37. package/src/oidc/vanilla/login.ts +76 -148
  38. package/src/oidc/vanilla/logout.ts +95 -0
  39. package/src/oidc/vanilla/oidc.ts +35 -98
  40. package/src/oidc/vanilla/requests.spec.ts +4 -0
  41. package/src/oidc/vanilla/requests.ts +55 -0
  42. package/src/oidc/vanilla/route-utils.ts +2 -2
  43. package/dist/vanilla/memoryStorageBackend.d.ts +0 -11
  44. package/dist/vanilla/memoryStorageBackend.d.ts.map +0 -1
  45. package/dist/vanilla/memoryStorageBackend.js +0 -31
  46. package/dist/vanilla/memoryStorageBackend.js.map +0 -1
  47. package/dist/vanilla/noHashQueryStringUtils.d.ts +0 -8
  48. package/dist/vanilla/noHashQueryStringUtils.d.ts.map +0 -1
  49. package/dist/vanilla/noHashQueryStringUtils.js +0 -32
  50. package/dist/vanilla/noHashQueryStringUtils.js.map +0 -1
  51. package/src/oidc/vanilla/memoryStorageBackend.ts +0 -40
  52. package/src/oidc/vanilla/noHashQueryStringUtils.ts +0 -32
@@ -1,13 +1,5 @@
1
- export const initSession = (configurationName, storage = sessionStorage) => {
2
- const saveItemsAsync = (items) => {
3
- storage[`oidc.items.${configurationName}`] = JSON.stringify(items);
4
- return Promise.resolve();
5
- };
6
-
7
- const loadItemsAsync = () => {
8
- return Promise.resolve(JSON.parse(storage[`oidc.items.${configurationName}`]));
9
- };
10
1
 
2
+ export const initSession = (configurationName, storage = sessionStorage) => {
11
3
  const clearAsync = (status) => {
12
4
  storage[`oidc.${configurationName}`] = JSON.stringify({ tokens: null, status });
13
5
  return Promise.resolve();
@@ -26,11 +18,11 @@ export const initSession = (configurationName, storage = sessionStorage) => {
26
18
  storage[`oidc.${configurationName}`] = JSON.stringify({ tokens });
27
19
  };
28
20
 
29
- const setSessionState = (sessionState) => {
21
+ const setSessionStateAsync = async (sessionState) => {
30
22
  storage[`oidc.session_state.${configurationName}`] = sessionState;
31
23
  };
32
24
 
33
- const getSessionState = () => {
25
+ const getSessionStateAsync = async () => {
34
26
  return storage[`oidc.session_state.${configurationName}`];
35
27
  };
36
28
 
@@ -63,18 +55,36 @@ export const initSession = (configurationName, storage = sessionStorage) => {
63
55
  return getLoginParamsCache;
64
56
  };
65
57
 
58
+ const getStateAsync = async () => {
59
+ return storage[`oidc.state.${configurationName}`];
60
+ };
61
+
62
+ const setStateAsync = async (state) => {
63
+ storage[`oidc.state.${configurationName}`] = state;
64
+ };
65
+
66
+ const getCodeVerifierAsync = async () => {
67
+ return storage[`oidc.code_verifier.${configurationName}`];
68
+ };
69
+
70
+ const setCodeVerifierAsync = async (codeVerifier) => {
71
+ storage[`oidc.code_verifier.${configurationName}`] = codeVerifier;
72
+ };
73
+
66
74
  return {
67
- saveItemsAsync,
68
- loadItemsAsync,
69
75
  clearAsync,
70
76
  initAsync,
71
77
  setTokens,
72
78
  getTokens,
73
- setSessionState,
74
- getSessionState,
79
+ setSessionStateAsync,
80
+ getSessionStateAsync,
75
81
  setNonceAsync,
76
82
  getNonceAsync,
77
83
  setLoginParams,
78
84
  getLoginParams,
85
+ getStateAsync,
86
+ setStateAsync,
87
+ getCodeVerifierAsync,
88
+ setCodeVerifierAsync,
79
89
  };
80
90
  };
@@ -189,22 +189,6 @@ export const initWorkerAsync = async(serviceWorkerRelativeUrl, configurationName
189
189
  });
190
190
  });
191
191
 
192
- const saveItemsAsync = (items) => {
193
- // iOS kill Service Worker when domain we leave domain
194
- if (operatingSystem.os === 'iOS') {
195
- const session = initSession(configurationName);
196
- return session.saveItemsAsync(items);
197
- }
198
- return sendMessageAsync(registration)({ type: 'saveItems', data: items, configurationName });
199
- };
200
- const loadItemsAsync = () => {
201
- // iOS kill Service Worker when domain we leave domain
202
- if (operatingSystem.os === 'iOS') {
203
- const session = initSession(configurationName);
204
- return session.loadItemsAsync();
205
- }
206
- return sendMessageAsync(registration)({ type: 'loadItems', data: null, configurationName });
207
- };
208
192
  const clearAsync = async (status) => {
209
193
  // iOS kill Service Worker when domain we leave domain
210
194
  if (operatingSystem.os === 'iOS') {
@@ -274,9 +258,46 @@ export const initWorkerAsync = async(serviceWorkerRelativeUrl, configurationName
274
258
  return getLoginParamsCache;
275
259
  };
276
260
 
261
+ const getStateAsync = async () => {
262
+ // iOS kill Service Worker when domain we leave domain
263
+ if (operatingSystem.os === 'iOS') {
264
+ const session = initSession(configurationName);
265
+ return session.getStateAsync();
266
+ }
267
+ const result = await sendMessageAsync(registration)({ type: 'getState', data: null, configurationName });
268
+ // @ts-ignore
269
+ return result.state;
270
+ };
271
+
272
+ const setStateAsync = async (state) => {
273
+ // iOS kill Service Worker when domain we leave domain
274
+ if (operatingSystem.os === 'iOS') {
275
+ const session = initSession(configurationName);
276
+ return session.setStateAsync(state);
277
+ }
278
+ return sendMessageAsync(registration)({ type: 'setState', data: { state }, configurationName });
279
+ };
280
+
281
+ const getCodeVerifierAsync = async () => {
282
+ // iOS kill Service Worker when domain we leave domain
283
+ if (operatingSystem.os === 'iOS') {
284
+ const session = initSession(configurationName);
285
+ return session.getCodeVerifierAsync();
286
+ }
287
+ const result = await sendMessageAsync(registration)({ type: 'getCodeVerifier', data: null, configurationName });
288
+ // @ts-ignore
289
+ return result.codeVerifier;
290
+ };
291
+
292
+ const setCodeVerifierAsync = async (codeVerifier) => {
293
+ if (operatingSystem.os === 'iOS') {
294
+ const session = initSession(configurationName);
295
+ return session.setCodeVerifierAsync(codeVerifier);
296
+ }
297
+ return sendMessageAsync(registration)({ type: 'setCodeVerifier', data: { codeVerifier }, configurationName });
298
+ };
299
+
277
300
  return {
278
- saveItemsAsync,
279
- loadItemsAsync,
280
301
  clearAsync,
281
302
  initAsync,
282
303
  startKeepAliveServiceWorker,
@@ -288,5 +309,9 @@ export const initWorkerAsync = async(serviceWorkerRelativeUrl, configurationName
288
309
  unregisterAsync,
289
310
  setLoginParams,
290
311
  getLoginParams,
312
+ getStateAsync,
313
+ setStateAsync,
314
+ getCodeVerifierAsync,
315
+ setCodeVerifierAsync,
291
316
  };
292
317
  };
@@ -1,29 +1,12 @@
1
- import {
2
- AuthorizationNotifier,
3
- AuthorizationRequest, BaseTokenRequestHandler,
4
- DefaultCrypto, FetchRequestor, GRANT_TYPE_AUTHORIZATION_CODE,
5
- RedirectRequestHandler,
6
- TokenRequest,
7
- } from '@openid/appauth';
8
-
1
+ import { generateRandom } from './crypto';
9
2
  import { eventNames } from './events';
10
3
  import { initSession } from './initSession';
11
4
  import { initWorkerAsync } from './initWorker';
12
- import { MemoryStorageBackend } from './memoryStorageBackend';
13
- import { HashQueryStringUtils, NoHashQueryStringUtils } from './noHashQueryStringUtils';
14
- import { isTokensOidcValid, setTokens } from './parseTokens';
5
+ import { isTokensOidcValid } from './parseTokens';
6
+ import { performAuthorizationRequestAsync, performFirstTokenRequestAsync } from './requests';
15
7
  import { getParseQueryStringFromLocation } from './route-utils';
16
8
  import { OidcConfiguration, StringMap } from './types';
17
9
 
18
- const randomString = function(length) {
19
- let text = '';
20
- const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
21
- for (let i = 0; i < length; i++) {
22
- text += possible.charAt(Math.floor(Math.random() * possible.length));
23
- }
24
- return text;
25
- };
26
-
27
10
  // eslint-disable-next-line @typescript-eslint/ban-types
28
11
  export const defaultLoginAsync = (window, configurationName, configuration:OidcConfiguration, publishEvent :(string, any)=>void, initAsync:Function) => (callbackPath:string = undefined, extras:StringMap = null, isSilentSignin = false, scope:string = undefined) => {
29
12
  const originExtras = extras;
@@ -31,10 +14,9 @@ export const defaultLoginAsync = (window, configurationName, configuration:OidcC
31
14
  const loginLocalAsync = async () => {
32
15
  const location = window.location;
33
16
  const url = callbackPath || location.pathname + (location.search || '') + (location.hash || '');
34
- let state;
35
- if (extras && 'state' in extras) {
36
- state = extras.state;
37
- delete extras.state;
17
+
18
+ if (!('state' in extras)) {
19
+ extras.state = generateRandom(16);
38
20
  }
39
21
 
40
22
  publishEvent(eventNames.loginAsync_begin, {});
@@ -53,38 +35,34 @@ export const defaultLoginAsync = (window, configurationName, configuration:OidcC
53
35
 
54
36
  const extraFinal = !configuration.extras ? extras : { ...configuration.extras, ...extras };
55
37
  if (!extraFinal.nonce) {
56
- extraFinal.nonce = randomString(12);
38
+ extraFinal.nonce = generateRandom(12);
57
39
  }
58
40
  const nonce = { nonce: extraFinal.nonce };
59
41
  const serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, configurationName);
60
42
  const oidcServerConfiguration = await initAsync(configuration.authority, configuration.authority_configuration);
61
43
  let storage;
62
44
  if (serviceWorker) {
63
- serviceWorker.setLoginParams(configurationName, { callbackPath: url, extras: originExtras, state });
45
+ serviceWorker.setLoginParams(configurationName, { callbackPath: url, extras: originExtras });
64
46
  serviceWorker.startKeepAliveServiceWorker();
65
47
  await serviceWorker.initAsync(oidcServerConfiguration, 'loginAsync', configuration);
66
48
  await serviceWorker.setNonceAsync(nonce);
67
- storage = new MemoryStorageBackend(serviceWorker.saveItemsAsync, {});
68
- await storage.setItem('dummy', {});
49
+ storage = serviceWorker;
69
50
  } else {
70
51
  const session = initSession(configurationName, configuration.storage ?? sessionStorage);
71
- session.setLoginParams(configurationName, { callbackPath: url, extras: originExtras, state });
52
+ session.setLoginParams(configurationName, { callbackPath: url, extras: originExtras });
72
53
  await session.setNonceAsync(nonce);
73
- storage = new MemoryStorageBackend(session.saveItemsAsync, {});
54
+ storage = session;
74
55
  }
75
56
 
76
57
  // @ts-ignore
77
- const queryStringUtil = redirectUri.includes('#') ? new HashQueryStringUtils() : new NoHashQueryStringUtils();
78
- const authorizationHandler = new RedirectRequestHandler(storage, queryStringUtil, window.location, new DefaultCrypto());
79
- const authRequest = new AuthorizationRequest({
58
+ const extraInternal = {
80
59
  client_id: configuration.client_id,
81
60
  redirect_uri: redirectUri,
82
61
  scope,
83
- response_type: AuthorizationRequest.RESPONSE_TYPE_CODE,
84
- state,
85
- extras: extraFinal,
86
- });
87
- authorizationHandler.performAuthorizationRequest(oidcServerConfiguration, authRequest);
62
+ response_type: 'code',
63
+ ...extraFinal,
64
+ };
65
+ await performAuthorizationRequestAsync(storage)(oidcServerConfiguration.authorizationEndpoint, extraInternal);
88
66
  } catch (exception) {
89
67
  publishEvent(eventNames.loginAsync_error, exception);
90
68
  throw exception;
@@ -105,134 +83,84 @@ export const loginCallbackAsync = (oidc) => async (isSilentSignin = false) => {
105
83
  const queryParams = getParseQueryStringFromLocation(window.location.href);
106
84
  const sessionState = queryParams.session_state;
107
85
  const serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, oidc.configurationName);
108
- let storage = null;
109
- let nonceData = null;
110
- let getLoginParams = null;
86
+ let storage;
87
+ let nonceData;
88
+ let getLoginParams;
89
+ let state;
111
90
  if (serviceWorker) {
112
91
  serviceWorker.startKeepAliveServiceWorker();
113
92
  await serviceWorker.initAsync(oidcServerConfiguration, 'loginCallbackAsync', configuration);
114
- const items = await serviceWorker.loadItemsAsync();
115
- storage = new MemoryStorageBackend(serviceWorker.saveItemsAsync, items);
116
- const dummy = await storage.getItem('dummy');
117
- if (!dummy) {
118
- throw new Error('Service Worker storage disapear');
119
- }
120
- await storage.removeItem('dummy');
121
93
  await serviceWorker.setSessionStateAsync(sessionState);
122
94
  nonceData = await serviceWorker.getNonceAsync();
123
95
  getLoginParams = serviceWorker.getLoginParams(oidc.configurationName);
96
+ state = await serviceWorker.getStateAsync();
97
+ storage = serviceWorker;
124
98
  } else {
125
99
  const session = initSession(oidc.configurationName, configuration.storage ?? sessionStorage);
126
- session.setSessionState(sessionState);
127
- const items = await session.loadItemsAsync();
128
- storage = new MemoryStorageBackend(session.saveItemsAsync, items);
100
+ await session.setSessionStateAsync(sessionState);
129
101
  nonceData = await session.getNonceAsync();
130
102
  getLoginParams = session.getLoginParams(oidc.configurationName);
103
+ state = await session.getStateAsync();
104
+ storage = session;
131
105
  }
132
106
 
133
- return new Promise((resolve, reject) => {
134
- let queryStringUtil = new NoHashQueryStringUtils();
135
- if (redirectUri.includes('#')) {
136
- const splithash = window.location.href.split('#');
137
- if (splithash.length === 2 && splithash[1].includes('?')) {
138
- queryStringUtil = new HashQueryStringUtils();
139
- }
140
- }
141
- const authorizationHandler = new RedirectRequestHandler(storage, queryStringUtil, window.location, new DefaultCrypto());
142
- const notifier = new AuthorizationNotifier();
143
- authorizationHandler.setAuthorizationNotifier(notifier);
107
+ const params = getParseQueryStringFromLocation(window.location.toString());
144
108
 
145
- notifier.setAuthorizationListener((request, response, error) => {
146
- if (error) {
147
- reject(error);
148
- return;
149
- }
150
- if (!response) {
151
- reject(new Error('no response'));
152
- return;
153
- }
109
+ if (params.iss && params.iss !== oidcServerConfiguration.issuer) {
110
+ throw new Error('issuer not valid');
111
+ }
112
+ if (params.state && params.state !== state) {
113
+ throw new Error('state not valid');
114
+ }
115
+
116
+ const data = {
117
+ code: params.code,
118
+ grant_type: 'authorization_code',
119
+ client_id: configuration.client_id,
120
+ redirect_uri: redirectUri,
121
+ };
154
122
 
155
- const extras = {};
156
- if (request && request.internal) {
157
- // @ts-ignore
158
- extras.code_verifier = request.internal.code_verifier;
159
- if (configuration.token_request_extras) {
160
- for (const [key, value] of Object.entries(configuration.token_request_extras)) {
161
- extras[key] = value;
162
- }
163
- }
164
- if (getLoginParams && getLoginParams.extras) {
165
- for (const [key, value] of Object.entries(getLoginParams.extras)) {
166
- if (key.endsWith(':token_request')) {
167
- extras[key.replace(':token_request', '')] = value;
168
- }
169
- }
170
- }
123
+ const extras = {};
124
+ // @ts-ignore
125
+ if (configuration.token_request_extras) {
126
+ for (const [key, value] of Object.entries(configuration.token_request_extras)) {
127
+ extras[key] = value;
128
+ }
129
+ }
130
+ if (getLoginParams && getLoginParams.extras) {
131
+ for (const [key, value] of Object.entries(getLoginParams.extras)) {
132
+ if (key.endsWith(':token_request')) {
133
+ extras[key.replace(':token_request', '')] = value;
171
134
  }
135
+ }
136
+ }
172
137
 
173
- const tokenRequest = new TokenRequest({
174
- client_id: clientId,
175
- redirect_uri: redirectUri, // @ts-ignore
176
- grant_type: GRANT_TYPE_AUTHORIZATION_CODE,
177
- code: response.code,
178
- refresh_token: undefined,
179
- extras,
180
- });
138
+ const tokenResponse = await performFirstTokenRequestAsync(storage)(oidcServerConfiguration.tokenEndpoint, { ...data, ...extras }, oidc.configuration.token_renew_mode, tokenRequestTimeout);
181
139
 
182
- let timeoutId = setTimeout(() => {
183
- reject(new Error('performTokenRequest timeout'));
184
- timeoutId = null;
185
- }, tokenRequestTimeout ?? 12000);
186
- try {
187
- const tokenHandler = new BaseTokenRequestHandler(new FetchRequestor());
188
- tokenHandler.performTokenRequest(oidcServerConfiguration, tokenRequest).then(async (tokenResponse) => {
189
- if (timeoutId) {
190
- clearTimeout(timeoutId);
191
- oidc.timeoutId = null;
192
- let loginParams = null;
193
- let formattedTokens = null;
194
- if (serviceWorker) {
195
- const { tokens } = await serviceWorker.initAsync(oidcServerConfiguration, 'syncTokensAsync', configuration);
196
- loginParams = serviceWorker.getLoginParams(oidc.configurationName);
197
- formattedTokens = tokens;
198
- } else {
199
- const session = initSession(oidc.configurationName, configuration.storage);
200
- loginParams = session.getLoginParams(oidc.configurationName);
201
- formattedTokens = setTokens(tokenResponse, null, configuration.token_renew_mode);
202
- }
203
- if (!isTokensOidcValid(formattedTokens, nonceData.nonce, oidcServerConfiguration)) {
204
- const exception = new Error('Tokens are not OpenID valid');
205
- if (timeoutId) {
206
- clearTimeout(timeoutId);
207
- oidc.timeoutId = null;
208
- oidc.publishEvent(eventNames.loginCallbackAsync_error, exception);
209
- console.error(exception);
210
- reject(exception);
211
- }
212
- }
140
+ let loginParams = null;
141
+ const formattedTokens = tokenResponse.data.tokens;
142
+ if (serviceWorker) {
143
+ await serviceWorker.initAsync(redirectUri, 'syncTokensAsync', configuration);
144
+ loginParams = serviceWorker.getLoginParams(oidc.configurationName);
145
+ } else {
146
+ const session = initSession(oidc.configurationName, configuration.storage);
147
+ loginParams = session.getLoginParams(oidc.configurationName);
148
+ }
149
+ // @ts-ignore
150
+ if (tokenResponse.data.state !== extras.state) {
151
+ throw new Error('state is not valid');
152
+ }
153
+ if (!isTokensOidcValid(formattedTokens, nonceData.nonce, oidcServerConfiguration)) {
154
+ throw new Error('Tokens are not OpenID valid');
155
+ }
213
156
 
214
- oidc.startCheckSessionAsync(oidcServerConfiguration.check_session_iframe, clientId, sessionState, isSilentSignin).then(() => {
215
- oidc.publishEvent(eventNames.loginCallbackAsync_end, {});
216
- resolve({
217
- tokens: formattedTokens,
218
- state: request.state,
219
- callbackPath: loginParams.callbackPath,
220
- });
221
- });
222
- }
223
- });
224
- } catch (exception) {
225
- if (timeoutId) {
226
- clearTimeout(timeoutId);
227
- oidc.timeoutId = null;
228
- oidc.publishEvent(eventNames.loginCallbackAsync_error, exception);
229
- console.error(exception);
230
- reject(exception);
231
- }
232
- }
233
- });
234
- authorizationHandler.completeAuthorizationRequestIfPossible();
235
- });
157
+ await oidc.startCheckSessionAsync(oidcServerConfiguration.check_session_iframe, clientId, sessionState, isSilentSignin);
158
+ oidc.publishEvent(eventNames.loginCallbackAsync_end, {});
159
+ return {
160
+ tokens: formattedTokens,
161
+ state: 'request.state',
162
+ callbackPath: loginParams.callbackPath,
163
+ };
236
164
  } catch (exception) {
237
165
  console.error(exception);
238
166
  oidc.publishEvent(eventNames.loginCallbackAsync_error, exception);
@@ -0,0 +1,95 @@
1
+ import { initSession } from './initSession';
2
+ import { initWorkerAsync } from './initWorker';
3
+ import { performRevocationRequestAsync, TOKEN_TYPE } from './requests';
4
+ import timer from './timer';
5
+ import { StringMap } from './types';
6
+
7
+ export const destroyAsync = (oidc) => async (status) => {
8
+ timer.clearTimeout(oidc.timeoutId);
9
+ oidc.timeoutId = null;
10
+ if (oidc.checkSessionIFrame) {
11
+ oidc.checkSessionIFrame.stop();
12
+ }
13
+ const serviceWorker = await initWorkerAsync(oidc.configuration.service_worker_relative_url, oidc.configurationName);
14
+ if (!serviceWorker) {
15
+ const session = initSession(oidc.configurationName, oidc.configuration.storage);
16
+ await session.clearAsync(status);
17
+ } else {
18
+ await serviceWorker.clearAsync(status);
19
+ }
20
+ oidc.tokens = null;
21
+ oidc.userInfo = null;
22
+ };
23
+
24
+ export const logoutAsync = (oidc, oidcDatabase) => async (callbackPathOrUrl: string | null | undefined = undefined, extras: StringMap = null) => {
25
+ const configuration = oidc.configuration;
26
+ const oidcServerConfiguration = await oidc.initAsync(configuration.authority, configuration.authority_configuration);
27
+ if (callbackPathOrUrl && (typeof callbackPathOrUrl !== 'string')) {
28
+ callbackPathOrUrl = undefined;
29
+ console.warn('callbackPathOrUrl path is not a string');
30
+ }
31
+ const path = (callbackPathOrUrl === null || callbackPathOrUrl === undefined) ? location.pathname + (location.search || '') + (location.hash || '') : callbackPathOrUrl;
32
+ let isUri = false;
33
+ if (callbackPathOrUrl) {
34
+ isUri = callbackPathOrUrl.includes('https://') || callbackPathOrUrl.includes('http://');
35
+ }
36
+ const url = isUri ? callbackPathOrUrl : window.location.origin + path;
37
+ // @ts-ignore
38
+ const idToken = oidc.tokens ? oidc.tokens.idToken : '';
39
+ try {
40
+ const revocationEndpoint = oidcServerConfiguration.revocationEndpoint;
41
+ if (revocationEndpoint) {
42
+ const promises = [];
43
+ const accessToken = oidc.tokens.accessToken;
44
+ if (accessToken) {
45
+ const revokeAccessTokenPromise = performRevocationRequestAsync(revocationEndpoint, accessToken, TOKEN_TYPE.access_token, configuration.client_id);
46
+ promises.push(revokeAccessTokenPromise);
47
+ }
48
+ const refreshToken = oidc.tokens.refreshToken;
49
+ if (refreshToken) {
50
+ const revokeRefreshTokenPromise = performRevocationRequestAsync(revocationEndpoint, refreshToken, TOKEN_TYPE.refresh_token, configuration.client_id);
51
+ promises.push(revokeRefreshTokenPromise);
52
+ }
53
+ if (promises.length > 0) {
54
+ await Promise.all(promises);
55
+ }
56
+ }
57
+ } catch (exception) {
58
+ console.warn(exception);
59
+ }
60
+ // @ts-ignore
61
+ const sub = oidc.tokens && oidc.tokens.idTokenPayload ? oidc.tokens.idTokenPayload.sub : null;
62
+ await oidc.destroyAsync('LOGGED_OUT');
63
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
64
+ for (const [key, itemOidc] of Object.entries(oidcDatabase)) {
65
+ if (itemOidc !== oidc) {
66
+ // @ts-ignore
67
+ await oidc.logoutSameTabAsync(oidc.configuration.client_id, sub);
68
+ }
69
+ }
70
+
71
+ if (oidcServerConfiguration.endSessionEndpoint) {
72
+ if (!extras) {
73
+ extras = {
74
+ id_token_hint: idToken,
75
+ };
76
+ if (callbackPathOrUrl !== null) {
77
+ extras.post_logout_redirect_uri = url;
78
+ }
79
+ }
80
+ let queryString = '';
81
+ if (extras) {
82
+ for (const [key, value] of Object.entries(extras)) {
83
+ if (queryString === '') {
84
+ queryString += '?';
85
+ } else {
86
+ queryString += '&';
87
+ }
88
+ queryString += `${key}=${encodeURIComponent(value)}`;
89
+ }
90
+ }
91
+ window.location.href = `${oidcServerConfiguration.endSessionEndpoint}${queryString}`;
92
+ } else {
93
+ window.location.reload();
94
+ }
95
+ };