@luizleon/sf.prefeiturasp.vuecomponents 0.0.64 → 0.0.66

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/src/keycloak.js CHANGED
@@ -1,3 +1,7 @@
1
+ /** 04/09/2024
2
+ * https://github.com/keycloak/keycloak/blob/main/js/libs/keycloak-js/src/keycloak.js
3
+ */
4
+
1
5
  /*
2
6
  * Copyright 2016 Red Hat, Inc. and/or its affiliates
3
7
  * and other contributors as indicated by the @author tags.
@@ -15,1717 +19,2118 @@
15
19
  * limitations under the License.
16
20
  */
17
21
 
18
- /**
19
- *
20
- * 24/11/2023
21
- *
22
- * https://github.com/keycloak/keycloak/blob/main/js/libs/keycloak-js/src/keycloak.js
23
- *
24
- * Adaptado para expor setToken.
25
- *
26
- * Adpatado para usar URL absoluta em configUrl (linha 829). *
27
- */
28
-
29
- import base64 from 'base64-js';
30
- import sha256 from 'js-sha256';
31
- import { jwtDecode } from 'jwt-decode';
22
+ import { sha256 } from "@noble/hashes/sha256";
23
+ import { jwtDecode } from "jwt-decode";
32
24
 
33
- if (typeof Promise === 'undefined') {
34
- throw Error('Keycloak requires an environment that supports Promises. Make sure that you include the appropriate polyfill.');
25
+ if (typeof Promise === "undefined") {
26
+ throw Error(
27
+ "Keycloak requires an environment that supports Promises. Make sure that you include the appropriate polyfill."
28
+ );
35
29
  }
36
30
 
37
- function Keycloak (config) {
38
- if (!(this instanceof Keycloak)) {
39
- throw new Error("The 'Keycloak' constructor must be invoked with 'new'.")
31
+ function Keycloak(config) {
32
+ if (!(this instanceof Keycloak)) {
33
+ throw new Error(
34
+ "The 'Keycloak' constructor must be invoked with 'new'."
35
+ );
36
+ }
37
+
38
+ var kc = this;
39
+ var adapter;
40
+ var refreshQueue = [];
41
+ var callbackStorage;
42
+
43
+ var loginIframe = {
44
+ enable: true,
45
+ callbackList: [],
46
+ interval: 5,
47
+ };
48
+
49
+ kc.didInitialize = false;
50
+
51
+ var scripts = document.getElementsByTagName("script");
52
+ for (var i = 0; i < scripts.length; i++) {
53
+ if (
54
+ (scripts[i].src.indexOf("keycloak.js") !== -1 ||
55
+ scripts[i].src.indexOf("keycloak.min.js") !== -1) &&
56
+ scripts[i].src.indexOf("version=") !== -1
57
+ ) {
58
+ kc.iframeVersion = scripts[i].src
59
+ .substring(scripts[i].src.indexOf("version=") + 8)
60
+ .split("&")[0];
40
61
  }
62
+ }
41
63
 
42
- var kc = this;
43
- var adapter;
44
- var refreshQueue = [];
45
- var callbackStorage;
64
+ var useNonce = true;
65
+ var logInfo = createLogger(console.info);
66
+ var logWarn = createLogger(console.warn);
46
67
 
47
- var loginIframe = {
48
- enable: true,
49
- callbackList: [],
50
- interval: 5
51
- };
52
-
53
- var scripts = document.getElementsByTagName('script');
54
- for (var i = 0; i < scripts.length; i++) {
55
- if ((scripts[i].src.indexOf('keycloak.js') !== -1 || scripts[i].src.indexOf('keycloak.min.js') !== -1) && scripts[i].src.indexOf('version=') !== -1) {
56
- kc.iframeVersion = scripts[i].src.substring(scripts[i].src.indexOf('version=') + 8).split('&')[0];
57
- }
68
+ kc.init = function (initOptions) {
69
+ if (kc.didInitialize) {
70
+ throw new Error(
71
+ "A 'Keycloak' instance can only be initialized once."
72
+ );
58
73
  }
59
74
 
60
- var useNonce = true;
61
- var logInfo = createLogger(console.info);
62
- var logWarn = createLogger(console.warn);
63
-
64
- kc.init = function (initOptions) {
65
- if (kc.didInitialize) {
66
- throw new Error("A 'Keycloak' instance can only be initialized once.");
67
- }
68
-
69
- kc.didInitialize = true;
70
-
71
- kc.authenticated = false;
72
-
73
- callbackStorage = createCallbackStorage();
74
- var adapters = ['default', 'cordova', 'cordova-native'];
75
+ kc.didInitialize = true;
76
+
77
+ kc.authenticated = false;
78
+
79
+ callbackStorage = createCallbackStorage();
80
+ var adapters = ["default", "cordova", "cordova-native"];
81
+
82
+ if (initOptions && adapters.indexOf(initOptions.adapter) > -1) {
83
+ adapter = loadAdapter(initOptions.adapter);
84
+ } else if (
85
+ initOptions &&
86
+ typeof initOptions.adapter === "object"
87
+ ) {
88
+ adapter = initOptions.adapter;
89
+ } else {
90
+ if (window.Cordova || window.cordova) {
91
+ adapter = loadAdapter("cordova");
92
+ } else {
93
+ adapter = loadAdapter();
94
+ }
95
+ }
75
96
 
76
- if (initOptions && adapters.indexOf(initOptions.adapter) > -1) {
77
- adapter = loadAdapter(initOptions.adapter);
78
- } else if (initOptions && typeof initOptions.adapter === "object") {
79
- adapter = initOptions.adapter;
97
+ if (initOptions) {
98
+ if (typeof initOptions.useNonce !== "undefined") {
99
+ useNonce = initOptions.useNonce;
100
+ }
101
+
102
+ if (typeof initOptions.checkLoginIframe !== "undefined") {
103
+ loginIframe.enable = initOptions.checkLoginIframe;
104
+ }
105
+
106
+ if (initOptions.checkLoginIframeInterval) {
107
+ loginIframe.interval = initOptions.checkLoginIframeInterval;
108
+ }
109
+
110
+ if (initOptions.onLoad === "login-required") {
111
+ kc.loginRequired = true;
112
+ }
113
+
114
+ if (initOptions.responseMode) {
115
+ if (
116
+ initOptions.responseMode === "query" ||
117
+ initOptions.responseMode === "fragment"
118
+ ) {
119
+ kc.responseMode = initOptions.responseMode;
80
120
  } else {
81
- if (window.Cordova || window.cordova) {
82
- adapter = loadAdapter('cordova');
83
- } else {
84
- adapter = loadAdapter();
85
- }
86
- }
87
-
88
- if (initOptions) {
89
- if (typeof initOptions.useNonce !== 'undefined') {
90
- useNonce = initOptions.useNonce;
91
- }
92
-
93
- if (typeof initOptions.checkLoginIframe !== 'undefined') {
94
- loginIframe.enable = initOptions.checkLoginIframe;
95
- }
96
-
97
- if (initOptions.checkLoginIframeInterval) {
98
- loginIframe.interval = initOptions.checkLoginIframeInterval;
99
- }
100
-
101
- if (initOptions.onLoad === 'login-required') {
102
- kc.loginRequired = true;
103
- }
104
-
105
- if (initOptions.responseMode) {
106
- if (initOptions.responseMode === 'query' || initOptions.responseMode === 'fragment') {
107
- kc.responseMode = initOptions.responseMode;
108
- } else {
109
- throw 'Invalid value for responseMode';
110
- }
111
- }
112
-
113
- if (initOptions.flow) {
114
- switch (initOptions.flow) {
115
- case 'standard':
116
- kc.responseType = 'code';
117
- break;
118
- case 'implicit':
119
- kc.responseType = 'id_token token';
120
- break;
121
- case 'hybrid':
122
- kc.responseType = 'code id_token token';
123
- break;
124
- default:
125
- throw 'Invalid value for flow';
126
- }
127
- kc.flow = initOptions.flow;
128
- }
129
-
130
- if (initOptions.timeSkew != null) {
131
- kc.timeSkew = initOptions.timeSkew;
132
- }
133
-
134
- if(initOptions.redirectUri) {
135
- kc.redirectUri = initOptions.redirectUri;
136
- }
137
-
138
- if (initOptions.silentCheckSsoRedirectUri) {
139
- kc.silentCheckSsoRedirectUri = initOptions.silentCheckSsoRedirectUri;
140
- }
121
+ throw "Invalid value for responseMode";
122
+ }
123
+ }
124
+
125
+ if (initOptions.flow) {
126
+ switch (initOptions.flow) {
127
+ case "standard":
128
+ kc.responseType = "code";
129
+ break;
130
+ case "implicit":
131
+ kc.responseType = "id_token token";
132
+ break;
133
+ case "hybrid":
134
+ kc.responseType = "code id_token token";
135
+ break;
136
+ default:
137
+ throw "Invalid value for flow";
138
+ }
139
+ kc.flow = initOptions.flow;
140
+ }
141
+
142
+ if (initOptions.timeSkew != null) {
143
+ kc.timeSkew = initOptions.timeSkew;
144
+ }
145
+
146
+ if (initOptions.redirectUri) {
147
+ kc.redirectUri = initOptions.redirectUri;
148
+ }
149
+
150
+ if (initOptions.silentCheckSsoRedirectUri) {
151
+ kc.silentCheckSsoRedirectUri =
152
+ initOptions.silentCheckSsoRedirectUri;
153
+ }
154
+
155
+ if (typeof initOptions.silentCheckSsoFallback === "boolean") {
156
+ kc.silentCheckSsoFallback =
157
+ initOptions.silentCheckSsoFallback;
158
+ } else {
159
+ kc.silentCheckSsoFallback = true;
160
+ }
161
+
162
+ if (typeof initOptions.pkceMethod !== "undefined") {
163
+ if (
164
+ initOptions.pkceMethod !== "S256" &&
165
+ initOptions.pkceMethod !== false
166
+ ) {
167
+ throw new TypeError(
168
+ `Invalid value for pkceMethod', expected 'S256' or false but got ${initOptions.pkceMethod}.`
169
+ );
170
+ }
171
+
172
+ kc.pkceMethod = initOptions.pkceMethod;
173
+ } else {
174
+ kc.pkceMethod = "S256";
175
+ }
176
+
177
+ if (typeof initOptions.enableLogging === "boolean") {
178
+ kc.enableLogging = initOptions.enableLogging;
179
+ } else {
180
+ kc.enableLogging = false;
181
+ }
182
+
183
+ if (initOptions.logoutMethod === "POST") {
184
+ kc.logoutMethod = "POST";
185
+ } else {
186
+ kc.logoutMethod = "GET";
187
+ }
188
+
189
+ if (typeof initOptions.scope === "string") {
190
+ kc.scope = initOptions.scope;
191
+ }
192
+
193
+ if (typeof initOptions.acrValues === "string") {
194
+ kc.acrValues = initOptions.acrValues;
195
+ }
196
+
197
+ if (
198
+ typeof initOptions.messageReceiveTimeout === "number" &&
199
+ initOptions.messageReceiveTimeout > 0
200
+ ) {
201
+ kc.messageReceiveTimeout = initOptions.messageReceiveTimeout;
202
+ } else {
203
+ kc.messageReceiveTimeout = 10000;
204
+ }
205
+ }
141
206
 
142
- if (typeof initOptions.silentCheckSsoFallback === 'boolean') {
143
- kc.silentCheckSsoFallback = initOptions.silentCheckSsoFallback;
144
- } else {
145
- kc.silentCheckSsoFallback = true;
146
- }
207
+ if (!kc.responseMode) {
208
+ kc.responseMode = "fragment";
209
+ }
210
+ if (!kc.responseType) {
211
+ kc.responseType = "code";
212
+ kc.flow = "standard";
213
+ }
147
214
 
148
- if (initOptions.pkceMethod) {
149
- if (initOptions.pkceMethod !== "S256") {
150
- throw 'Invalid value for pkceMethod';
151
- }
152
- kc.pkceMethod = initOptions.pkceMethod;
153
- }
215
+ var promise = createPromise();
154
216
 
155
- if (typeof initOptions.enableLogging === 'boolean') {
156
- kc.enableLogging = initOptions.enableLogging;
157
- } else {
158
- kc.enableLogging = false;
159
- }
217
+ var initPromise = createPromise();
160
218
 
161
- if (typeof initOptions.scope === 'string') {
162
- kc.scope = initOptions.scope;
163
- }
219
+ initPromise.promise
220
+ .then(function () {
221
+ kc.onReady && kc.onReady(kc.authenticated);
222
+ promise.setSuccess(kc.authenticated);
223
+ })
224
+ .catch(function (error) {
225
+ promise.setError(error);
226
+ });
164
227
 
165
- if (typeof initOptions.acrValues === 'string') {
166
- kc.acrValues = initOptions.acrValues;
167
- }
228
+ var configPromise = loadConfig(config);
168
229
 
169
- if (typeof initOptions.messageReceiveTimeout === 'number' && initOptions.messageReceiveTimeout > 0) {
170
- kc.messageReceiveTimeout = initOptions.messageReceiveTimeout;
171
- } else {
172
- kc.messageReceiveTimeout = 10000;
173
- }
230
+ function onLoad() {
231
+ var doLogin = function (prompt) {
232
+ if (!prompt) {
233
+ options.prompt = "none";
174
234
  }
175
235
 
176
- if (!kc.responseMode) {
177
- kc.responseMode = 'fragment';
178
- }
179
- if (!kc.responseType) {
180
- kc.responseType = 'code';
181
- kc.flow = 'standard';
236
+ if (initOptions && initOptions.locale) {
237
+ options.locale = initOptions.locale;
182
238
  }
239
+ kc.login(options)
240
+ .then(function () {
241
+ initPromise.setSuccess();
242
+ })
243
+ .catch(function (error) {
244
+ initPromise.setError(error);
245
+ });
246
+ };
183
247
 
184
- var promise = createPromise();
248
+ var checkSsoSilently = function () {
249
+ var ifrm = document.createElement("iframe");
185
250
 
186
- var initPromise = createPromise();
187
- initPromise.promise.then(function() {
188
- kc.onReady && kc.onReady(kc.authenticated);
189
- promise.setSuccess(kc.authenticated);
190
- }).catch(function(error) {
191
- promise.setError(error);
251
+ var src = kc.createLoginUrl({
252
+ prompt: "none",
253
+ redirectUri: kc.silentCheckSsoRedirectUri,
192
254
  });
193
255
 
194
- var configPromise = loadConfig(config);
256
+ ifrm.setAttribute("src", src);
195
257
 
196
- function onLoad() {
197
- var doLogin = function(prompt) {
198
- if (!prompt) {
199
- options.prompt = 'none';
200
- }
258
+ ifrm.setAttribute(
259
+ "sandbox",
260
+ "allow-storage-access-by-user-activation allow-scripts allow-same-origin"
261
+ );
201
262
 
202
- if (initOptions && initOptions.locale) {
203
- options.locale = initOptions.locale;
204
- }
205
- kc.login(options).then(function () {
206
- initPromise.setSuccess();
207
- }).catch(function (error) {
208
- initPromise.setError(error);
209
- });
210
- }
263
+ ifrm.setAttribute("title", "keycloak-silent-check-sso");
264
+ ifrm.style.display = "none";
265
+ document.body.appendChild(ifrm);
211
266
 
212
- var checkSsoSilently = function() {
213
- var ifrm = document.createElement("iframe");
214
- var src = kc.createLoginUrl({prompt: 'none', redirectUri: kc.silentCheckSsoRedirectUri});
215
- ifrm.setAttribute("src", src);
216
- ifrm.setAttribute("sandbox", "allow-scripts allow-same-origin");
217
- ifrm.setAttribute("title", "keycloak-silent-check-sso");
218
- ifrm.style.display = "none";
219
- document.body.appendChild(ifrm);
220
-
221
- var messageCallback = function(event) {
222
- if (event.origin !== window.location.origin || ifrm.contentWindow !== event.source) {
223
- return;
224
- }
225
-
226
- var oauth = parseCallback(event.data);
227
- processCallback(oauth, initPromise);
228
-
229
- document.body.removeChild(ifrm);
230
- window.removeEventListener("message", messageCallback);
231
- };
232
-
233
- window.addEventListener("message", messageCallback);
234
- };
235
-
236
- var options = {};
237
- switch (initOptions.onLoad) {
238
- case 'check-sso':
239
- if (loginIframe.enable) {
240
- setupCheckLoginIframe().then(function() {
241
- checkLoginIframe().then(function (unchanged) {
242
- if (!unchanged) {
243
- kc.silentCheckSsoRedirectUri ? checkSsoSilently() : doLogin(false);
244
- } else {
245
- initPromise.setSuccess();
246
- }
247
- }).catch(function (error) {
248
- initPromise.setError(error);
249
- });
250
- });
251
- } else {
252
- kc.silentCheckSsoRedirectUri ? checkSsoSilently() : doLogin(false);
253
- }
254
- break;
255
- case 'login-required':
256
- doLogin(true);
257
- break;
258
- default:
259
- throw 'Invalid value for onLoad';
260
- }
261
- }
267
+ var messageCallback = function (event) {
268
+ if (
269
+ event.origin !== window.location.origin ||
270
+ ifrm.contentWindow !== event.source
271
+ ) {
272
+ return;
273
+ }
262
274
 
263
- function processInit() {
264
- var callback = parseCallback(window.location.href);
275
+ var oauth = parseCallback(event.data);
276
+ processCallback(oauth, initPromise);
265
277
 
266
- if (callback) {
267
- window.history.replaceState(window.history.state, null, callback.newUrl);
268
- }
278
+ document.body.removeChild(ifrm);
279
+ window.removeEventListener("message", messageCallback);
280
+ };
269
281
 
270
- if (callback && callback.valid) {
271
- return setupCheckLoginIframe().then(function() {
272
- processCallback(callback, initPromise);
273
- }).catch(function (error) {
274
- initPromise.setError(error);
282
+ window.addEventListener("message", messageCallback);
283
+ };
284
+
285
+ var options = {};
286
+ switch (initOptions.onLoad) {
287
+ case "check-sso":
288
+ if (loginIframe.enable) {
289
+ setupCheckLoginIframe().then(function () {
290
+ checkLoginIframe()
291
+ .then(function (unchanged) {
292
+ if (!unchanged) {
293
+ kc.silentCheckSsoRedirectUri
294
+ ? checkSsoSilently()
295
+ : doLogin(false);
296
+ } else {
297
+ initPromise.setSuccess();
298
+ }
299
+ })
300
+ .catch(function (error) {
301
+ initPromise.setError(error);
275
302
  });
276
- } else if (initOptions) {
277
- if (initOptions.token && initOptions.refreshToken) {
278
- setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken);
279
-
280
- if (loginIframe.enable) {
281
- setupCheckLoginIframe().then(function() {
282
- checkLoginIframe().then(function (unchanged) {
283
- if (unchanged) {
284
- kc.onAuthSuccess && kc.onAuthSuccess();
285
- initPromise.setSuccess();
286
- scheduleCheckIframe();
287
- } else {
288
- initPromise.setSuccess();
289
- }
290
- }).catch(function (error) {
291
- initPromise.setError(error);
292
- });
293
- });
294
- } else {
295
- kc.updateToken(-1).then(function() {
296
- kc.onAuthSuccess && kc.onAuthSuccess();
297
- initPromise.setSuccess();
298
- }).catch(function(error) {
299
- kc.onAuthError && kc.onAuthError();
300
- if (initOptions.onLoad) {
301
- onLoad();
302
- } else {
303
- initPromise.setError(error);
304
- }
305
- });
306
- }
307
- } else if (initOptions.onLoad) {
308
- onLoad();
309
- } else {
303
+ });
304
+ } else {
305
+ kc.silentCheckSsoRedirectUri
306
+ ? checkSsoSilently()
307
+ : doLogin(false);
308
+ }
309
+ break;
310
+ case "login-required":
311
+ doLogin(true);
312
+ break;
313
+ default:
314
+ throw "Invalid value for onLoad";
315
+ }
316
+ }
317
+
318
+ function processInit() {
319
+ var callback = parseCallback(window.location.href);
320
+
321
+ if (callback) {
322
+ window.history.replaceState(
323
+ window.history.state,
324
+ null,
325
+ callback.newUrl
326
+ );
327
+ }
328
+
329
+ if (callback && callback.valid) {
330
+ return setupCheckLoginIframe()
331
+ .then(function () {
332
+ processCallback(callback, initPromise);
333
+ })
334
+ .catch(function (error) {
335
+ initPromise.setError(error);
336
+ });
337
+ } else if (initOptions) {
338
+ if (initOptions.token && initOptions.refreshToken) {
339
+ setToken(
340
+ initOptions.token,
341
+ initOptions.refreshToken,
342
+ initOptions.idToken
343
+ );
344
+
345
+ if (loginIframe.enable) {
346
+ setupCheckLoginIframe().then(function () {
347
+ checkLoginIframe()
348
+ .then(function (unchanged) {
349
+ if (unchanged) {
350
+ kc.onAuthSuccess && kc.onAuthSuccess();
310
351
  initPromise.setSuccess();
311
- }
312
- } else {
352
+ scheduleCheckIframe();
353
+ } else {
354
+ initPromise.setSuccess();
355
+ }
356
+ })
357
+ .catch(function (error) {
358
+ initPromise.setError(error);
359
+ });
360
+ });
361
+ } else {
362
+ kc.updateToken(-1)
363
+ .then(function () {
364
+ kc.onAuthSuccess && kc.onAuthSuccess();
313
365
  initPromise.setSuccess();
314
- }
366
+ })
367
+ .catch(function (error) {
368
+ kc.onAuthError && kc.onAuthError();
369
+ if (initOptions.onLoad) {
370
+ onLoad();
371
+ } else {
372
+ initPromise.setError(error);
373
+ }
374
+ });
375
+ }
376
+ } else if (initOptions.onLoad) {
377
+ onLoad();
378
+ } else {
379
+ initPromise.setSuccess();
315
380
  }
381
+ } else {
382
+ initPromise.setSuccess();
383
+ }
384
+ }
316
385
 
317
- function domReady() {
318
- var promise = createPromise();
319
-
320
- var checkReadyState = function () {
321
- if (document.readyState === 'interactive' || document.readyState === 'complete') {
322
- document.removeEventListener('readystatechange', checkReadyState);
323
- promise.setSuccess();
324
- }
325
- }
326
- document.addEventListener('readystatechange', checkReadyState);
386
+ function domReady() {
387
+ var promise = createPromise();
327
388
 
328
- checkReadyState(); // just in case the event was already fired and we missed it (in case the init is done later than at the load time, i.e. it's done from code)
389
+ var checkReadyState = function () {
390
+ if (
391
+ document.readyState === "interactive" ||
392
+ document.readyState === "complete"
393
+ ) {
394
+ document.removeEventListener(
395
+ "readystatechange",
396
+ checkReadyState
397
+ );
329
398
 
330
- return promise.promise;
399
+ promise.setSuccess();
331
400
  }
401
+ };
332
402
 
333
- configPromise.then(function () {
334
- domReady()
335
- .then(check3pCookiesSupported)
336
- .then(processInit)
337
- .catch(function (error) {
338
- promise.setError(error);
339
- });
340
- });
341
- configPromise.catch(function (error) {
342
- promise.setError(error);
343
- });
403
+ document.addEventListener("readystatechange", checkReadyState);
344
404
 
345
- return promise.promise;
346
- }
405
+ checkReadyState(); // just in case the event was already fired and we missed it (in case the init is done later than at the load time, i.e. it's done from code)
347
406
 
348
- kc.login = function (options) {
349
- return adapter.login(options);
407
+ return promise.promise;
350
408
  }
351
409
 
352
- function generateRandomData(len) {
353
- // use web crypto APIs if possible
354
- var array = null;
355
- var crypto = window.crypto || window.msCrypto;
356
- if (crypto && crypto.getRandomValues && window.Uint8Array) {
357
- array = new Uint8Array(len);
358
- crypto.getRandomValues(array);
359
- return array;
360
- }
361
-
362
- // fallback to Math random
363
- array = new Array(len);
364
- for (var j = 0; j < array.length; j++) {
365
- array[j] = Math.floor(256 * Math.random());
366
- }
367
- return array;
410
+ configPromise.then(function () {
411
+ domReady()
412
+ .then(check3pCookiesSupported)
413
+ .then(processInit)
414
+ .catch(function (error) {
415
+ promise.setError(error);
416
+ });
417
+ });
418
+ configPromise.catch(function (error) {
419
+ promise.setError(error);
420
+ });
421
+
422
+ return promise.promise;
423
+ };
424
+
425
+ kc.login = function (options) {
426
+ return adapter.login(options);
427
+ };
428
+
429
+ function generateRandomData(len) {
430
+ // use web crypto APIs if possible
431
+ var array = null;
432
+ var crypto = window.crypto || window.msCrypto;
433
+ if (crypto && crypto.getRandomValues && window.Uint8Array) {
434
+ array = new Uint8Array(len);
435
+ crypto.getRandomValues(array);
436
+ return array;
368
437
  }
369
438
 
370
- function generateCodeVerifier(len) {
371
- return generateRandomString(len, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789');
439
+ // fallback to Math random
440
+ array = new Array(len);
441
+ for (var j = 0; j < array.length; j++) {
442
+ array[j] = Math.floor(256 * Math.random());
372
443
  }
373
-
374
- function generateRandomString(len, alphabet){
375
- var randomData = generateRandomData(len);
376
- var chars = new Array(len);
377
- for (var i = 0; i < len; i++) {
378
- chars[i] = alphabet.charCodeAt(randomData[i] % alphabet.length);
379
- }
380
- return String.fromCharCode.apply(null, chars);
381
- }
382
-
383
- function generatePkceChallenge(pkceMethod, codeVerifier) {
384
- switch (pkceMethod) {
385
- // The use of the "plain" method is considered insecure and therefore not supported.
386
- case "S256":
387
- // hash codeVerifier, then encode as url-safe base64 without padding
388
- var hashBytes = new Uint8Array(sha256.arrayBuffer(codeVerifier));
389
- var encodedHash = base64.fromByteArray(hashBytes)
390
- .replace(/\+/g, '-')
391
- .replace(/\//g, '_')
392
- .replace(/\=/g, '');
393
- return encodedHash;
394
- default:
395
- throw 'Invalid value for pkceMethod';
396
- }
444
+ return array;
445
+ }
446
+
447
+ function generateCodeVerifier(len) {
448
+ return generateRandomString(
449
+ len,
450
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
451
+ );
452
+ }
453
+
454
+ function generateRandomString(len, alphabet) {
455
+ var randomData = generateRandomData(len);
456
+ var chars = new Array(len);
457
+ for (var i = 0; i < len; i++) {
458
+ chars[i] = alphabet.charCodeAt(randomData[i] % alphabet.length);
397
459
  }
398
-
399
- function buildClaimsParameter(requestedAcr){
400
- var claims = {
401
- id_token: {
402
- acr: requestedAcr
403
- }
404
- }
405
- return JSON.stringify(claims);
460
+ return String.fromCharCode.apply(null, chars);
461
+ }
462
+
463
+ function generatePkceChallenge(pkceMethod, codeVerifier) {
464
+ if (pkceMethod !== "S256") {
465
+ throw new TypeError(
466
+ `Invalid value for 'pkceMethod', expected 'S256' but got '${pkceMethod}'.`
467
+ );
406
468
  }
407
469
 
408
- kc.createLoginUrl = function(options) {
409
- var state = createUUID();
410
- var nonce = createUUID();
411
-
412
- var redirectUri = adapter.redirectUri(options);
413
-
414
- var callbackState = {
415
- state: state,
416
- nonce: nonce,
417
- redirectUri: encodeURIComponent(redirectUri)
418
- };
419
-
420
- if (options && options.prompt) {
421
- callbackState.prompt = options.prompt;
422
- }
423
-
424
- var baseUrl;
425
- if (options && options.action == 'register') {
426
- baseUrl = kc.endpoints.register();
427
- } else {
428
- baseUrl = kc.endpoints.authorize();
429
- }
430
-
431
- var scope = options && options.scope || kc.scope;
432
- if (!scope) {
433
- // if scope is not set, default to "openid"
434
- scope = "openid";
435
- } else if (scope.indexOf("openid") === -1) {
436
- // if openid scope is missing, prefix the given scopes with it
437
- scope = "openid " + scope;
438
- }
439
-
440
- var url = baseUrl
441
- + '?client_id=' + encodeURIComponent(kc.clientId)
442
- + '&redirect_uri=' + encodeURIComponent(redirectUri)
443
- + '&state=' + encodeURIComponent(state)
444
- + '&response_mode=' + encodeURIComponent(kc.responseMode)
445
- + '&response_type=' + encodeURIComponent(kc.responseType)
446
- + '&scope=' + encodeURIComponent(scope);
447
- if (useNonce) {
448
- url = url + '&nonce=' + encodeURIComponent(nonce);
449
- }
450
-
451
- if (options && options.prompt) {
452
- url += '&prompt=' + encodeURIComponent(options.prompt);
453
- }
454
-
455
- if (options && options.maxAge) {
456
- url += '&max_age=' + encodeURIComponent(options.maxAge);
457
- }
458
-
459
- if (options && options.loginHint) {
460
- url += '&login_hint=' + encodeURIComponent(options.loginHint);
461
- }
462
-
463
- if (options && options.idpHint) {
464
- url += '&kc_idp_hint=' + encodeURIComponent(options.idpHint);
465
- }
466
-
467
- if (options && options.action && options.action != 'register') {
468
- url += '&kc_action=' + encodeURIComponent(options.action);
469
- }
470
-
471
- if (options && options.locale) {
472
- url += '&ui_locales=' + encodeURIComponent(options.locale);
473
- }
474
-
475
- if (options && options.acr) {
476
- var claimsParameter = buildClaimsParameter(options.acr);
477
- url += '&claims=' + encodeURIComponent(claimsParameter);
478
- }
470
+ // hash codeVerifier, then encode as url-safe base64 without padding
471
+ const hashBytes = sha256(codeVerifier);
472
+ const encodedHash = bytesToBase64(hashBytes)
473
+ .replace(/\+/g, "-")
474
+ .replace(/\//g, "_")
475
+ .replace(/\=/g, "");
476
+
477
+ return encodedHash;
478
+ }
479
+
480
+ function buildClaimsParameter(requestedAcr) {
481
+ var claims = {
482
+ id_token: {
483
+ acr: requestedAcr,
484
+ },
485
+ };
486
+ return JSON.stringify(claims);
487
+ }
479
488
 
480
- if ((options && options.acrValues) || kc.acrValues) {
481
- url += '&acr_values=' + encodeURIComponent(options.acrValues || kc.acrValues);
482
- }
489
+ kc.createLoginUrl = function (options) {
490
+ var state = createUUID();
491
+ var nonce = createUUID();
483
492
 
484
- if (kc.pkceMethod) {
485
- var codeVerifier = generateCodeVerifier(96);
486
- callbackState.pkceCodeVerifier = codeVerifier;
487
- var pkceChallenge = generatePkceChallenge(kc.pkceMethod, codeVerifier);
488
- url += '&code_challenge=' + pkceChallenge;
489
- url += '&code_challenge_method=' + kc.pkceMethod;
490
- }
493
+ var redirectUri = adapter.redirectUri(options);
491
494
 
492
- callbackStorage.add(callbackState);
495
+ var callbackState = {
496
+ state: state,
497
+ nonce: nonce,
498
+ redirectUri: encodeURIComponent(redirectUri),
499
+ loginOptions: options,
500
+ };
493
501
 
494
- return url;
502
+ if (options && options.prompt) {
503
+ callbackState.prompt = options.prompt;
495
504
  }
496
505
 
497
- kc.logout = function(options) {
498
- return adapter.logout(options);
506
+ var baseUrl;
507
+ if (options && options.action == "register") {
508
+ baseUrl = kc.endpoints.register();
509
+ } else {
510
+ baseUrl = kc.endpoints.authorize();
499
511
  }
500
512
 
501
- kc.createLogoutUrl = function(options) {
502
- var url = kc.endpoints.logout()
503
- + '?client_id=' + encodeURIComponent(kc.clientId)
504
- + '&post_logout_redirect_uri=' + encodeURIComponent(adapter.redirectUri(options, false));
505
-
506
- if (kc.idToken) {
507
- url += '&id_token_hint=' + encodeURIComponent(kc.idToken);
508
- }
509
-
510
- return url;
513
+ var scope = (options && options.scope) || kc.scope;
514
+ if (!scope) {
515
+ // if scope is not set, default to "openid"
516
+ scope = "openid";
517
+ } else if (scope.indexOf("openid") === -1) {
518
+ // if openid scope is missing, prefix the given scopes with it
519
+ scope = "openid " + scope;
511
520
  }
512
521
 
513
- kc.register = function (options) {
514
- return adapter.register(options);
522
+ var url =
523
+ baseUrl +
524
+ "?client_id=" +
525
+ encodeURIComponent(kc.clientId) +
526
+ "&redirect_uri=" +
527
+ encodeURIComponent(redirectUri) +
528
+ "&state=" +
529
+ encodeURIComponent(state) +
530
+ "&response_mode=" +
531
+ encodeURIComponent(kc.responseMode) +
532
+ "&response_type=" +
533
+ encodeURIComponent(kc.responseType) +
534
+ "&scope=" +
535
+ encodeURIComponent(scope);
536
+ if (useNonce) {
537
+ url = url + "&nonce=" + encodeURIComponent(nonce);
515
538
  }
516
539
 
517
- kc.createRegisterUrl = function(options) {
518
- if (!options) {
519
- options = {};
520
- }
521
- options.action = 'register';
522
- return kc.createLoginUrl(options);
523
- }
524
-
525
- kc.createAccountUrl = function(options) {
526
- var realm = getRealmUrl();
527
- var url = undefined;
528
- if (typeof realm !== 'undefined') {
529
- url = realm
530
- + '/account'
531
- + '?referrer=' + encodeURIComponent(kc.clientId)
532
- + '&referrer_uri=' + encodeURIComponent(adapter.redirectUri(options));
533
- }
534
- return url;
540
+ if (options && options.prompt) {
541
+ url += "&prompt=" + encodeURIComponent(options.prompt);
535
542
  }
536
543
 
537
- kc.accountManagement = function() {
538
- return adapter.accountManagement();
544
+ if (options && options.maxAge) {
545
+ url += "&max_age=" + encodeURIComponent(options.maxAge);
539
546
  }
540
547
 
541
- kc.hasRealmRole = function (role) {
542
- var access = kc.realmAccess;
543
- return !!access && access.roles.indexOf(role) >= 0;
548
+ if (options && options.loginHint) {
549
+ url += "&login_hint=" + encodeURIComponent(options.loginHint);
544
550
  }
545
551
 
546
- kc.hasResourceRole = function(role, resource) {
547
- if (!kc.resourceAccess) {
548
- return false;
549
- }
552
+ if (options && options.idpHint) {
553
+ url += "&kc_idp_hint=" + encodeURIComponent(options.idpHint);
554
+ }
550
555
 
551
- var access = kc.resourceAccess[resource || kc.clientId];
552
- return !!access && access.roles.indexOf(role) >= 0;
556
+ if (options && options.action && options.action != "register") {
557
+ url += "&kc_action=" + encodeURIComponent(options.action);
553
558
  }
554
559
 
555
- kc.loadUserProfile = function() {
556
- var url = getRealmUrl() + '/account';
557
- var req = new XMLHttpRequest();
558
- req.open('GET', url, true);
559
- req.setRequestHeader('Accept', 'application/json');
560
- req.setRequestHeader('Authorization', 'bearer ' + kc.token);
560
+ if (options && options.locale) {
561
+ url += "&ui_locales=" + encodeURIComponent(options.locale);
562
+ }
561
563
 
562
- var promise = createPromise();
564
+ if (options && options.acr) {
565
+ var claimsParameter = buildClaimsParameter(options.acr);
566
+ url += "&claims=" + encodeURIComponent(claimsParameter);
567
+ }
563
568
 
564
- req.onreadystatechange = function () {
565
- if (req.readyState == 4) {
566
- if (req.status == 200) {
567
- kc.profile = JSON.parse(req.responseText);
568
- promise.setSuccess(kc.profile);
569
- } else {
570
- promise.setError();
571
- }
572
- }
573
- }
569
+ if ((options && options.acrValues) || kc.acrValues) {
570
+ url +=
571
+ "&acr_values=" +
572
+ encodeURIComponent(options.acrValues || kc.acrValues);
573
+ }
574
574
 
575
- req.send();
575
+ if (kc.pkceMethod) {
576
+ var codeVerifier = generateCodeVerifier(96);
577
+ callbackState.pkceCodeVerifier = codeVerifier;
578
+ var pkceChallenge = generatePkceChallenge(
579
+ kc.pkceMethod,
580
+ codeVerifier
581
+ );
576
582
 
577
- return promise.promise;
583
+ url += "&code_challenge=" + pkceChallenge;
584
+ url += "&code_challenge_method=" + kc.pkceMethod;
578
585
  }
579
586
 
580
- kc.loadUserInfo = function() {
581
- var url = kc.endpoints.userinfo();
582
- var req = new XMLHttpRequest();
583
- req.open('GET', url, true);
584
- req.setRequestHeader('Accept', 'application/json');
585
- req.setRequestHeader('Authorization', 'bearer ' + kc.token);
587
+ callbackStorage.add(callbackState);
586
588
 
587
- var promise = createPromise();
589
+ return url;
590
+ };
588
591
 
589
- req.onreadystatechange = function () {
590
- if (req.readyState == 4) {
591
- if (req.status == 200) {
592
- kc.userInfo = JSON.parse(req.responseText);
593
- promise.setSuccess(kc.userInfo);
594
- } else {
595
- promise.setError();
596
- }
597
- }
598
- }
599
-
600
- req.send();
592
+ kc.logout = function (options) {
593
+ return adapter.logout(options);
594
+ };
601
595
 
602
- return promise.promise;
596
+ kc.createLogoutUrl = function (options) {
597
+ const logoutMethod = options?.logoutMethod ?? kc.logoutMethod;
598
+ if (logoutMethod === "POST") {
599
+ return kc.endpoints.logout();
603
600
  }
604
601
 
605
- kc.isTokenExpired = function(minValidity) {
606
- if (!kc.tokenParsed || (!kc.refreshToken && kc.flow != 'implicit' )) {
607
- throw 'Not authenticated';
608
- }
609
-
610
- if (kc.timeSkew == null) {
611
- logInfo('[KEYCLOAK] Unable to determine if token is expired as timeskew is not set');
612
- return true;
613
- }
602
+ var url =
603
+ kc.endpoints.logout() +
604
+ "?client_id=" +
605
+ encodeURIComponent(kc.clientId) +
606
+ "&post_logout_redirect_uri=" +
607
+ encodeURIComponent(adapter.redirectUri(options, false));
614
608
 
615
- var expiresIn = kc.tokenParsed['exp'] - Math.ceil(new Date().getTime() / 1000) + kc.timeSkew;
616
- if (minValidity) {
617
- if (isNaN(minValidity)) {
618
- throw 'Invalid minValidity';
619
- }
620
- expiresIn -= minValidity;
621
- }
622
- return expiresIn < 0;
609
+ if (kc.idToken) {
610
+ url += "&id_token_hint=" + encodeURIComponent(kc.idToken);
623
611
  }
624
612
 
625
- kc.updateToken = function(minValidity) {
626
- var promise = createPromise();
627
-
628
- if (!kc.refreshToken) {
629
- promise.setError();
630
- return promise.promise;
631
- }
632
-
633
- minValidity = minValidity || 5;
613
+ return url;
614
+ };
634
615
 
635
- var exec = function() {
636
- var refreshToken = false;
637
- if (minValidity == -1) {
638
- refreshToken = true;
639
- logInfo('[KEYCLOAK] Refreshing token: forced refresh');
640
- } else if (!kc.tokenParsed || kc.isTokenExpired(minValidity)) {
641
- refreshToken = true;
642
- logInfo('[KEYCLOAK] Refreshing token: token expired');
643
- }
644
-
645
- if (!refreshToken) {
646
- promise.setSuccess(false);
647
- } else {
648
- var params = 'grant_type=refresh_token&' + 'refresh_token=' + kc.refreshToken;
649
- var url = kc.endpoints.token();
616
+ kc.register = function (options) {
617
+ return adapter.register(options);
618
+ };
650
619
 
651
- refreshQueue.push(promise);
620
+ kc.createRegisterUrl = function (options) {
621
+ if (!options) {
622
+ options = {};
623
+ }
624
+ options.action = "register";
625
+ return kc.createLoginUrl(options);
626
+ };
627
+
628
+ kc.createAccountUrl = function (options) {
629
+ var realm = getRealmUrl();
630
+ var url = undefined;
631
+ if (typeof realm !== "undefined") {
632
+ url =
633
+ realm +
634
+ "/account" +
635
+ "?referrer=" +
636
+ encodeURIComponent(kc.clientId) +
637
+ "&referrer_uri=" +
638
+ encodeURIComponent(adapter.redirectUri(options));
639
+ }
640
+ return url;
641
+ };
652
642
 
653
- if (refreshQueue.length == 1) {
654
- var req = new XMLHttpRequest();
655
- req.open('POST', url, true);
656
- req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
657
- req.withCredentials = true;
643
+ kc.accountManagement = function () {
644
+ return adapter.accountManagement();
645
+ };
658
646
 
659
- params += '&client_id=' + encodeURIComponent(kc.clientId);
647
+ kc.hasRealmRole = function (role) {
648
+ var access = kc.realmAccess;
649
+ return !!access && access.roles.indexOf(role) >= 0;
650
+ };
660
651
 
661
- var timeLocal = new Date().getTime();
652
+ kc.hasResourceRole = function (role, resource) {
653
+ if (!kc.resourceAccess) {
654
+ return false;
655
+ }
662
656
 
663
- req.onreadystatechange = function () {
664
- if (req.readyState == 4) {
665
- if (req.status == 200) {
666
- logInfo('[KEYCLOAK] Token refreshed');
657
+ var access = kc.resourceAccess[resource || kc.clientId];
658
+ return !!access && access.roles.indexOf(role) >= 0;
659
+ };
667
660
 
668
- timeLocal = (timeLocal + new Date().getTime()) / 2;
661
+ kc.loadUserProfile = function () {
662
+ var url = getRealmUrl() + "/account";
663
+ var req = new XMLHttpRequest();
664
+ req.open("GET", url, true);
665
+ req.setRequestHeader("Accept", "application/json");
666
+ req.setRequestHeader("Authorization", "bearer " + kc.token);
669
667
 
670
- var tokenResponse = JSON.parse(req.responseText);
668
+ var promise = createPromise();
671
669
 
672
- setToken(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token'], timeLocal);
670
+ req.onreadystatechange = function () {
671
+ if (req.readyState == 4) {
672
+ if (req.status == 200) {
673
+ kc.profile = JSON.parse(req.responseText);
674
+ promise.setSuccess(kc.profile);
675
+ } else {
676
+ promise.setError();
677
+ }
678
+ }
679
+ };
673
680
 
674
- kc.onAuthRefreshSuccess && kc.onAuthRefreshSuccess();
675
- for (var p = refreshQueue.pop(); p != null; p = refreshQueue.pop()) {
676
- p.setSuccess(true);
677
- }
678
- } else {
679
- logWarn('[KEYCLOAK] Failed to refresh token');
681
+ req.send();
680
682
 
681
- if (req.status == 400) {
682
- kc.clearToken();
683
- }
683
+ return promise.promise;
684
+ };
684
685
 
685
- kc.onAuthRefreshError && kc.onAuthRefreshError();
686
- for (var p = refreshQueue.pop(); p != null; p = refreshQueue.pop()) {
687
- p.setError(true);
688
- }
689
- }
690
- }
691
- };
686
+ kc.loadUserInfo = function () {
687
+ var url = kc.endpoints.userinfo();
688
+ var req = new XMLHttpRequest();
689
+ req.open("GET", url, true);
690
+ req.setRequestHeader("Accept", "application/json");
691
+ req.setRequestHeader("Authorization", "bearer " + kc.token);
692
692
 
693
- req.send(params);
694
- }
695
- }
696
- }
693
+ var promise = createPromise();
697
694
 
698
- if (loginIframe.enable) {
699
- var iframePromise = checkLoginIframe();
700
- iframePromise.then(function() {
701
- exec();
702
- }).catch(function(error) {
703
- promise.setError(error);
704
- });
695
+ req.onreadystatechange = function () {
696
+ if (req.readyState == 4) {
697
+ if (req.status == 200) {
698
+ kc.userInfo = JSON.parse(req.responseText);
699
+ promise.setSuccess(kc.userInfo);
705
700
  } else {
706
- exec();
701
+ promise.setError();
707
702
  }
703
+ }
704
+ };
708
705
 
709
- return promise.promise;
710
- }
711
-
712
- kc.clearToken = function() {
713
- if (kc.token) {
714
- setToken(null, null, null);
715
- kc.onAuthLogout && kc.onAuthLogout();
716
- if (kc.loginRequired) {
717
- kc.login();
718
- }
719
- }
720
- }
706
+ req.send();
721
707
 
722
- kc.setToken = setToken;
708
+ return promise.promise;
709
+ };
723
710
 
724
- function getRealmUrl() {
725
- if (typeof kc.authServerUrl !== 'undefined') {
726
- if (kc.authServerUrl.charAt(kc.authServerUrl.length - 1) == '/') {
727
- return kc.authServerUrl + 'realms/' + encodeURIComponent(kc.realm);
728
- } else {
729
- return kc.authServerUrl + '/realms/' + encodeURIComponent(kc.realm);
730
- }
731
- } else {
732
- return undefined;
733
- }
711
+ kc.isTokenExpired = function (minValidity) {
712
+ if (
713
+ !kc.tokenParsed ||
714
+ (!kc.refreshToken && kc.flow != "implicit")
715
+ ) {
716
+ throw "Not authenticated";
734
717
  }
735
718
 
736
- function getOrigin() {
737
- if (!window.location.origin) {
738
- return window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
739
- } else {
740
- return window.location.origin;
741
- }
719
+ if (kc.timeSkew == null) {
720
+ logInfo(
721
+ "[KEYCLOAK] Unable to determine if token is expired as timeskew is not set"
722
+ );
723
+
724
+ return true;
742
725
  }
743
726
 
744
- function processCallback(oauth, promise) {
745
- var code = oauth.code;
746
- var error = oauth.error;
747
- var prompt = oauth.prompt;
727
+ var expiresIn =
728
+ kc.tokenParsed["exp"] -
729
+ Math.ceil(new Date().getTime() / 1000) +
730
+ kc.timeSkew;
748
731
 
749
- var timeLocal = new Date().getTime();
732
+ if (minValidity) {
733
+ if (isNaN(minValidity)) {
734
+ throw "Invalid minValidity";
735
+ }
736
+ expiresIn -= minValidity;
737
+ }
738
+ return expiresIn < 0;
739
+ };
750
740
 
751
- if (oauth['kc_action_status']) {
752
- kc.onActionUpdate && kc.onActionUpdate(oauth['kc_action_status']);
753
- }
741
+ kc.updateToken = function (minValidity) {
742
+ var promise = createPromise();
754
743
 
755
- if (error) {
756
- if (prompt != 'none') {
757
- var errorData = { error: error, error_description: oauth.error_description };
758
- kc.onAuthError && kc.onAuthError(errorData);
759
- promise && promise.setError(errorData);
760
- } else {
761
- promise && promise.setSuccess();
762
- }
763
- return;
764
- } else if ((kc.flow != 'standard') && (oauth.access_token || oauth.id_token)) {
765
- authSuccess(oauth.access_token, null, oauth.id_token, true);
766
- }
744
+ if (!kc.refreshToken) {
745
+ promise.setError();
746
+ return promise.promise;
747
+ }
767
748
 
768
- if ((kc.flow != 'implicit') && code) {
769
- var params = 'code=' + code + '&grant_type=authorization_code';
770
- var url = kc.endpoints.token();
749
+ minValidity = minValidity || 5;
771
750
 
772
- var req = new XMLHttpRequest();
773
- req.open('POST', url, true);
774
- req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
751
+ var exec = function () {
752
+ var refreshToken = false;
753
+ if (minValidity == -1) {
754
+ refreshToken = true;
755
+ logInfo("[KEYCLOAK] Refreshing token: forced refresh");
756
+ } else if (!kc.tokenParsed || kc.isTokenExpired(minValidity)) {
757
+ refreshToken = true;
758
+ logInfo("[KEYCLOAK] Refreshing token: token expired");
759
+ }
775
760
 
776
- params += '&client_id=' + encodeURIComponent(kc.clientId);
777
- params += '&redirect_uri=' + oauth.redirectUri;
761
+ if (!refreshToken) {
762
+ promise.setSuccess(false);
763
+ } else {
764
+ var params =
765
+ "grant_type=refresh_token&" +
766
+ "refresh_token=" +
767
+ kc.refreshToken;
778
768
 
779
- if (oauth.pkceCodeVerifier) {
780
- params += '&code_verifier=' + oauth.pkceCodeVerifier;
781
- }
769
+ var url = kc.endpoints.token();
782
770
 
783
- req.withCredentials = true;
771
+ refreshQueue.push(promise);
784
772
 
785
- req.onreadystatechange = function() {
786
- if (req.readyState == 4) {
787
- if (req.status == 200) {
773
+ if (refreshQueue.length == 1) {
774
+ var req = new XMLHttpRequest();
775
+ req.open("POST", url, true);
788
776
 
789
- var tokenResponse = JSON.parse(req.responseText);
790
- authSuccess(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token'], kc.flow === 'standard');
791
- scheduleCheckIframe();
792
- } else {
793
- kc.onAuthError && kc.onAuthError();
794
- promise && promise.setError();
795
- }
796
- }
797
- };
777
+ req.setRequestHeader(
778
+ "Content-type",
779
+ "application/x-www-form-urlencoded"
780
+ );
798
781
 
799
- req.send(params);
800
- }
782
+ req.withCredentials = true;
801
783
 
802
- function authSuccess(accessToken, refreshToken, idToken, fulfillPromise) {
803
- timeLocal = (timeLocal + new Date().getTime()) / 2;
784
+ params += "&client_id=" + encodeURIComponent(kc.clientId);
804
785
 
805
- setToken(accessToken, refreshToken, idToken, timeLocal);
786
+ var timeLocal = new Date().getTime();
806
787
 
807
- if (useNonce && ((kc.tokenParsed && kc.tokenParsed.nonce != oauth.storedNonce) ||
808
- (kc.refreshTokenParsed && kc.refreshTokenParsed.nonce != oauth.storedNonce) ||
809
- (kc.idTokenParsed && kc.idTokenParsed.nonce != oauth.storedNonce))) {
788
+ req.onreadystatechange = function () {
789
+ if (req.readyState == 4) {
790
+ if (req.status == 200) {
791
+ logInfo("[KEYCLOAK] Token refreshed");
810
792
 
811
- logInfo('[KEYCLOAK] Invalid nonce, clearing token');
812
- kc.clearToken();
813
- promise && promise.setError();
814
- } else {
815
- if (fulfillPromise) {
816
- kc.onAuthSuccess && kc.onAuthSuccess();
817
- promise && promise.setSuccess();
818
- }
819
- }
820
- }
793
+ timeLocal = (timeLocal + new Date().getTime()) / 2;
821
794
 
822
- }
795
+ var tokenResponse = JSON.parse(req.responseText);
823
796
 
824
- function loadConfig(url) {
825
- var promise = createPromise();
826
- var configUrl;
797
+ setToken(
798
+ tokenResponse["access_token"],
799
+ tokenResponse["refresh_token"],
800
+ tokenResponse["id_token"],
801
+ timeLocal
802
+ );
827
803
 
828
- if (!config) {
829
- configUrl = location.origin + '/keycloak.json';
830
- } else if (typeof config === 'string') {
831
- configUrl = config;
832
- }
804
+ kc.onAuthRefreshSuccess && kc.onAuthRefreshSuccess();
833
805
 
834
- function setupOidcEndoints(oidcConfiguration) {
835
- if (! oidcConfiguration) {
836
- kc.endpoints = {
837
- authorize: function() {
838
- return getRealmUrl() + '/protocol/openid-connect/auth';
839
- },
840
- token: function() {
841
- return getRealmUrl() + '/protocol/openid-connect/token';
842
- },
843
- logout: function() {
844
- return getRealmUrl() + '/protocol/openid-connect/logout';
845
- },
846
- checkSessionIframe: function() {
847
- var src = getRealmUrl() + '/protocol/openid-connect/login-status-iframe.html';
848
- if (kc.iframeVersion) {
849
- src = src + '?version=' + kc.iframeVersion;
850
- }
851
- return src;
852
- },
853
- thirdPartyCookiesIframe: function() {
854
- var src = getRealmUrl() + '/protocol/openid-connect/3p-cookies/step1.html';
855
- if (kc.iframeVersion) {
856
- src = src + '?version=' + kc.iframeVersion;
857
- }
858
- return src;
859
- },
860
- register: function() {
861
- return getRealmUrl() + '/protocol/openid-connect/registrations';
862
- },
863
- userinfo: function() {
864
- return getRealmUrl() + '/protocol/openid-connect/userinfo';
865
- }
866
- };
867
- } else {
868
- kc.endpoints = {
869
- authorize: function() {
870
- return oidcConfiguration.authorization_endpoint;
871
- },
872
- token: function() {
873
- return oidcConfiguration.token_endpoint;
874
- },
875
- logout: function() {
876
- if (!oidcConfiguration.end_session_endpoint) {
877
- throw "Not supported by the OIDC server";
878
- }
879
- return oidcConfiguration.end_session_endpoint;
880
- },
881
- checkSessionIframe: function() {
882
- if (!oidcConfiguration.check_session_iframe) {
883
- throw "Not supported by the OIDC server";
884
- }
885
- return oidcConfiguration.check_session_iframe;
886
- },
887
- register: function() {
888
- throw 'Redirection to "Register user" page not supported in standard OIDC mode';
889
- },
890
- userinfo: function() {
891
- if (!oidcConfiguration.userinfo_endpoint) {
892
- throw "Not supported by the OIDC server";
893
- }
894
- return oidcConfiguration.userinfo_endpoint;
895
- }
806
+ for (
807
+ var p = refreshQueue.pop();
808
+ p != null;
809
+ p = refreshQueue.pop()
810
+ ) {
811
+ p.setSuccess(true);
896
812
  }
897
- }
898
- }
813
+ } else {
814
+ logWarn("[KEYCLOAK] Failed to refresh token");
899
815
 
900
- if (configUrl) {
901
- var req = new XMLHttpRequest();
902
- req.open('GET', configUrl, true);
903
- req.setRequestHeader('Accept', 'application/json');
904
-
905
- req.onreadystatechange = function () {
906
- if (req.readyState == 4) {
907
- if (req.status == 200 || fileLoaded(req)) {
908
- var config = JSON.parse(req.responseText);
909
-
910
- kc.authServerUrl = config['auth-server-url'];
911
- kc.realm = config['realm'];
912
- kc.clientId = config['resource'];
913
- setupOidcEndoints(null);
914
- promise.setSuccess();
915
- } else {
916
- promise.setError();
917
- }
816
+ if (req.status == 400) {
817
+ kc.clearToken();
918
818
  }
919
- };
920
-
921
- req.send();
922
- } else {
923
- if (!config.clientId) {
924
- throw 'clientId missing';
925
- }
926
819
 
927
- kc.clientId = config.clientId;
928
-
929
- var oidcProvider = config['oidcProvider'];
930
- if (!oidcProvider) {
931
- if (!config['url']) {
932
- var scripts = document.getElementsByTagName('script');
933
- for (var i = 0; i < scripts.length; i++) {
934
- if (scripts[i].src.match(/.*keycloak\.js/)) {
935
- config.url = scripts[i].src.substr(0, scripts[i].src.indexOf('/js/keycloak.js'));
936
- break;
937
- }
938
- }
939
- }
940
- if (!config.realm) {
941
- throw 'realm missing';
942
- }
820
+ kc.onAuthRefreshError && kc.onAuthRefreshError();
943
821
 
944
- kc.authServerUrl = config.url;
945
- kc.realm = config.realm;
946
- setupOidcEndoints(null);
947
- promise.setSuccess();
948
- } else {
949
- if (typeof oidcProvider === 'string') {
950
- var oidcProviderConfigUrl;
951
- if (oidcProvider.charAt(oidcProvider.length - 1) == '/') {
952
- oidcProviderConfigUrl = oidcProvider + '.well-known/openid-configuration';
953
- } else {
954
- oidcProviderConfigUrl = oidcProvider + '/.well-known/openid-configuration';
955
- }
956
- var req = new XMLHttpRequest();
957
- req.open('GET', oidcProviderConfigUrl, true);
958
- req.setRequestHeader('Accept', 'application/json');
959
-
960
- req.onreadystatechange = function () {
961
- if (req.readyState == 4) {
962
- if (req.status == 200 || fileLoaded(req)) {
963
- var oidcProviderConfig = JSON.parse(req.responseText);
964
- setupOidcEndoints(oidcProviderConfig);
965
- promise.setSuccess();
966
- } else {
967
- promise.setError();
968
- }
969
- }
970
- };
971
-
972
- req.send();
973
- } else {
974
- setupOidcEndoints(oidcProvider);
975
- promise.setSuccess();
822
+ for (
823
+ var p = refreshQueue.pop();
824
+ p != null;
825
+ p = refreshQueue.pop()
826
+ ) {
827
+ p.setError(true);
976
828
  }
829
+ }
977
830
  }
831
+ };
832
+
833
+ req.send(params);
978
834
  }
835
+ }
836
+ };
979
837
 
980
- return promise.promise;
838
+ if (loginIframe.enable) {
839
+ var iframePromise = checkLoginIframe();
840
+ iframePromise
841
+ .then(function () {
842
+ exec();
843
+ })
844
+ .catch(function (error) {
845
+ promise.setError(error);
846
+ });
847
+ } else {
848
+ exec();
981
849
  }
982
850
 
983
- function fileLoaded(xhr) {
984
- return xhr.status == 0 && xhr.responseText && xhr.responseURL.startsWith('file:');
851
+ return promise.promise;
852
+ };
853
+
854
+ kc.clearToken = function () {
855
+ if (kc.token) {
856
+ setToken(null, null, null);
857
+ kc.onAuthLogout && kc.onAuthLogout();
858
+ if (kc.loginRequired) {
859
+ kc.login();
860
+ }
861
+ }
862
+ };
863
+
864
+ function getRealmUrl() {
865
+ if (typeof kc.authServerUrl !== "undefined") {
866
+ if (
867
+ kc.authServerUrl.charAt(kc.authServerUrl.length - 1) == "/"
868
+ ) {
869
+ return (
870
+ kc.authServerUrl + "realms/" + encodeURIComponent(kc.realm)
871
+ );
872
+ } else {
873
+ return (
874
+ kc.authServerUrl + "/realms/" + encodeURIComponent(kc.realm)
875
+ );
876
+ }
877
+ } else {
878
+ return undefined;
985
879
  }
880
+ }
881
+
882
+ function getOrigin() {
883
+ if (!window.location.origin) {
884
+ return (
885
+ window.location.protocol +
886
+ "//" +
887
+ window.location.hostname +
888
+ (window.location.port ? ":" + window.location.port : "")
889
+ );
890
+ } else {
891
+ return window.location.origin;
892
+ }
893
+ }
986
894
 
987
- function setToken(token, refreshToken, idToken, timeLocal) {
988
- if (kc.tokenTimeoutHandle) {
989
- clearTimeout(kc.tokenTimeoutHandle);
990
- kc.tokenTimeoutHandle = null;
991
- }
895
+ function processCallback(oauth, promise) {
896
+ var code = oauth.code;
897
+ var error = oauth.error;
898
+ var prompt = oauth.prompt;
992
899
 
993
- if (refreshToken) {
994
- kc.refreshToken = refreshToken;
995
- kc.refreshTokenParsed = jwtDecode(refreshToken);
996
- } else {
997
- delete kc.refreshToken;
998
- delete kc.refreshTokenParsed;
999
- }
900
+ var timeLocal = new Date().getTime();
901
+
902
+ if (oauth["kc_action_status"]) {
903
+ kc.onActionUpdate &&
904
+ kc.onActionUpdate(
905
+ oauth["kc_action_status"],
906
+ oauth["kc_action"]
907
+ );
908
+ }
1000
909
 
1001
- if (idToken) {
1002
- kc.idToken = idToken;
1003
- kc.idTokenParsed = jwtDecode(idToken);
910
+ if (error) {
911
+ if (prompt != "none") {
912
+ if (
913
+ oauth.error_description &&
914
+ oauth.error_description === "authentication_expired"
915
+ ) {
916
+ kc.login(oauth.loginOptions);
1004
917
  } else {
1005
- delete kc.idToken;
1006
- delete kc.idTokenParsed;
1007
- }
918
+ var errorData = {
919
+ error: error,
920
+ error_description: oauth.error_description,
921
+ };
922
+
923
+ kc.onAuthError && kc.onAuthError(errorData);
924
+ promise && promise.setError(errorData);
925
+ }
926
+ } else {
927
+ promise && promise.setSuccess();
928
+ }
929
+ return;
930
+ } else if (
931
+ kc.flow != "standard" &&
932
+ (oauth.access_token || oauth.id_token)
933
+ ) {
934
+ authSuccess(oauth.access_token, null, oauth.id_token, true);
935
+ }
1008
936
 
1009
- if (token) {
1010
- kc.token = token;
1011
- kc.tokenParsed = jwtDecode(token);
1012
- kc.sessionId = kc.tokenParsed.session_state;
1013
- kc.authenticated = true;
1014
- kc.subject = kc.tokenParsed.sub;
1015
- kc.realmAccess = kc.tokenParsed.realm_access;
1016
- kc.resourceAccess = kc.tokenParsed.resource_access;
1017
-
1018
- if (timeLocal) {
1019
- kc.timeSkew = Math.floor(timeLocal / 1000) - kc.tokenParsed.iat;
1020
- }
937
+ if (kc.flow != "implicit" && code) {
938
+ var params = "code=" + code + "&grant_type=authorization_code";
939
+ var url = kc.endpoints.token();
1021
940
 
1022
- if (kc.timeSkew != null) {
1023
- logInfo('[KEYCLOAK] Estimated time difference between browser and server is ' + kc.timeSkew + ' seconds');
1024
-
1025
- if (kc.onTokenExpired) {
1026
- var expiresIn = (kc.tokenParsed['exp'] - (new Date().getTime() / 1000) + kc.timeSkew) * 1000;
1027
- logInfo('[KEYCLOAK] Token expires in ' + Math.round(expiresIn / 1000) + ' s');
1028
- if (expiresIn <= 0) {
1029
- kc.onTokenExpired();
1030
- } else {
1031
- kc.tokenTimeoutHandle = setTimeout(kc.onTokenExpired, expiresIn);
1032
- }
1033
- }
1034
- }
1035
- } else {
1036
- delete kc.token;
1037
- delete kc.tokenParsed;
1038
- delete kc.subject;
1039
- delete kc.realmAccess;
1040
- delete kc.resourceAccess;
941
+ var req = new XMLHttpRequest();
942
+ req.open("POST", url, true);
1041
943
 
1042
- kc.authenticated = false;
1043
- }
1044
- }
944
+ req.setRequestHeader(
945
+ "Content-type",
946
+ "application/x-www-form-urlencoded"
947
+ );
1045
948
 
1046
- function createUUID() {
1047
- var hexDigits = '0123456789abcdef';
1048
- var s = generateRandomString(36, hexDigits).split("");
1049
- s[14] = '4';
1050
- s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
1051
- s[8] = s[13] = s[18] = s[23] = '-';
1052
- var uuid = s.join('');
1053
- return uuid;
1054
- }
949
+ params += "&client_id=" + encodeURIComponent(kc.clientId);
950
+ params += "&redirect_uri=" + oauth.redirectUri;
1055
951
 
1056
- function parseCallback(url) {
1057
- var oauth = parseCallbackUrl(url);
1058
- if (!oauth) {
1059
- return;
1060
- }
952
+ if (oauth.pkceCodeVerifier) {
953
+ params += "&code_verifier=" + oauth.pkceCodeVerifier;
954
+ }
1061
955
 
1062
- var oauthState = callbackStorage.get(oauth.state);
956
+ req.withCredentials = true;
1063
957
 
1064
- if (oauthState) {
1065
- oauth.valid = true;
1066
- oauth.redirectUri = oauthState.redirectUri;
1067
- oauth.storedNonce = oauthState.nonce;
1068
- oauth.prompt = oauthState.prompt;
1069
- oauth.pkceCodeVerifier = oauthState.pkceCodeVerifier;
1070
- }
958
+ req.onreadystatechange = function () {
959
+ if (req.readyState == 4) {
960
+ if (req.status == 200) {
961
+ var tokenResponse = JSON.parse(req.responseText);
962
+ authSuccess(
963
+ tokenResponse["access_token"],
964
+ tokenResponse["refresh_token"],
965
+ tokenResponse["id_token"],
966
+ kc.flow === "standard"
967
+ );
1071
968
 
1072
- return oauth;
1073
- }
1074
-
1075
- function parseCallbackUrl(url) {
1076
- var supportedParams;
1077
- switch (kc.flow) {
1078
- case 'standard':
1079
- supportedParams = ['code', 'state', 'session_state', 'kc_action_status', 'iss'];
1080
- break;
1081
- case 'implicit':
1082
- supportedParams = ['access_token', 'token_type', 'id_token', 'state', 'session_state', 'expires_in', 'kc_action_status', 'iss'];
1083
- break;
1084
- case 'hybrid':
1085
- supportedParams = ['access_token', 'token_type', 'id_token', 'code', 'state', 'session_state', 'expires_in', 'kc_action_status', 'iss'];
1086
- break;
969
+ scheduleCheckIframe();
970
+ } else {
971
+ kc.onAuthError && kc.onAuthError();
972
+ promise && promise.setError();
973
+ }
1087
974
  }
975
+ };
1088
976
 
1089
- supportedParams.push('error');
1090
- supportedParams.push('error_description');
1091
- supportedParams.push('error_uri');
977
+ req.send(params);
978
+ }
979
+
980
+ function authSuccess(
981
+ accessToken,
982
+ refreshToken,
983
+ idToken,
984
+ fulfillPromise
985
+ ) {
986
+ timeLocal = (timeLocal + new Date().getTime()) / 2;
987
+
988
+ setToken(accessToken, refreshToken, idToken, timeLocal);
989
+
990
+ if (
991
+ useNonce &&
992
+ kc.idTokenParsed &&
993
+ kc.idTokenParsed.nonce != oauth.storedNonce
994
+ ) {
995
+ logInfo("[KEYCLOAK] Invalid nonce, clearing token");
996
+ kc.clearToken();
997
+ promise && promise.setError();
998
+ } else {
999
+ if (fulfillPromise) {
1000
+ kc.onAuthSuccess && kc.onAuthSuccess();
1001
+ promise && promise.setSuccess();
1002
+ }
1003
+ }
1004
+ }
1005
+ }
1092
1006
 
1093
- var queryIndex = url.indexOf('?');
1094
- var fragmentIndex = url.indexOf('#');
1007
+ function loadConfig(url) {
1008
+ var promise = createPromise();
1009
+ var configUrl;
1095
1010
 
1096
- var newUrl;
1097
- var parsed;
1011
+ if (!config) {
1012
+ configUrl = "keycloak.json";
1013
+ } else if (typeof config === "string") {
1014
+ configUrl = config;
1015
+ }
1098
1016
 
1099
- if (kc.responseMode === 'query' && queryIndex !== -1) {
1100
- newUrl = url.substring(0, queryIndex);
1101
- parsed = parseCallbackParams(url.substring(queryIndex + 1, fragmentIndex !== -1 ? fragmentIndex : url.length), supportedParams);
1102
- if (parsed.paramsString !== '') {
1103
- newUrl += '?' + parsed.paramsString;
1017
+ function setupOidcEndoints(oidcConfiguration) {
1018
+ if (!oidcConfiguration) {
1019
+ kc.endpoints = {
1020
+ authorize: function () {
1021
+ return getRealmUrl() + "/protocol/openid-connect/auth";
1022
+ },
1023
+ token: function () {
1024
+ return getRealmUrl() + "/protocol/openid-connect/token";
1025
+ },
1026
+ logout: function () {
1027
+ return getRealmUrl() + "/protocol/openid-connect/logout";
1028
+ },
1029
+ checkSessionIframe: function () {
1030
+ var src =
1031
+ getRealmUrl() +
1032
+ "/protocol/openid-connect/login-status-iframe.html";
1033
+ if (kc.iframeVersion) {
1034
+ src = src + "?version=" + kc.iframeVersion;
1104
1035
  }
1105
- if (fragmentIndex !== -1) {
1106
- newUrl += url.substring(fragmentIndex);
1036
+ return src;
1037
+ },
1038
+ thirdPartyCookiesIframe: function () {
1039
+ var src =
1040
+ getRealmUrl() +
1041
+ "/protocol/openid-connect/3p-cookies/step1.html";
1042
+ if (kc.iframeVersion) {
1043
+ src = src + "?version=" + kc.iframeVersion;
1107
1044
  }
1108
- } else if (kc.responseMode === 'fragment' && fragmentIndex !== -1) {
1109
- newUrl = url.substring(0, fragmentIndex);
1110
- parsed = parseCallbackParams(url.substring(fragmentIndex + 1), supportedParams);
1111
- if (parsed.paramsString !== '') {
1112
- newUrl += '#' + parsed.paramsString;
1045
+ return src;
1046
+ },
1047
+ register: function () {
1048
+ return (
1049
+ getRealmUrl() + "/protocol/openid-connect/registrations"
1050
+ );
1051
+ },
1052
+ userinfo: function () {
1053
+ return (
1054
+ getRealmUrl() + "/protocol/openid-connect/userinfo"
1055
+ );
1056
+ },
1057
+ };
1058
+ } else {
1059
+ kc.endpoints = {
1060
+ authorize: function () {
1061
+ return oidcConfiguration.authorization_endpoint;
1062
+ },
1063
+ token: function () {
1064
+ return oidcConfiguration.token_endpoint;
1065
+ },
1066
+ logout: function () {
1067
+ if (!oidcConfiguration.end_session_endpoint) {
1068
+ throw "Not supported by the OIDC server";
1113
1069
  }
1114
- }
1115
-
1116
- if (parsed && parsed.oauthParams) {
1117
- if (kc.flow === 'standard' || kc.flow === 'hybrid') {
1118
- if ((parsed.oauthParams.code || parsed.oauthParams.error) && parsed.oauthParams.state) {
1119
- parsed.oauthParams.newUrl = newUrl;
1120
- return parsed.oauthParams;
1121
- }
1122
- } else if (kc.flow === 'implicit') {
1123
- if ((parsed.oauthParams.access_token || parsed.oauthParams.error) && parsed.oauthParams.state) {
1124
- parsed.oauthParams.newUrl = newUrl;
1125
- return parsed.oauthParams;
1126
- }
1070
+ return oidcConfiguration.end_session_endpoint;
1071
+ },
1072
+ checkSessionIframe: function () {
1073
+ if (!oidcConfiguration.check_session_iframe) {
1074
+ throw "Not supported by the OIDC server";
1127
1075
  }
1128
- }
1129
- }
1130
-
1131
- function parseCallbackParams(paramsString, supportedParams) {
1132
- var p = paramsString.split('&');
1133
- var result = {
1134
- paramsString: '',
1135
- oauthParams: {}
1136
- }
1137
- for (var i = 0; i < p.length; i++) {
1138
- var split = p[i].indexOf("=");
1139
- var key = p[i].slice(0, split);
1140
- if (supportedParams.indexOf(key) !== -1) {
1141
- result.oauthParams[key] = p[i].slice(split + 1);
1142
- } else {
1143
- if (result.paramsString !== '') {
1144
- result.paramsString += '&';
1145
- }
1146
- result.paramsString += p[i];
1076
+ return oidcConfiguration.check_session_iframe;
1077
+ },
1078
+ register: function () {
1079
+ throw 'Redirection to "Register user" page not supported in standard OIDC mode';
1080
+ },
1081
+ userinfo: function () {
1082
+ if (!oidcConfiguration.userinfo_endpoint) {
1083
+ throw "Not supported by the OIDC server";
1147
1084
  }
1148
- }
1149
- return result;
1085
+ return oidcConfiguration.userinfo_endpoint;
1086
+ },
1087
+ };
1088
+ }
1150
1089
  }
1151
1090
 
1152
- function createPromise() {
1153
- // Need to create a native Promise which also preserves the
1154
- // interface of the custom promise type previously used by the API
1155
- var p = {
1156
- setSuccess: function(result) {
1157
- p.resolve(result);
1158
- },
1091
+ if (configUrl) {
1092
+ var req = new XMLHttpRequest();
1093
+ req.open("GET", configUrl, true);
1094
+ req.setRequestHeader("Accept", "application/json");
1159
1095
 
1160
- setError: function(result) {
1161
- p.reject(result);
1096
+ req.onreadystatechange = function () {
1097
+ if (req.readyState == 4) {
1098
+ if (req.status == 200 || fileLoaded(req)) {
1099
+ var config = JSON.parse(req.responseText);
1100
+
1101
+ kc.authServerUrl = config["auth-server-url"];
1102
+ kc.realm = config["realm"];
1103
+ kc.clientId = config["resource"];
1104
+ setupOidcEndoints(null);
1105
+ promise.setSuccess();
1106
+ } else {
1107
+ promise.setError();
1108
+ }
1109
+ }
1110
+ };
1111
+
1112
+ req.send();
1113
+ } else {
1114
+ if (!config.clientId) {
1115
+ throw "clientId missing";
1116
+ }
1117
+
1118
+ kc.clientId = config.clientId;
1119
+
1120
+ var oidcProvider = config["oidcProvider"];
1121
+ if (!oidcProvider) {
1122
+ if (!config["url"]) {
1123
+ var scripts = document.getElementsByTagName("script");
1124
+ for (var i = 0; i < scripts.length; i++) {
1125
+ if (scripts[i].src.match(/.*keycloak\.js/)) {
1126
+ config.url = scripts[i].src.substr(
1127
+ 0,
1128
+ scripts[i].src.indexOf("/js/keycloak.js")
1129
+ );
1130
+
1131
+ break;
1162
1132
  }
1163
- };
1164
- p.promise = new Promise(function(resolve, reject) {
1165
- p.resolve = resolve;
1166
- p.reject = reject;
1167
- });
1133
+ }
1134
+ }
1135
+ if (!config.realm) {
1136
+ throw "realm missing";
1137
+ }
1138
+
1139
+ kc.authServerUrl = config.url;
1140
+ kc.realm = config.realm;
1141
+ setupOidcEndoints(null);
1142
+ promise.setSuccess();
1143
+ } else {
1144
+ if (typeof oidcProvider === "string") {
1145
+ var oidcProviderConfigUrl;
1146
+ if (oidcProvider.charAt(oidcProvider.length - 1) == "/") {
1147
+ oidcProviderConfigUrl =
1148
+ oidcProvider + ".well-known/openid-configuration";
1149
+ } else {
1150
+ oidcProviderConfigUrl =
1151
+ oidcProvider + "/.well-known/openid-configuration";
1152
+ }
1153
+ var req = new XMLHttpRequest();
1154
+ req.open("GET", oidcProviderConfigUrl, true);
1155
+ req.setRequestHeader("Accept", "application/json");
1156
+
1157
+ req.onreadystatechange = function () {
1158
+ if (req.readyState == 4) {
1159
+ if (req.status == 200 || fileLoaded(req)) {
1160
+ var oidcProviderConfig = JSON.parse(req.responseText);
1161
+ setupOidcEndoints(oidcProviderConfig);
1162
+ promise.setSuccess();
1163
+ } else {
1164
+ promise.setError();
1165
+ }
1166
+ }
1167
+ };
1168
1168
 
1169
- return p;
1169
+ req.send();
1170
+ } else {
1171
+ setupOidcEndoints(oidcProvider);
1172
+ promise.setSuccess();
1173
+ }
1174
+ }
1170
1175
  }
1171
1176
 
1172
- // Function to extend existing native Promise with timeout
1173
- function applyTimeoutToPromise(promise, timeout, errorMessage) {
1174
- var timeoutHandle = null;
1175
- var timeoutPromise = new Promise(function (resolve, reject) {
1176
- timeoutHandle = setTimeout(function () {
1177
- reject({ "error": errorMessage || "Promise is not settled within timeout of " + timeout + "ms" });
1178
- }, timeout);
1179
- });
1177
+ return promise.promise;
1178
+ }
1179
+
1180
+ function fileLoaded(xhr) {
1181
+ return (
1182
+ xhr.status == 0 &&
1183
+ xhr.responseText &&
1184
+ xhr.responseURL.startsWith("file:")
1185
+ );
1186
+ }
1187
+
1188
+ function setToken(token, refreshToken, idToken, timeLocal) {
1189
+ if (kc.tokenTimeoutHandle) {
1190
+ clearTimeout(kc.tokenTimeoutHandle);
1191
+ kc.tokenTimeoutHandle = null;
1192
+ }
1180
1193
 
1181
- return Promise.race([promise, timeoutPromise]).finally(function () {
1182
- clearTimeout(timeoutHandle);
1183
- });
1194
+ if (refreshToken) {
1195
+ kc.refreshToken = refreshToken;
1196
+ kc.refreshTokenParsed = jwtDecode(refreshToken);
1197
+ } else {
1198
+ delete kc.refreshToken;
1199
+ delete kc.refreshTokenParsed;
1184
1200
  }
1185
1201
 
1186
- function setupCheckLoginIframe() {
1187
- var promise = createPromise();
1202
+ if (idToken) {
1203
+ kc.idToken = idToken;
1204
+ kc.idTokenParsed = jwtDecode(idToken);
1205
+ } else {
1206
+ delete kc.idToken;
1207
+ delete kc.idTokenParsed;
1208
+ }
1188
1209
 
1189
- if (!loginIframe.enable) {
1190
- promise.setSuccess();
1191
- return promise.promise;
1192
- }
1210
+ if (token) {
1211
+ kc.token = token;
1212
+ kc.tokenParsed = jwtDecode(token);
1213
+ kc.sessionId = kc.tokenParsed.sid;
1214
+ kc.authenticated = true;
1215
+ kc.subject = kc.tokenParsed.sub;
1216
+ kc.realmAccess = kc.tokenParsed.realm_access;
1217
+ kc.resourceAccess = kc.tokenParsed.resource_access;
1218
+
1219
+ if (timeLocal) {
1220
+ kc.timeSkew =
1221
+ Math.floor(timeLocal / 1000) - kc.tokenParsed.iat;
1222
+ }
1223
+
1224
+ if (kc.timeSkew != null) {
1225
+ logInfo(
1226
+ "[KEYCLOAK] Estimated time difference between browser and server is " +
1227
+ kc.timeSkew +
1228
+ " seconds"
1229
+ );
1230
+
1231
+ if (kc.onTokenExpired) {
1232
+ var expiresIn =
1233
+ (kc.tokenParsed["exp"] -
1234
+ new Date().getTime() / 1000 +
1235
+ kc.timeSkew) *
1236
+ 1000;
1237
+
1238
+ logInfo(
1239
+ "[KEYCLOAK] Token expires in " +
1240
+ Math.round(expiresIn / 1000) +
1241
+ " s"
1242
+ );
1243
+
1244
+ if (expiresIn <= 0) {
1245
+ kc.onTokenExpired();
1246
+ } else {
1247
+ kc.tokenTimeoutHandle = setTimeout(
1248
+ kc.onTokenExpired,
1249
+ expiresIn
1250
+ );
1251
+ }
1252
+ }
1253
+ }
1254
+ } else {
1255
+ delete kc.token;
1256
+ delete kc.tokenParsed;
1257
+ delete kc.subject;
1258
+ delete kc.realmAccess;
1259
+ delete kc.resourceAccess;
1260
+
1261
+ kc.authenticated = false;
1262
+ }
1263
+ }
1264
+
1265
+ function createUUID() {
1266
+ var hexDigits = "0123456789abcdef";
1267
+ var s = generateRandomString(36, hexDigits).split("");
1268
+ s[14] = "4";
1269
+ s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
1270
+ s[8] = s[13] = s[18] = s[23] = "-";
1271
+ var uuid = s.join("");
1272
+ return uuid;
1273
+ }
1274
+
1275
+ function parseCallback(url) {
1276
+ var oauth = parseCallbackUrl(url);
1277
+ if (!oauth) {
1278
+ return;
1279
+ }
1193
1280
 
1194
- if (loginIframe.iframe) {
1195
- promise.setSuccess();
1196
- return promise.promise;
1197
- }
1281
+ var oauthState = callbackStorage.get(oauth.state);
1198
1282
 
1199
- var iframe = document.createElement('iframe');
1200
- loginIframe.iframe = iframe;
1283
+ if (oauthState) {
1284
+ oauth.valid = true;
1285
+ oauth.redirectUri = oauthState.redirectUri;
1286
+ oauth.storedNonce = oauthState.nonce;
1287
+ oauth.prompt = oauthState.prompt;
1288
+ oauth.pkceCodeVerifier = oauthState.pkceCodeVerifier;
1289
+ oauth.loginOptions = oauthState.loginOptions;
1290
+ }
1201
1291
 
1202
- iframe.onload = function() {
1203
- var authUrl = kc.endpoints.authorize();
1204
- if (authUrl.charAt(0) === '/') {
1205
- loginIframe.iframeOrigin = getOrigin();
1206
- } else {
1207
- loginIframe.iframeOrigin = authUrl.substring(0, authUrl.indexOf('/', 8));
1208
- }
1209
- promise.setSuccess();
1210
- }
1292
+ return oauth;
1293
+ }
1294
+
1295
+ function parseCallbackUrl(url) {
1296
+ var supportedParams;
1297
+ switch (kc.flow) {
1298
+ case "standard":
1299
+ supportedParams = [
1300
+ "code",
1301
+ "state",
1302
+ "session_state",
1303
+ "kc_action_status",
1304
+ "kc_action",
1305
+ "iss",
1306
+ ];
1307
+
1308
+ break;
1309
+ case "implicit":
1310
+ supportedParams = [
1311
+ "access_token",
1312
+ "token_type",
1313
+ "id_token",
1314
+ "state",
1315
+ "session_state",
1316
+ "expires_in",
1317
+ "kc_action_status",
1318
+ "kc_action",
1319
+ "iss",
1320
+ ];
1321
+
1322
+ break;
1323
+ case "hybrid":
1324
+ supportedParams = [
1325
+ "access_token",
1326
+ "token_type",
1327
+ "id_token",
1328
+ "code",
1329
+ "state",
1330
+ "session_state",
1331
+ "expires_in",
1332
+ "kc_action_status",
1333
+ "kc_action",
1334
+ "iss",
1335
+ ];
1336
+
1337
+ break;
1338
+ }
1211
1339
 
1212
- var src = kc.endpoints.checkSessionIframe();
1213
- iframe.setAttribute('src', src );
1214
- iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
1215
- iframe.setAttribute('title', 'keycloak-session-iframe' );
1216
- iframe.style.display = 'none';
1217
- document.body.appendChild(iframe);
1340
+ supportedParams.push("error");
1341
+ supportedParams.push("error_description");
1342
+ supportedParams.push("error_uri");
1343
+
1344
+ var queryIndex = url.indexOf("?");
1345
+ var fragmentIndex = url.indexOf("#");
1346
+
1347
+ var newUrl;
1348
+ var parsed;
1349
+
1350
+ if (kc.responseMode === "query" && queryIndex !== -1) {
1351
+ newUrl = url.substring(0, queryIndex);
1352
+
1353
+ parsed = parseCallbackParams(
1354
+ url.substring(
1355
+ queryIndex + 1,
1356
+ fragmentIndex !== -1 ? fragmentIndex : url.length
1357
+ ),
1358
+ supportedParams
1359
+ );
1360
+
1361
+ if (parsed.paramsString !== "") {
1362
+ newUrl += "?" + parsed.paramsString;
1363
+ }
1364
+ if (fragmentIndex !== -1) {
1365
+ newUrl += url.substring(fragmentIndex);
1366
+ }
1367
+ } else if (
1368
+ kc.responseMode === "fragment" &&
1369
+ fragmentIndex !== -1
1370
+ ) {
1371
+ newUrl = url.substring(0, fragmentIndex);
1372
+
1373
+ parsed = parseCallbackParams(
1374
+ url.substring(fragmentIndex + 1),
1375
+ supportedParams
1376
+ );
1377
+
1378
+ if (parsed.paramsString !== "") {
1379
+ newUrl += "#" + parsed.paramsString;
1380
+ }
1381
+ }
1218
1382
 
1219
- var messageCallback = function(event) {
1220
- if ((event.origin !== loginIframe.iframeOrigin) || (loginIframe.iframe.contentWindow !== event.source)) {
1221
- return;
1222
- }
1383
+ if (parsed && parsed.oauthParams) {
1384
+ if (kc.flow === "standard" || kc.flow === "hybrid") {
1385
+ if (
1386
+ (parsed.oauthParams.code || parsed.oauthParams.error) &&
1387
+ parsed.oauthParams.state
1388
+ ) {
1389
+ parsed.oauthParams.newUrl = newUrl;
1390
+ return parsed.oauthParams;
1391
+ }
1392
+ } else if (kc.flow === "implicit") {
1393
+ if (
1394
+ (parsed.oauthParams.access_token ||
1395
+ parsed.oauthParams.error) &&
1396
+ parsed.oauthParams.state
1397
+ ) {
1398
+ parsed.oauthParams.newUrl = newUrl;
1399
+ return parsed.oauthParams;
1400
+ }
1401
+ }
1402
+ }
1403
+ }
1223
1404
 
1224
- if (!(event.data == 'unchanged' || event.data == 'changed' || event.data == 'error')) {
1225
- return;
1226
- }
1405
+ function parseCallbackParams(paramsString, supportedParams) {
1406
+ var p = paramsString.split("&");
1407
+ var result = {
1408
+ paramsString: "",
1409
+ oauthParams: {},
1410
+ };
1411
+ for (var i = 0; i < p.length; i++) {
1412
+ var split = p[i].indexOf("=");
1413
+ var key = p[i].slice(0, split);
1414
+ if (supportedParams.indexOf(key) !== -1) {
1415
+ result.oauthParams[key] = p[i].slice(split + 1);
1416
+ } else {
1417
+ if (result.paramsString !== "") {
1418
+ result.paramsString += "&";
1419
+ }
1420
+ result.paramsString += p[i];
1421
+ }
1422
+ }
1423
+ return result;
1424
+ }
1425
+
1426
+ function createPromise() {
1427
+ // Need to create a native Promise which also preserves the
1428
+ // interface of the custom promise type previously used by the API
1429
+ var p = {
1430
+ setSuccess: function (result) {
1431
+ p.resolve(result);
1432
+ },
1433
+
1434
+ setError: function (result) {
1435
+ p.reject(result);
1436
+ },
1437
+ };
1438
+ p.promise = new Promise(function (resolve, reject) {
1439
+ p.resolve = resolve;
1440
+ p.reject = reject;
1441
+ });
1442
+
1443
+ return p;
1444
+ }
1445
+
1446
+ // Function to extend existing native Promise with timeout
1447
+ function applyTimeoutToPromise(promise, timeout, errorMessage) {
1448
+ var timeoutHandle = null;
1449
+ var timeoutPromise = new Promise(function (resolve, reject) {
1450
+ timeoutHandle = setTimeout(function () {
1451
+ reject({
1452
+ error:
1453
+ errorMessage ||
1454
+ "Promise is not settled within timeout of " +
1455
+ timeout +
1456
+ "ms",
1457
+ });
1458
+ }, timeout);
1459
+ });
1460
+
1461
+ return Promise.race([promise, timeoutPromise]).finally(
1462
+ function () {
1463
+ clearTimeout(timeoutHandle);
1464
+ }
1465
+ );
1466
+ }
1467
+
1468
+ function setupCheckLoginIframe() {
1469
+ var promise = createPromise();
1470
+
1471
+ if (!loginIframe.enable) {
1472
+ promise.setSuccess();
1473
+ return promise.promise;
1474
+ }
1227
1475
 
1476
+ if (loginIframe.iframe) {
1477
+ promise.setSuccess();
1478
+ return promise.promise;
1479
+ }
1228
1480
 
1229
- if (event.data != 'unchanged') {
1230
- kc.clearToken();
1231
- }
1481
+ var iframe = document.createElement("iframe");
1482
+ loginIframe.iframe = iframe;
1483
+
1484
+ iframe.onload = function () {
1485
+ var authUrl = kc.endpoints.authorize();
1486
+ if (authUrl.charAt(0) === "/") {
1487
+ loginIframe.iframeOrigin = getOrigin();
1488
+ } else {
1489
+ loginIframe.iframeOrigin = authUrl.substring(
1490
+ 0,
1491
+ authUrl.indexOf("/", 8)
1492
+ );
1493
+ }
1494
+ promise.setSuccess();
1495
+ };
1232
1496
 
1233
- var callbacks = loginIframe.callbackList.splice(0, loginIframe.callbackList.length);
1497
+ var src = kc.endpoints.checkSessionIframe();
1498
+ iframe.setAttribute("src", src);
1499
+
1500
+ iframe.setAttribute(
1501
+ "sandbox",
1502
+ "allow-storage-access-by-user-activation allow-scripts allow-same-origin"
1503
+ );
1504
+
1505
+ iframe.setAttribute("title", "keycloak-session-iframe");
1506
+ iframe.style.display = "none";
1507
+ document.body.appendChild(iframe);
1508
+
1509
+ var messageCallback = function (event) {
1510
+ if (
1511
+ event.origin !== loginIframe.iframeOrigin ||
1512
+ loginIframe.iframe.contentWindow !== event.source
1513
+ ) {
1514
+ return;
1515
+ }
1516
+
1517
+ if (
1518
+ !(
1519
+ event.data == "unchanged" ||
1520
+ event.data == "changed" ||
1521
+ event.data == "error"
1522
+ )
1523
+ ) {
1524
+ return;
1525
+ }
1526
+
1527
+ if (event.data != "unchanged") {
1528
+ kc.clearToken();
1529
+ }
1530
+
1531
+ var callbacks = loginIframe.callbackList.splice(
1532
+ 0,
1533
+ loginIframe.callbackList.length
1534
+ );
1535
+
1536
+ for (var i = callbacks.length - 1; i >= 0; --i) {
1537
+ var promise = callbacks[i];
1538
+ if (event.data == "error") {
1539
+ promise.setError();
1540
+ } else {
1541
+ promise.setSuccess(event.data == "unchanged");
1542
+ }
1543
+ }
1544
+ };
1234
1545
 
1235
- for (var i = callbacks.length - 1; i >= 0; --i) {
1236
- var promise = callbacks[i];
1237
- if (event.data == 'error') {
1238
- promise.setError();
1239
- } else {
1240
- promise.setSuccess(event.data == 'unchanged');
1241
- }
1242
- }
1243
- };
1546
+ window.addEventListener("message", messageCallback, false);
1244
1547
 
1245
- window.addEventListener('message', messageCallback, false);
1548
+ return promise.promise;
1549
+ }
1246
1550
 
1247
- return promise.promise;
1551
+ function scheduleCheckIframe() {
1552
+ if (loginIframe.enable) {
1553
+ if (kc.token) {
1554
+ setTimeout(function () {
1555
+ checkLoginIframe().then(function (unchanged) {
1556
+ if (unchanged) {
1557
+ scheduleCheckIframe();
1558
+ }
1559
+ });
1560
+ }, loginIframe.interval * 1000);
1561
+ }
1562
+ }
1563
+ }
1564
+
1565
+ function checkLoginIframe() {
1566
+ var promise = createPromise();
1567
+
1568
+ if (loginIframe.iframe && loginIframe.iframeOrigin) {
1569
+ var msg =
1570
+ kc.clientId + " " + (kc.sessionId ? kc.sessionId : "");
1571
+ loginIframe.callbackList.push(promise);
1572
+ var origin = loginIframe.iframeOrigin;
1573
+ if (loginIframe.callbackList.length == 1) {
1574
+ loginIframe.iframe.contentWindow.postMessage(msg, origin);
1575
+ }
1576
+ } else {
1577
+ promise.setSuccess();
1248
1578
  }
1249
1579
 
1250
- function scheduleCheckIframe() {
1251
- if (loginIframe.enable) {
1252
- if (kc.token) {
1253
- setTimeout(function() {
1254
- checkLoginIframe().then(function(unchanged) {
1255
- if (unchanged) {
1256
- scheduleCheckIframe();
1257
- }
1258
- });
1259
- }, loginIframe.interval * 1000);
1260
- }
1261
- }
1580
+ return promise.promise;
1581
+ }
1582
+
1583
+ function check3pCookiesSupported() {
1584
+ var promise = createPromise();
1585
+
1586
+ if (loginIframe.enable || kc.silentCheckSsoRedirectUri) {
1587
+ var iframe = document.createElement("iframe");
1588
+
1589
+ iframe.setAttribute(
1590
+ "src",
1591
+ kc.endpoints.thirdPartyCookiesIframe()
1592
+ );
1593
+
1594
+ iframe.setAttribute(
1595
+ "sandbox",
1596
+ "allow-storage-access-by-user-activation allow-scripts allow-same-origin"
1597
+ );
1598
+
1599
+ iframe.setAttribute("title", "keycloak-3p-check-iframe");
1600
+ iframe.style.display = "none";
1601
+ document.body.appendChild(iframe);
1602
+
1603
+ var messageCallback = function (event) {
1604
+ if (iframe.contentWindow !== event.source) {
1605
+ return;
1606
+ }
1607
+
1608
+ if (
1609
+ event.data !== "supported" &&
1610
+ event.data !== "unsupported"
1611
+ ) {
1612
+ return;
1613
+ } else if (event.data === "unsupported") {
1614
+ logWarn(
1615
+ "[KEYCLOAK] Your browser is blocking access to 3rd-party cookies, this means:\n\n" +
1616
+ " - It is not possible to retrieve tokens without redirecting to the Keycloak server (a.k.a. no support for silent authentication).\n" +
1617
+ " - It is not possible to automatically detect changes to the session status (such as the user logging out in another tab).\n\n" +
1618
+ "For more information see: https://www.keycloak.org/docs/latest/securing_apps/#_modern_browsers"
1619
+ );
1620
+
1621
+ loginIframe.enable = false;
1622
+ if (kc.silentCheckSsoFallback) {
1623
+ kc.silentCheckSsoRedirectUri = false;
1624
+ }
1625
+ }
1626
+
1627
+ document.body.removeChild(iframe);
1628
+ window.removeEventListener("message", messageCallback);
1629
+ promise.setSuccess();
1630
+ };
1631
+
1632
+ window.addEventListener("message", messageCallback, false);
1633
+ } else {
1634
+ promise.setSuccess();
1262
1635
  }
1263
1636
 
1264
- function checkLoginIframe() {
1265
- var promise = createPromise();
1637
+ return applyTimeoutToPromise(
1638
+ promise.promise,
1639
+ kc.messageReceiveTimeout,
1640
+ "Timeout when waiting for 3rd party check iframe message."
1641
+ );
1642
+ }
1643
+
1644
+ function loadAdapter(type) {
1645
+ if (!type || type == "default") {
1646
+ return {
1647
+ login: function (options) {
1648
+ window.location.assign(kc.createLoginUrl(options));
1649
+ return createPromise().promise;
1650
+ },
1651
+
1652
+ logout: async function (options) {
1653
+ const logoutMethod =
1654
+ options?.logoutMethod ?? kc.logoutMethod;
1655
+ if (logoutMethod === "GET") {
1656
+ window.location.replace(kc.createLogoutUrl(options));
1657
+ return;
1658
+ }
1266
1659
 
1267
- if (loginIframe.iframe && loginIframe.iframeOrigin ) {
1268
- var msg = kc.clientId + ' ' + (kc.sessionId ? kc.sessionId : '');
1269
- loginIframe.callbackList.push(promise);
1270
- var origin = loginIframe.iframeOrigin;
1271
- if (loginIframe.callbackList.length == 1) {
1272
- loginIframe.iframe.contentWindow.postMessage(msg, origin);
1273
- }
1274
- } else {
1275
- promise.setSuccess();
1276
- }
1660
+ const logoutUrl = kc.createLogoutUrl(options);
1661
+ const response = await fetch(logoutUrl, {
1662
+ method: "POST",
1663
+ headers: {
1664
+ "Content-Type": "application/x-www-form-urlencoded",
1665
+ },
1666
+ body: new URLSearchParams({
1667
+ id_token_hint: kc.idToken,
1668
+ client_id: kc.clientId,
1669
+ post_logout_redirect_uri: adapter.redirectUri(
1670
+ options,
1671
+ false
1672
+ ),
1673
+ }),
1674
+ });
1675
+
1676
+ if (response.redirected) {
1677
+ window.location.href = response.url;
1678
+ return;
1679
+ }
1277
1680
 
1278
- return promise.promise;
1681
+ if (response.ok) {
1682
+ window.location.reload();
1683
+ return;
1684
+ }
1685
+
1686
+ throw new Error(
1687
+ "Logout failed, request returned an error code."
1688
+ );
1689
+ },
1690
+
1691
+ register: function (options) {
1692
+ window.location.assign(kc.createRegisterUrl(options));
1693
+ return createPromise().promise;
1694
+ },
1695
+
1696
+ accountManagement: function () {
1697
+ var accountUrl = kc.createAccountUrl();
1698
+ if (typeof accountUrl !== "undefined") {
1699
+ window.location.href = accountUrl;
1700
+ } else {
1701
+ throw "Not supported by the OIDC server";
1702
+ }
1703
+ return createPromise().promise;
1704
+ },
1705
+
1706
+ redirectUri: function (options, encodeHash) {
1707
+ if (arguments.length == 1) {
1708
+ encodeHash = true;
1709
+ }
1710
+
1711
+ if (options && options.redirectUri) {
1712
+ return options.redirectUri;
1713
+ } else if (kc.redirectUri) {
1714
+ return kc.redirectUri;
1715
+ } else {
1716
+ return location.href;
1717
+ }
1718
+ },
1719
+ };
1279
1720
  }
1280
1721
 
1281
- function check3pCookiesSupported() {
1282
- var promise = createPromise();
1722
+ if (type == "cordova") {
1723
+ loginIframe.enable = false;
1724
+ var cordovaOpenWindowWrapper = function (
1725
+ loginUrl,
1726
+ target,
1727
+ options
1728
+ ) {
1729
+ if (window.cordova && window.cordova.InAppBrowser) {
1730
+ // Use inappbrowser for IOS and Android if available
1731
+ return window.cordova.InAppBrowser.open(
1732
+ loginUrl,
1733
+ target,
1734
+ options
1735
+ );
1736
+ } else {
1737
+ return window.open(loginUrl, target, options);
1738
+ }
1739
+ };
1283
1740
 
1284
- if (loginIframe.enable || kc.silentCheckSsoRedirectUri) {
1285
- var iframe = document.createElement('iframe');
1286
- iframe.setAttribute('src', kc.endpoints.thirdPartyCookiesIframe());
1287
- iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
1288
- iframe.setAttribute('title', 'keycloak-3p-check-iframe' );
1289
- iframe.style.display = 'none';
1290
- document.body.appendChild(iframe);
1741
+ var shallowCloneCordovaOptions = function (userOptions) {
1742
+ if (userOptions && userOptions.cordovaOptions) {
1743
+ return Object.keys(userOptions.cordovaOptions).reduce(
1744
+ function (options, optionName) {
1745
+ options[optionName] =
1746
+ userOptions.cordovaOptions[optionName];
1291
1747
 
1292
- var messageCallback = function(event) {
1293
- if (iframe.contentWindow !== event.source) {
1294
- return;
1295
- }
1748
+ return options;
1749
+ },
1750
+ {}
1751
+ );
1752
+ } else {
1753
+ return {};
1754
+ }
1755
+ };
1756
+
1757
+ var formatCordovaOptions = function (cordovaOptions) {
1758
+ return Object.keys(cordovaOptions)
1759
+ .reduce(function (options, optionName) {
1760
+ options.push(
1761
+ optionName + "=" + cordovaOptions[optionName]
1762
+ );
1763
+
1764
+ return options;
1765
+ }, [])
1766
+ .join(",");
1767
+ };
1768
+
1769
+ var createCordovaOptions = function (userOptions) {
1770
+ var cordovaOptions = shallowCloneCordovaOptions(userOptions);
1771
+ cordovaOptions.location = "no";
1772
+ if (userOptions && userOptions.prompt == "none") {
1773
+ cordovaOptions.hidden = "yes";
1774
+ }
1775
+ return formatCordovaOptions(cordovaOptions);
1776
+ };
1777
+
1778
+ var getCordovaRedirectUri = function () {
1779
+ return kc.redirectUri || "http://localhost";
1780
+ };
1781
+
1782
+ return {
1783
+ login: function (options) {
1784
+ var promise = createPromise();
1785
+
1786
+ var cordovaOptions = createCordovaOptions(options);
1787
+ var loginUrl = kc.createLoginUrl(options);
1788
+ var ref = cordovaOpenWindowWrapper(
1789
+ loginUrl,
1790
+ "_blank",
1791
+ cordovaOptions
1792
+ );
1793
+
1794
+ var completed = false;
1795
+
1796
+ var closed = false;
1797
+ var closeBrowser = function () {
1798
+ closed = true;
1799
+ ref.close();
1800
+ };
1801
+
1802
+ ref.addEventListener("loadstart", function (event) {
1803
+ if (event.url.indexOf(getCordovaRedirectUri()) == 0) {
1804
+ var callback = parseCallback(event.url);
1805
+ processCallback(callback, promise);
1806
+ closeBrowser();
1807
+ completed = true;
1808
+ }
1809
+ });
1810
+
1811
+ ref.addEventListener("loaderror", function (event) {
1812
+ if (!completed) {
1813
+ if (event.url.indexOf(getCordovaRedirectUri()) == 0) {
1814
+ var callback = parseCallback(event.url);
1815
+ processCallback(callback, promise);
1816
+ closeBrowser();
1817
+ completed = true;
1818
+ } else {
1819
+ promise.setError();
1820
+ closeBrowser();
1821
+ }
1822
+ }
1823
+ });
1296
1824
 
1297
- if (event.data !== "supported" && event.data !== "unsupported") {
1298
- return;
1299
- } else if (event.data === "unsupported") {
1300
- logWarn(
1301
- "[KEYCLOAK] Your browser is blocking access to 3rd-party cookies, this means:\n\n" +
1302
- " - It is not possible to retrieve tokens without redirecting to the Keycloak server (a.k.a. no support for silent authentication).\n" +
1303
- " - It is not possible to automatically detect changes to the session status (such as the user logging out in another tab).\n\n" +
1304
- "For more information see: https://www.keycloak.org/docs/latest/securing_apps/#_modern_browsers"
1305
- );
1306
-
1307
- loginIframe.enable = false;
1308
- if (kc.silentCheckSsoFallback) {
1309
- kc.silentCheckSsoRedirectUri = false;
1310
- }
1311
- }
1825
+ ref.addEventListener("exit", function (event) {
1826
+ if (!closed) {
1827
+ promise.setError({
1828
+ reason: "closed_by_user",
1829
+ });
1830
+ }
1831
+ });
1312
1832
 
1313
- document.body.removeChild(iframe);
1314
- window.removeEventListener("message", messageCallback);
1315
- promise.setSuccess();
1316
- };
1833
+ return promise.promise;
1834
+ },
1317
1835
 
1318
- window.addEventListener('message', messageCallback, false);
1319
- } else {
1320
- promise.setSuccess();
1321
- }
1836
+ logout: function (options) {
1837
+ var promise = createPromise();
1322
1838
 
1323
- return applyTimeoutToPromise(promise.promise, kc.messageReceiveTimeout, "Timeout when waiting for 3rd party check iframe message.");
1324
- }
1325
-
1326
- function loadAdapter(type) {
1327
- if (!type || type == 'default') {
1328
- return {
1329
- login: function(options) {
1330
- window.location.assign(kc.createLoginUrl(options));
1331
- return createPromise().promise;
1332
- },
1333
-
1334
- logout: function(options) {
1335
- window.location.replace(kc.createLogoutUrl(options));
1336
- return createPromise().promise;
1337
- },
1338
-
1339
- register: function(options) {
1340
- window.location.assign(kc.createRegisterUrl(options));
1341
- return createPromise().promise;
1342
- },
1343
-
1344
- accountManagement : function() {
1345
- var accountUrl = kc.createAccountUrl();
1346
- if (typeof accountUrl !== 'undefined') {
1347
- window.location.href = accountUrl;
1348
- } else {
1349
- throw "Not supported by the OIDC server";
1350
- }
1351
- return createPromise().promise;
1352
- },
1353
-
1354
- redirectUri: function(options, encodeHash) {
1355
- if (arguments.length == 1) {
1356
- encodeHash = true;
1357
- }
1358
-
1359
- if (options && options.redirectUri) {
1360
- return options.redirectUri;
1361
- } else if (kc.redirectUri) {
1362
- return kc.redirectUri;
1363
- } else {
1364
- return location.href;
1365
- }
1366
- }
1367
- };
1368
- }
1839
+ var logoutUrl = kc.createLogoutUrl(options);
1369
1840
 
1370
- if (type == 'cordova') {
1371
- loginIframe.enable = false;
1372
- var cordovaOpenWindowWrapper = function(loginUrl, target, options) {
1373
- if (window.cordova && window.cordova.InAppBrowser) {
1374
- // Use inappbrowser for IOS and Android if available
1375
- return window.cordova.InAppBrowser.open(loginUrl, target, options);
1376
- } else {
1377
- return window.open(loginUrl, target, options);
1378
- }
1379
- };
1380
-
1381
- var shallowCloneCordovaOptions = function (userOptions) {
1382
- if (userOptions && userOptions.cordovaOptions) {
1383
- return Object.keys(userOptions.cordovaOptions).reduce(function (options, optionName) {
1384
- options[optionName] = userOptions.cordovaOptions[optionName];
1385
- return options;
1386
- }, {});
1387
- } else {
1388
- return {};
1389
- }
1390
- };
1391
-
1392
- var formatCordovaOptions = function (cordovaOptions) {
1393
- return Object.keys(cordovaOptions).reduce(function (options, optionName) {
1394
- options.push(optionName+"="+cordovaOptions[optionName]);
1395
- return options;
1396
- }, []).join(",");
1397
- };
1398
-
1399
- var createCordovaOptions = function (userOptions) {
1400
- var cordovaOptions = shallowCloneCordovaOptions(userOptions);
1401
- cordovaOptions.location = 'no';
1402
- if (userOptions && userOptions.prompt == 'none') {
1403
- cordovaOptions.hidden = 'yes';
1404
- }
1405
- return formatCordovaOptions(cordovaOptions);
1406
- };
1841
+ var ref = cordovaOpenWindowWrapper(
1842
+ logoutUrl,
1843
+ "_blank",
1844
+ "location=no,hidden=yes,clearcache=yes"
1845
+ );
1407
1846
 
1408
- var getCordovaRedirectUri = function() {
1409
- return kc.redirectUri || 'http://localhost';
1410
- }
1411
-
1412
- return {
1413
- login: function(options) {
1414
- var promise = createPromise();
1415
-
1416
- var cordovaOptions = createCordovaOptions(options);
1417
- var loginUrl = kc.createLoginUrl(options);
1418
- var ref = cordovaOpenWindowWrapper(loginUrl, '_blank', cordovaOptions);
1419
- var completed = false;
1420
-
1421
- var closed = false;
1422
- var closeBrowser = function() {
1423
- closed = true;
1424
- ref.close();
1425
- };
1426
-
1427
- ref.addEventListener('loadstart', function(event) {
1428
- if (event.url.indexOf(getCordovaRedirectUri()) == 0) {
1429
- var callback = parseCallback(event.url);
1430
- processCallback(callback, promise);
1431
- closeBrowser();
1432
- completed = true;
1433
- }
1434
- });
1435
-
1436
- ref.addEventListener('loaderror', function(event) {
1437
- if (!completed) {
1438
- if (event.url.indexOf(getCordovaRedirectUri()) == 0) {
1439
- var callback = parseCallback(event.url);
1440
- processCallback(callback, promise);
1441
- closeBrowser();
1442
- completed = true;
1443
- } else {
1444
- promise.setError();
1445
- closeBrowser();
1446
- }
1447
- }
1448
- });
1449
-
1450
- ref.addEventListener('exit', function(event) {
1451
- if (!closed) {
1452
- promise.setError({
1453
- reason: "closed_by_user"
1454
- });
1455
- }
1456
- });
1457
-
1458
- return promise.promise;
1459
- },
1460
-
1461
- logout: function(options) {
1462
- var promise = createPromise();
1463
-
1464
- var logoutUrl = kc.createLogoutUrl(options);
1465
- var ref = cordovaOpenWindowWrapper(logoutUrl, '_blank', 'location=no,hidden=yes,clearcache=yes');
1466
-
1467
- var error;
1468
-
1469
- ref.addEventListener('loadstart', function(event) {
1470
- if (event.url.indexOf(getCordovaRedirectUri()) == 0) {
1471
- ref.close();
1472
- }
1473
- });
1474
-
1475
- ref.addEventListener('loaderror', function(event) {
1476
- if (event.url.indexOf(getCordovaRedirectUri()) == 0) {
1477
- ref.close();
1478
- } else {
1479
- error = true;
1480
- ref.close();
1481
- }
1482
- });
1483
-
1484
- ref.addEventListener('exit', function(event) {
1485
- if (error) {
1486
- promise.setError();
1487
- } else {
1488
- kc.clearToken();
1489
- promise.setSuccess();
1490
- }
1491
- });
1492
-
1493
- return promise.promise;
1494
- },
1495
-
1496
- register : function(options) {
1497
- var promise = createPromise();
1498
- var registerUrl = kc.createRegisterUrl();
1499
- var cordovaOptions = createCordovaOptions(options);
1500
- var ref = cordovaOpenWindowWrapper(registerUrl, '_blank', cordovaOptions);
1501
- ref.addEventListener('loadstart', function(event) {
1502
- if (event.url.indexOf(getCordovaRedirectUri()) == 0) {
1503
- ref.close();
1504
- var oauth = parseCallback(event.url);
1505
- processCallback(oauth, promise);
1506
- }
1507
- });
1508
- return promise.promise;
1509
- },
1510
-
1511
- accountManagement : function() {
1512
- var accountUrl = kc.createAccountUrl();
1513
- if (typeof accountUrl !== 'undefined') {
1514
- var ref = cordovaOpenWindowWrapper(accountUrl, '_blank', 'location=no');
1515
- ref.addEventListener('loadstart', function(event) {
1516
- if (event.url.indexOf(getCordovaRedirectUri()) == 0) {
1517
- ref.close();
1518
- }
1519
- });
1520
- } else {
1521
- throw "Not supported by the OIDC server";
1522
- }
1523
- },
1524
-
1525
- redirectUri: function(options) {
1526
- return getCordovaRedirectUri();
1527
- }
1847
+ var error;
1848
+
1849
+ ref.addEventListener("loadstart", function (event) {
1850
+ if (event.url.indexOf(getCordovaRedirectUri()) == 0) {
1851
+ ref.close();
1528
1852
  }
1529
- }
1853
+ });
1530
1854
 
1531
- if (type == 'cordova-native') {
1532
- loginIframe.enable = false;
1533
-
1534
- return {
1535
- login: function(options) {
1536
- var promise = createPromise();
1537
- var loginUrl = kc.createLoginUrl(options);
1538
-
1539
- universalLinks.subscribe('keycloak', function(event) {
1540
- universalLinks.unsubscribe('keycloak');
1541
- window.cordova.plugins.browsertab.close();
1542
- var oauth = parseCallback(event.url);
1543
- processCallback(oauth, promise);
1544
- });
1545
-
1546
- window.cordova.plugins.browsertab.openUrl(loginUrl);
1547
- return promise.promise;
1548
- },
1549
-
1550
- logout: function(options) {
1551
- var promise = createPromise();
1552
- var logoutUrl = kc.createLogoutUrl(options);
1553
-
1554
- universalLinks.subscribe('keycloak', function(event) {
1555
- universalLinks.unsubscribe('keycloak');
1556
- window.cordova.plugins.browsertab.close();
1557
- kc.clearToken();
1558
- promise.setSuccess();
1559
- });
1560
-
1561
- window.cordova.plugins.browsertab.openUrl(logoutUrl);
1562
- return promise.promise;
1563
- },
1564
-
1565
- register : function(options) {
1566
- var promise = createPromise();
1567
- var registerUrl = kc.createRegisterUrl(options);
1568
- universalLinks.subscribe('keycloak' , function(event) {
1569
- universalLinks.unsubscribe('keycloak');
1570
- window.cordova.plugins.browsertab.close();
1571
- var oauth = parseCallback(event.url);
1572
- processCallback(oauth, promise);
1573
- });
1574
- window.cordova.plugins.browsertab.openUrl(registerUrl);
1575
- return promise.promise;
1576
-
1577
- },
1578
-
1579
- accountManagement : function() {
1580
- var accountUrl = kc.createAccountUrl();
1581
- if (typeof accountUrl !== 'undefined') {
1582
- window.cordova.plugins.browsertab.openUrl(accountUrl);
1583
- } else {
1584
- throw "Not supported by the OIDC server";
1585
- }
1586
- },
1587
-
1588
- redirectUri: function(options) {
1589
- if (options && options.redirectUri) {
1590
- return options.redirectUri;
1591
- } else if (kc.redirectUri) {
1592
- return kc.redirectUri;
1593
- } else {
1594
- return "http://localhost";
1595
- }
1596
- }
1855
+ ref.addEventListener("loaderror", function (event) {
1856
+ if (event.url.indexOf(getCordovaRedirectUri()) == 0) {
1857
+ ref.close();
1858
+ } else {
1859
+ error = true;
1860
+ ref.close();
1597
1861
  }
1598
- }
1862
+ });
1599
1863
 
1600
- throw 'invalid adapter type: ' + type;
1864
+ ref.addEventListener("exit", function (event) {
1865
+ if (error) {
1866
+ promise.setError();
1867
+ } else {
1868
+ kc.clearToken();
1869
+ promise.setSuccess();
1870
+ }
1871
+ });
1872
+
1873
+ return promise.promise;
1874
+ },
1875
+
1876
+ register: function (options) {
1877
+ var promise = createPromise();
1878
+ var registerUrl = kc.createRegisterUrl();
1879
+ var cordovaOptions = createCordovaOptions(options);
1880
+ var ref = cordovaOpenWindowWrapper(
1881
+ registerUrl,
1882
+ "_blank",
1883
+ cordovaOptions
1884
+ );
1885
+
1886
+ ref.addEventListener("loadstart", function (event) {
1887
+ if (event.url.indexOf(getCordovaRedirectUri()) == 0) {
1888
+ ref.close();
1889
+ var oauth = parseCallback(event.url);
1890
+ processCallback(oauth, promise);
1891
+ }
1892
+ });
1893
+ return promise.promise;
1894
+ },
1895
+
1896
+ accountManagement: function () {
1897
+ var accountUrl = kc.createAccountUrl();
1898
+ if (typeof accountUrl !== "undefined") {
1899
+ var ref = cordovaOpenWindowWrapper(
1900
+ accountUrl,
1901
+ "_blank",
1902
+ "location=no"
1903
+ );
1904
+
1905
+ ref.addEventListener("loadstart", function (event) {
1906
+ if (event.url.indexOf(getCordovaRedirectUri()) == 0) {
1907
+ ref.close();
1908
+ }
1909
+ });
1910
+ } else {
1911
+ throw "Not supported by the OIDC server";
1912
+ }
1913
+ },
1914
+
1915
+ redirectUri: function (options) {
1916
+ return getCordovaRedirectUri();
1917
+ },
1918
+ };
1601
1919
  }
1602
1920
 
1603
- var LocalStorage = function() {
1604
- if (!(this instanceof LocalStorage)) {
1605
- return new LocalStorage();
1606
- }
1921
+ if (type == "cordova-native") {
1922
+ loginIframe.enable = false;
1923
+
1924
+ return {
1925
+ login: function (options) {
1926
+ var promise = createPromise();
1927
+ var loginUrl = kc.createLoginUrl(options);
1928
+
1929
+ universalLinks.subscribe("keycloak", function (event) {
1930
+ universalLinks.unsubscribe("keycloak");
1931
+ window.cordova.plugins.browsertab.close();
1932
+ var oauth = parseCallback(event.url);
1933
+ processCallback(oauth, promise);
1934
+ });
1935
+
1936
+ window.cordova.plugins.browsertab.openUrl(loginUrl);
1937
+ return promise.promise;
1938
+ },
1939
+
1940
+ logout: function (options) {
1941
+ var promise = createPromise();
1942
+ var logoutUrl = kc.createLogoutUrl(options);
1943
+
1944
+ universalLinks.subscribe("keycloak", function (event) {
1945
+ universalLinks.unsubscribe("keycloak");
1946
+ window.cordova.plugins.browsertab.close();
1947
+ kc.clearToken();
1948
+ promise.setSuccess();
1949
+ });
1950
+
1951
+ window.cordova.plugins.browsertab.openUrl(logoutUrl);
1952
+ return promise.promise;
1953
+ },
1954
+
1955
+ register: function (options) {
1956
+ var promise = createPromise();
1957
+ var registerUrl = kc.createRegisterUrl(options);
1958
+ universalLinks.subscribe("keycloak", function (event) {
1959
+ universalLinks.unsubscribe("keycloak");
1960
+ window.cordova.plugins.browsertab.close();
1961
+ var oauth = parseCallback(event.url);
1962
+ processCallback(oauth, promise);
1963
+ });
1964
+ window.cordova.plugins.browsertab.openUrl(registerUrl);
1965
+ return promise.promise;
1966
+ },
1967
+
1968
+ accountManagement: function () {
1969
+ var accountUrl = kc.createAccountUrl();
1970
+ if (typeof accountUrl !== "undefined") {
1971
+ window.cordova.plugins.browsertab.openUrl(accountUrl);
1972
+ } else {
1973
+ throw "Not supported by the OIDC server";
1974
+ }
1975
+ },
1976
+
1977
+ redirectUri: function (options) {
1978
+ if (options && options.redirectUri) {
1979
+ return options.redirectUri;
1980
+ } else if (kc.redirectUri) {
1981
+ return kc.redirectUri;
1982
+ } else {
1983
+ return "http://localhost";
1984
+ }
1985
+ },
1986
+ };
1987
+ }
1607
1988
 
1608
- localStorage.setItem('kc-test', 'test');
1609
- localStorage.removeItem('kc-test');
1610
-
1611
- var cs = this;
1612
-
1613
- function clearExpired() {
1614
- var time = new Date().getTime();
1615
- for (var i = 0; i < localStorage.length; i++) {
1616
- var key = localStorage.key(i);
1617
- if (key && key.indexOf('kc-callback-') == 0) {
1618
- var value = localStorage.getItem(key);
1619
- if (value) {
1620
- try {
1621
- var expires = JSON.parse(value).expires;
1622
- if (!expires || expires < time) {
1623
- localStorage.removeItem(key);
1624
- }
1625
- } catch (err) {
1626
- localStorage.removeItem(key);
1627
- }
1628
- }
1629
- }
1630
- }
1631
- }
1989
+ throw "invalid adapter type: " + type;
1990
+ }
1632
1991
 
1633
- cs.get = function(state) {
1634
- if (!state) {
1635
- return;
1636
- }
1992
+ var LocalStorage = function () {
1993
+ if (!(this instanceof LocalStorage)) {
1994
+ return new LocalStorage();
1995
+ }
1637
1996
 
1638
- var key = 'kc-callback-' + state;
1639
- var value = localStorage.getItem(key);
1640
- if (value) {
1997
+ localStorage.setItem("kc-test", "test");
1998
+ localStorage.removeItem("kc-test");
1999
+
2000
+ var cs = this;
2001
+
2002
+ function clearExpired() {
2003
+ var time = new Date().getTime();
2004
+ for (var i = 0; i < localStorage.length; i++) {
2005
+ var key = localStorage.key(i);
2006
+ if (key && key.indexOf("kc-callback-") == 0) {
2007
+ var value = localStorage.getItem(key);
2008
+ if (value) {
2009
+ try {
2010
+ var expires = JSON.parse(value).expires;
2011
+ if (!expires || expires < time) {
1641
2012
  localStorage.removeItem(key);
1642
- value = JSON.parse(value);
2013
+ }
2014
+ } catch (err) {
2015
+ localStorage.removeItem(key);
1643
2016
  }
2017
+ }
2018
+ }
2019
+ }
2020
+ }
1644
2021
 
1645
- clearExpired();
1646
- return value;
1647
- };
2022
+ cs.get = function (state) {
2023
+ if (!state) {
2024
+ return;
2025
+ }
1648
2026
 
1649
- cs.add = function(state) {
1650
- clearExpired();
2027
+ var key = "kc-callback-" + state;
2028
+ var value = localStorage.getItem(key);
2029
+ if (value) {
2030
+ localStorage.removeItem(key);
2031
+ value = JSON.parse(value);
2032
+ }
1651
2033
 
1652
- var key = 'kc-callback-' + state.state;
1653
- state.expires = new Date().getTime() + (60 * 60 * 1000);
1654
- localStorage.setItem(key, JSON.stringify(state));
1655
- };
2034
+ clearExpired();
2035
+ return value;
1656
2036
  };
1657
2037
 
1658
- var CookieStorage = function() {
1659
- if (!(this instanceof CookieStorage)) {
1660
- return new CookieStorage();
1661
- }
2038
+ cs.add = function (state) {
2039
+ clearExpired();
1662
2040
 
1663
- var cs = this;
2041
+ var key = "kc-callback-" + state.state;
2042
+ state.expires = new Date().getTime() + 60 * 60 * 1000;
2043
+ localStorage.setItem(key, JSON.stringify(state));
2044
+ };
2045
+ };
1664
2046
 
1665
- cs.get = function(state) {
1666
- if (!state) {
1667
- return;
1668
- }
2047
+ var CookieStorage = function () {
2048
+ if (!(this instanceof CookieStorage)) {
2049
+ return new CookieStorage();
2050
+ }
1669
2051
 
1670
- var value = getCookie('kc-callback-' + state);
1671
- setCookie('kc-callback-' + state, '', cookieExpiration(-100));
1672
- if (value) {
1673
- return JSON.parse(value);
1674
- }
1675
- };
2052
+ var cs = this;
1676
2053
 
1677
- cs.add = function(state) {
1678
- setCookie('kc-callback-' + state.state, JSON.stringify(state), cookieExpiration(60));
1679
- };
2054
+ cs.get = function (state) {
2055
+ if (!state) {
2056
+ return;
2057
+ }
1680
2058
 
1681
- cs.removeItem = function(key) {
1682
- setCookie(key, '', cookieExpiration(-100));
1683
- };
2059
+ var value = getCookie("kc-callback-" + state);
2060
+ setCookie("kc-callback-" + state, "", cookieExpiration(-100));
2061
+ if (value) {
2062
+ return JSON.parse(value);
2063
+ }
2064
+ };
1684
2065
 
1685
- var cookieExpiration = function (minutes) {
1686
- var exp = new Date();
1687
- exp.setTime(exp.getTime() + (minutes*60*1000));
1688
- return exp;
1689
- };
2066
+ cs.add = function (state) {
2067
+ setCookie(
2068
+ "kc-callback-" + state.state,
2069
+ JSON.stringify(state),
2070
+ cookieExpiration(60)
2071
+ );
2072
+ };
1690
2073
 
1691
- var getCookie = function (key) {
1692
- var name = key + '=';
1693
- var ca = document.cookie.split(';');
1694
- for (var i = 0; i < ca.length; i++) {
1695
- var c = ca[i];
1696
- while (c.charAt(0) == ' ') {
1697
- c = c.substring(1);
1698
- }
1699
- if (c.indexOf(name) == 0) {
1700
- return c.substring(name.length, c.length);
1701
- }
1702
- }
1703
- return '';
1704
- };
2074
+ cs.removeItem = function (key) {
2075
+ setCookie(key, "", cookieExpiration(-100));
2076
+ };
1705
2077
 
1706
- var setCookie = function (key, value, expirationDate) {
1707
- var cookie = key + '=' + value + '; '
1708
- + 'expires=' + expirationDate.toUTCString() + '; ';
1709
- document.cookie = cookie;
1710
- }
2078
+ var cookieExpiration = function (minutes) {
2079
+ var exp = new Date();
2080
+ exp.setTime(exp.getTime() + minutes * 60 * 1000);
2081
+ return exp;
1711
2082
  };
1712
2083
 
1713
- function createCallbackStorage() {
1714
- try {
1715
- return new LocalStorage();
1716
- } catch (err) {
2084
+ var getCookie = function (key) {
2085
+ var name = key + "=";
2086
+ var ca = document.cookie.split(";");
2087
+ for (var i = 0; i < ca.length; i++) {
2088
+ var c = ca[i];
2089
+ while (c.charAt(0) == " ") {
2090
+ c = c.substring(1);
1717
2091
  }
2092
+ if (c.indexOf(name) == 0) {
2093
+ return c.substring(name.length, c.length);
2094
+ }
2095
+ }
2096
+ return "";
2097
+ };
1718
2098
 
1719
- return new CookieStorage();
1720
- }
2099
+ var setCookie = function (key, value, expirationDate) {
2100
+ var cookie =
2101
+ key +
2102
+ "=" +
2103
+ value +
2104
+ "; " +
2105
+ "expires=" +
2106
+ expirationDate.toUTCString() +
2107
+ "; ";
2108
+
2109
+ document.cookie = cookie;
2110
+ };
2111
+ };
1721
2112
 
1722
- function createLogger(fn) {
1723
- return function() {
1724
- if (kc.enableLogging) {
1725
- fn.apply(console, Array.prototype.slice.call(arguments));
1726
- }
1727
- };
1728
- }
2113
+ function createCallbackStorage() {
2114
+ try {
2115
+ return new LocalStorage();
2116
+ } catch (err) {}
2117
+
2118
+ return new CookieStorage();
2119
+ }
2120
+
2121
+ function createLogger(fn) {
2122
+ return function () {
2123
+ if (kc.enableLogging) {
2124
+ fn.apply(console, Array.prototype.slice.call(arguments));
2125
+ }
2126
+ };
2127
+ }
1729
2128
  }
1730
2129
 
1731
- export default Keycloak;
2130
+ export default Keycloak;
2131
+
2132
+ // See: https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem
2133
+ function bytesToBase64(bytes) {
2134
+ const binString = String.fromCodePoint(...bytes);
2135
+ return btoa(binString);
2136
+ }