@tidecloak/js 0.13.14 → 0.13.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/lib/tidecloak-dpop.js +481 -0
- package/dist/cjs/lib/tidecloak-dpop.js.map +1 -0
- package/dist/cjs/lib/tidecloak.js +642 -484
- package/dist/cjs/lib/tidecloak.js.map +1 -1
- package/dist/cjs/src/IAMService.js +137 -6
- package/dist/cjs/src/IAMService.js.map +1 -1
- package/dist/esm/lib/tidecloak-dpop.js +481 -0
- package/dist/esm/lib/tidecloak-dpop.js.map +1 -0
- package/dist/esm/lib/tidecloak.js +642 -484
- package/dist/esm/lib/tidecloak.js.map +1 -1
- package/dist/esm/src/IAMService.js +137 -6
- package/dist/esm/src/IAMService.js.map +1 -1
- package/dist/types/IAMService.d.ts +31 -0
- package/dist/types/lib/tidecloak-dpop.d.ts +53 -0
- package/dist/types/lib/tidecloak.d.ts +78 -94
- package/dist/types/src/IAMService.d.ts +31 -0
- package/package.json +2 -2
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import {Acr, TideCloakAccountOptions, TideCloakAdapter, TideCloakConfig, TideCloakError, TideCloakFlow, TideCloakInitOptions, TideCloakLoginOptions, TideCloakLogoutOptions, TideCloakPkceMethod, TideCloakProfile, TideCloakRegisterOptions, TideCloakResourceAccess, TideCloakResponseMode, TideCloakResponseType, TideCloakRoles, TideCloakTokenParsed, OpenIdProviderMetadata} from "./tidecloak.js"
|
|
3
|
+
*/
|
|
1
4
|
/*
|
|
2
5
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
3
6
|
* and other contributors as indicated by the @author tags.
|
|
@@ -33,7 +36,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
|
|
|
33
36
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
34
37
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
35
38
|
};
|
|
36
|
-
var _TideCloak_instances, _TideCloak_refreshQueue, _TideCloak_adapter, _TideCloak_useNonce, _TideCloak_callbackStorage, _TideCloak_logInfo, _TideCloak_logWarn, _TideCloak_loginIframe, _TideCloak_config, _TideCloak_loadAdapter, _TideCloak_loadDefaultAdapter, _TideCloak_loadCordovaAdapter, _TideCloak_loadCordovaNativeAdapter, _TideCloak_loadConfig, _TideCloak_setupEndpoints, _TideCloak_loadOidcConfig, _TideCloak_setupOidcEndpoints, _TideCloak_check3pCookiesSupported, _TideCloak_processInit, _TideCloak_setupCheckLoginIframe, _TideCloak_checkLoginIframe, _TideCloak_checkSsoSilently, _TideCloak_parseCallback, _TideCloak_parseCallbackUrl, _TideCloak_parseCallbackParams, _TideCloak_processCallback, _TideCloak_scheduleCheckIframe, _TideCloak_getVoucherUrl, _TideCloak_setToken, _TideCloak_getRealmUrl, _TideCloak_createLogger, _LocalStorage_instances, _LocalStorage_clearInvalidValues, _LocalStorage_clearAllValues, _LocalStorage_getStoredEntries, _LocalStorage_parseExpiry, _CookieStorage_instances, _CookieStorage_getCookie, _CookieStorage_setCookie, _CookieStorage_cookieExpiration;
|
|
39
|
+
var _TideCloak_instances, _TideCloak_refreshQueue, _TideCloak_adapter, _TideCloak_useNonce, _TideCloak_callbackStorage, _TideCloak_logInfo, _TideCloak_logWarn, _TideCloak_loginIframe, _TideCloak_dpopProvider, _TideCloak_config, _TideCloak_loadAdapter, _TideCloak_loadDefaultAdapter, _TideCloak_loadCordovaAdapter, _TideCloak_loadCordovaNativeAdapter, _TideCloak_loadConfig, _TideCloak_setupEndpoints, _TideCloak_loadOidcConfig, _TideCloak_setupOidcEndpoints, _TideCloak_getIssuerUrl, _TideCloak_check3pCookiesSupported, _TideCloak_processInit, _TideCloak_setupCheckLoginIframe, _TideCloak_checkLoginIframe, _TideCloak_checkSsoSilently, _TideCloak_parseCallback, _TideCloak_parseCallbackUrl, _TideCloak_parseCallbackParams, _TideCloak_processCallback, _TideCloak_scheduleCheckIframe, _TideCloak_fetchAccessToken, _TideCloak_fetchRefreshToken, _TideCloak_ensureRequestEnclaveOpen, _TideCloak_getVoucherUrl, _TideCloak_setToken, _TideCloak_getRealmUrl, _TideCloak_createLogger, _LocalStorage_instances, _LocalStorage_clearInvalidValues, _LocalStorage_clearAllValues, _LocalStorage_getStoredEntries, _LocalStorage_parseExpiry, _CookieStorage_instances, _CookieStorage_getCookie, _CookieStorage_setCookie, _CookieStorage_cookieExpiration;
|
|
37
40
|
// MODIFIED: Added dependency to external Tide helper libraries.
|
|
38
41
|
import { RequestEnclave, ApprovalEnclave, ApprovalEnclaveNew } from "heimdall-tide";
|
|
39
42
|
const CONTENT_TYPE_JSON = 'application/json';
|
|
@@ -58,15 +61,15 @@ const CONTENT_TYPE_JSON = 'application/json';
|
|
|
58
61
|
export { RequestEnclave, ApprovalEnclave, ApprovalEnclaveNew, TideMemory, BaseTideRequest, PolicySignRequest, Policy, PolicyParameters } from "heimdall-tide";
|
|
59
62
|
class TideCloak {
|
|
60
63
|
/**
|
|
61
|
-
* @param {
|
|
64
|
+
* @param {TideCloakConfig} config
|
|
62
65
|
*/
|
|
63
66
|
constructor(config) {
|
|
64
67
|
_TideCloak_instances.add(this);
|
|
65
68
|
/** @type {Pick<PromiseWithResolvers<boolean>, 'resolve' | 'reject'>[]} */
|
|
66
69
|
_TideCloak_refreshQueue.set(this, []
|
|
67
|
-
/** @type {
|
|
70
|
+
/** @type {TideCloakAdapter} */
|
|
68
71
|
);
|
|
69
|
-
/** @type {
|
|
72
|
+
/** @type {TideCloakAdapter} */
|
|
70
73
|
_TideCloak_adapter.set(this, void 0);
|
|
71
74
|
/** @type {boolean} */
|
|
72
75
|
_TideCloak_useNonce.set(this, true
|
|
@@ -84,40 +87,501 @@ class TideCloak {
|
|
|
84
87
|
callbackList: [],
|
|
85
88
|
interval: 5
|
|
86
89
|
}
|
|
87
|
-
/** @type {
|
|
90
|
+
/** @type {import('./tidecloak-dpop.js').DPoPSignatureProvider=} */
|
|
88
91
|
);
|
|
89
|
-
/** @type {
|
|
92
|
+
/** @type {import('./tidecloak-dpop.js').DPoPSignatureProvider=} */
|
|
93
|
+
_TideCloak_dpopProvider.set(this, void 0);
|
|
94
|
+
/** @type {TideCloakConfig} config */
|
|
90
95
|
_TideCloak_config.set(this, void 0);
|
|
91
96
|
this.didInitialize = false;
|
|
92
97
|
this.authenticated = false;
|
|
93
98
|
this.loginRequired = false;
|
|
94
|
-
/** @type {
|
|
99
|
+
/** @type {TideCloakResponseMode} */
|
|
95
100
|
this.responseMode = 'fragment';
|
|
96
|
-
/** @type {
|
|
101
|
+
/** @type {TideCloakResponseType} */
|
|
97
102
|
this.responseType = 'code';
|
|
98
|
-
/** @type {
|
|
103
|
+
/** @type {TideCloakFlow} */
|
|
99
104
|
this.flow = 'standard';
|
|
105
|
+
/** @type {number?} */
|
|
106
|
+
this.timeSkew = null;
|
|
100
107
|
/** @type {boolean} */
|
|
101
108
|
this.silentCheckSsoFallback = true;
|
|
102
|
-
/** @type {
|
|
109
|
+
/** @type {TideCloakPkceMethod} */
|
|
103
110
|
this.pkceMethod = 'S256';
|
|
104
111
|
this.enableLogging = false;
|
|
105
112
|
/** @type {'GET' | 'POST'} */
|
|
106
113
|
this.logoutMethod = 'GET';
|
|
107
114
|
this.messageReceiveTimeout = 10000;
|
|
115
|
+
/**
|
|
116
|
+
* @param {TideCloakInitOptions} initOptions
|
|
117
|
+
* @returns {Promise<boolean>}
|
|
118
|
+
*/
|
|
119
|
+
this.init = async (initOptions = {}) => {
|
|
120
|
+
var _a, _b, _c;
|
|
121
|
+
if (this.didInitialize) {
|
|
122
|
+
throw new Error("A 'TideCloak' instance can only be initialized once.");
|
|
123
|
+
}
|
|
124
|
+
this.didInitialize = true;
|
|
125
|
+
__classPrivateFieldSet(this, _TideCloak_callbackStorage, createCallbackStorage(), "f");
|
|
126
|
+
const adapters = ['default', 'cordova', 'cordova-native'];
|
|
127
|
+
if (typeof initOptions.adapter === 'string' && adapters.includes(initOptions.adapter)) {
|
|
128
|
+
__classPrivateFieldSet(this, _TideCloak_adapter, __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_loadAdapter).call(this, initOptions.adapter), "f");
|
|
129
|
+
}
|
|
130
|
+
else if (typeof initOptions.adapter === 'object') {
|
|
131
|
+
__classPrivateFieldSet(this, _TideCloak_adapter, initOptions.adapter, "f");
|
|
132
|
+
}
|
|
133
|
+
else if ('Cordova' in window || 'cordova' in window) {
|
|
134
|
+
__classPrivateFieldSet(this, _TideCloak_adapter, __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_loadAdapter).call(this, 'cordova'), "f");
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
__classPrivateFieldSet(this, _TideCloak_adapter, __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_loadAdapter).call(this, 'default'), "f");
|
|
138
|
+
}
|
|
139
|
+
if (typeof initOptions.useNonce !== 'undefined') {
|
|
140
|
+
__classPrivateFieldSet(this, _TideCloak_useNonce, initOptions.useNonce, "f");
|
|
141
|
+
}
|
|
142
|
+
if (typeof initOptions.checkLoginIframe !== 'undefined') {
|
|
143
|
+
__classPrivateFieldGet(this, _TideCloak_loginIframe, "f").enable = initOptions.checkLoginIframe;
|
|
144
|
+
}
|
|
145
|
+
if (initOptions.checkLoginIframeInterval) {
|
|
146
|
+
__classPrivateFieldGet(this, _TideCloak_loginIframe, "f").interval = initOptions.checkLoginIframeInterval;
|
|
147
|
+
}
|
|
148
|
+
if (initOptions.onLoad === 'login-required') {
|
|
149
|
+
this.loginRequired = true;
|
|
150
|
+
}
|
|
151
|
+
if (initOptions.responseMode) {
|
|
152
|
+
if (initOptions.responseMode === 'query' || initOptions.responseMode === 'fragment') {
|
|
153
|
+
this.responseMode = initOptions.responseMode;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
throw new Error('Invalid value for responseMode');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (initOptions.flow) {
|
|
160
|
+
switch (initOptions.flow) {
|
|
161
|
+
case 'standard':
|
|
162
|
+
this.responseType = 'code';
|
|
163
|
+
break;
|
|
164
|
+
case 'implicit':
|
|
165
|
+
this.responseType = 'id_token token';
|
|
166
|
+
break;
|
|
167
|
+
case 'hybrid':
|
|
168
|
+
this.responseType = 'code id_token token';
|
|
169
|
+
break;
|
|
170
|
+
default:
|
|
171
|
+
throw new Error('Invalid value for flow');
|
|
172
|
+
}
|
|
173
|
+
this.flow = initOptions.flow;
|
|
174
|
+
}
|
|
175
|
+
if (typeof initOptions.timeSkew === 'number') {
|
|
176
|
+
this.timeSkew = initOptions.timeSkew;
|
|
177
|
+
}
|
|
178
|
+
if (initOptions.redirectUri) {
|
|
179
|
+
this.redirectUri = initOptions.redirectUri;
|
|
180
|
+
}
|
|
181
|
+
if (initOptions.silentCheckSsoRedirectUri) {
|
|
182
|
+
this.silentCheckSsoRedirectUri = initOptions.silentCheckSsoRedirectUri;
|
|
183
|
+
}
|
|
184
|
+
if (typeof initOptions.silentCheckSsoFallback === 'boolean') {
|
|
185
|
+
this.silentCheckSsoFallback = initOptions.silentCheckSsoFallback;
|
|
186
|
+
}
|
|
187
|
+
if (typeof initOptions.pkceMethod !== 'undefined') {
|
|
188
|
+
if (initOptions.pkceMethod !== 'S256' && initOptions.pkceMethod !== false) {
|
|
189
|
+
throw new TypeError(`Invalid value for pkceMethod', expected 'S256' or false but got ${initOptions.pkceMethod}.`);
|
|
190
|
+
}
|
|
191
|
+
this.pkceMethod = initOptions.pkceMethod;
|
|
192
|
+
}
|
|
193
|
+
if (typeof initOptions.enableLogging === 'boolean') {
|
|
194
|
+
this.enableLogging = initOptions.enableLogging;
|
|
195
|
+
}
|
|
196
|
+
if (initOptions.logoutMethod === 'POST') {
|
|
197
|
+
this.logoutMethod = 'POST';
|
|
198
|
+
}
|
|
199
|
+
if (typeof initOptions.scope === 'string') {
|
|
200
|
+
this.scope = initOptions.scope;
|
|
201
|
+
}
|
|
202
|
+
if (typeof initOptions.messageReceiveTimeout === 'number' && initOptions.messageReceiveTimeout > 0) {
|
|
203
|
+
this.messageReceiveTimeout = initOptions.messageReceiveTimeout;
|
|
204
|
+
}
|
|
205
|
+
if (initOptions.useDPoP) {
|
|
206
|
+
this.useDPoP = initOptions.useDPoP;
|
|
207
|
+
}
|
|
208
|
+
await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_loadConfig).call(this);
|
|
209
|
+
if (((_a = this.useDPoP) === null || _a === void 0 ? void 0 : _a.mode) === 'strict' && (!this.dpopSigningAlgValuesSupported || this.dpopSigningAlgValuesSupported.length === 0)) {
|
|
210
|
+
throw new Error('DPoP is set to strict mode but the server does not advertise DPoP support (dpop_signing_alg_values_supported is missing or empty).');
|
|
211
|
+
}
|
|
212
|
+
// Initialize DPoP if enabled and server supports it
|
|
213
|
+
if (this.useDPoP && ((_b = this.dpopSigningAlgValuesSupported) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
214
|
+
const issuerUrl = __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_getIssuerUrl).call(this);
|
|
215
|
+
if (!issuerUrl)
|
|
216
|
+
throw new Error('Cannot initialize DPoP: issuer URL is not available. Ensure authServerUrl and realm are configured, or use OIDC provider mode with a valid issuer.');
|
|
217
|
+
if (!this.clientId)
|
|
218
|
+
throw new Error('Cannot initialize DPoP: clientId is not configured.');
|
|
219
|
+
const { DPoPSignatureProvider, BrowserSignatureAlgs } = await import('./tidecloak-dpop.js');
|
|
220
|
+
__classPrivateFieldSet(this, _TideCloak_dpopProvider, new DPoPSignatureProvider({
|
|
221
|
+
issuerUrl: new URL(issuerUrl),
|
|
222
|
+
clientId: this.clientId,
|
|
223
|
+
serverSupportedAlgorithms: this.dpopSigningAlgValuesSupported,
|
|
224
|
+
requestedAlgorithm: !this.useDPoP.alg ? BrowserSignatureAlgs.ES256 : BrowserSignatureAlgs[this.useDPoP.alg]
|
|
225
|
+
}), "f");
|
|
226
|
+
await __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f").init();
|
|
227
|
+
__classPrivateFieldGet(this, _TideCloak_logInfo, "f").call(this, '[TIDECLOAK] DPoP initialized');
|
|
228
|
+
}
|
|
229
|
+
await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_check3pCookiesSupported).call(this);
|
|
230
|
+
await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_processInit).call(this, initOptions);
|
|
231
|
+
(_c = this.onReady) === null || _c === void 0 ? void 0 : _c.call(this, this.authenticated);
|
|
232
|
+
// initialize request enclave if authenticated
|
|
233
|
+
if (this.token)
|
|
234
|
+
this.initRequestEnclave();
|
|
235
|
+
// to get around popups requiring user gestures
|
|
236
|
+
document.addEventListener('click', () => {
|
|
237
|
+
__classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_ensureRequestEnclaveOpen).call(this);
|
|
238
|
+
});
|
|
239
|
+
return this.authenticated;
|
|
240
|
+
};
|
|
241
|
+
/**
|
|
242
|
+
* @param {TideCloakLoginOptions} [options]
|
|
243
|
+
* @returns {Promise<void>}
|
|
244
|
+
*/
|
|
245
|
+
this.login = (options) => {
|
|
246
|
+
return __classPrivateFieldGet(this, _TideCloak_adapter, "f").login(options);
|
|
247
|
+
};
|
|
248
|
+
/**
|
|
249
|
+
* @param {TideCloakLoginOptions} [options]
|
|
250
|
+
* @returns {Promise<string>}
|
|
251
|
+
*/
|
|
252
|
+
this.createLoginUrl = async (options) => {
|
|
253
|
+
const state = createUUID();
|
|
254
|
+
const nonce = createUUID();
|
|
255
|
+
const redirectUri = __classPrivateFieldGet(this, _TideCloak_adapter, "f").redirectUri(options);
|
|
256
|
+
/** @type {CallbackState} */
|
|
257
|
+
const callbackState = {
|
|
258
|
+
state,
|
|
259
|
+
nonce,
|
|
260
|
+
redirectUri,
|
|
261
|
+
loginOptions: options
|
|
262
|
+
};
|
|
263
|
+
if (options === null || options === void 0 ? void 0 : options.prompt) {
|
|
264
|
+
callbackState.prompt = options.prompt;
|
|
265
|
+
}
|
|
266
|
+
const url = (options === null || options === void 0 ? void 0 : options.action) === 'register'
|
|
267
|
+
? this.endpoints.register()
|
|
268
|
+
: this.endpoints.authorize();
|
|
269
|
+
let scope = (options === null || options === void 0 ? void 0 : options.scope) || this.scope;
|
|
270
|
+
const scopeValues = scope ? scope.split(' ') : [];
|
|
271
|
+
// Ensure the 'openid' scope is always included.
|
|
272
|
+
if (!scopeValues.includes('openid')) {
|
|
273
|
+
scopeValues.unshift('openid');
|
|
274
|
+
}
|
|
275
|
+
scope = scopeValues.join(' ');
|
|
276
|
+
const params = new URLSearchParams([
|
|
277
|
+
['client_id', /** @type {string} */ (this.clientId)],
|
|
278
|
+
['redirect_uri', redirectUri],
|
|
279
|
+
['state', state],
|
|
280
|
+
['response_mode', this.responseMode],
|
|
281
|
+
['response_type', this.responseType],
|
|
282
|
+
['scope', scope]
|
|
283
|
+
]);
|
|
284
|
+
if (__classPrivateFieldGet(this, _TideCloak_useNonce, "f")) {
|
|
285
|
+
params.append('nonce', nonce);
|
|
286
|
+
}
|
|
287
|
+
if (options === null || options === void 0 ? void 0 : options.prompt) {
|
|
288
|
+
params.append('prompt', options.prompt);
|
|
289
|
+
}
|
|
290
|
+
if (typeof (options === null || options === void 0 ? void 0 : options.maxAge) === 'number') {
|
|
291
|
+
params.append('max_age', options.maxAge.toString());
|
|
292
|
+
}
|
|
293
|
+
if (options === null || options === void 0 ? void 0 : options.loginHint) {
|
|
294
|
+
params.append('login_hint', options.loginHint);
|
|
295
|
+
}
|
|
296
|
+
if (options === null || options === void 0 ? void 0 : options.idpHint) {
|
|
297
|
+
params.append('kc_idp_hint', options.idpHint);
|
|
298
|
+
}
|
|
299
|
+
if ((options === null || options === void 0 ? void 0 : options.action) && options.action !== 'register') {
|
|
300
|
+
params.append('kc_action', options.action);
|
|
301
|
+
}
|
|
302
|
+
if (options === null || options === void 0 ? void 0 : options.locale) {
|
|
303
|
+
params.append('ui_locales', options.locale);
|
|
304
|
+
}
|
|
305
|
+
if (options === null || options === void 0 ? void 0 : options.acr) {
|
|
306
|
+
params.append('claims', buildClaimsParameter(options.acr));
|
|
307
|
+
}
|
|
308
|
+
if (options === null || options === void 0 ? void 0 : options.acrValues) {
|
|
309
|
+
params.append('acr_values', options.acrValues);
|
|
310
|
+
}
|
|
311
|
+
if (this.pkceMethod) {
|
|
312
|
+
try {
|
|
313
|
+
const codeVerifier = generateCodeVerifier(96);
|
|
314
|
+
const pkceChallenge = await generatePkceChallenge(this.pkceMethod, codeVerifier);
|
|
315
|
+
callbackState.pkceCodeVerifier = codeVerifier;
|
|
316
|
+
params.append('code_challenge', pkceChallenge);
|
|
317
|
+
params.append('code_challenge_method', this.pkceMethod);
|
|
318
|
+
}
|
|
319
|
+
catch (error) {
|
|
320
|
+
throw new Error('Failed to generate PKCE challenge.', { cause: error });
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
__classPrivateFieldGet(this, _TideCloak_callbackStorage, "f").add(callbackState);
|
|
324
|
+
return `${url}?${params.toString()}`;
|
|
325
|
+
};
|
|
326
|
+
/**
|
|
327
|
+
* @param {TideCloakLogoutOptions} [options]
|
|
328
|
+
* @returns {Promise<void>}
|
|
329
|
+
*/
|
|
330
|
+
this.logout = async (options) => {
|
|
331
|
+
var _a;
|
|
332
|
+
await ((_a = __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f")) === null || _a === void 0 ? void 0 : _a.flush());
|
|
333
|
+
return __classPrivateFieldGet(this, _TideCloak_adapter, "f").logout(options);
|
|
334
|
+
};
|
|
335
|
+
/**
|
|
336
|
+
* @param {TideCloakLogoutOptions} [options]
|
|
337
|
+
* @returns {string}
|
|
338
|
+
*/
|
|
339
|
+
this.createLogoutUrl = (options) => {
|
|
340
|
+
var _a;
|
|
341
|
+
const logoutMethod = (_a = options === null || options === void 0 ? void 0 : options.logoutMethod) !== null && _a !== void 0 ? _a : this.logoutMethod;
|
|
342
|
+
const url = this.endpoints.logout();
|
|
343
|
+
if (logoutMethod === 'POST') {
|
|
344
|
+
return url;
|
|
345
|
+
}
|
|
346
|
+
const params = new URLSearchParams([
|
|
347
|
+
['client_id', /** @type {string} */ (this.clientId)],
|
|
348
|
+
['post_logout_redirect_uri', __classPrivateFieldGet(this, _TideCloak_adapter, "f").redirectUri(options)]
|
|
349
|
+
]);
|
|
350
|
+
if (this.idToken) {
|
|
351
|
+
params.append('id_token_hint', this.idToken);
|
|
352
|
+
}
|
|
353
|
+
return `${url}?${params.toString()}`;
|
|
354
|
+
};
|
|
355
|
+
/**
|
|
356
|
+
* @param {TideCloakRegisterOptions} [options]
|
|
357
|
+
* @returns {Promise<void>}
|
|
358
|
+
*/
|
|
359
|
+
this.register = (options) => {
|
|
360
|
+
return __classPrivateFieldGet(this, _TideCloak_adapter, "f").register(options);
|
|
361
|
+
};
|
|
362
|
+
/**
|
|
363
|
+
* @param {TideCloakRegisterOptions} [options]
|
|
364
|
+
* @returns {Promise<string>}
|
|
365
|
+
*/
|
|
366
|
+
this.createRegisterUrl = (options) => {
|
|
367
|
+
return this.createLoginUrl({ ...options, action: 'register' });
|
|
368
|
+
};
|
|
369
|
+
/**
|
|
370
|
+
* @param {TideCloakAccountOptions} [options]
|
|
371
|
+
* @returns {string}
|
|
372
|
+
*/
|
|
373
|
+
this.createAccountUrl = (options) => {
|
|
374
|
+
const url = __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_getRealmUrl).call(this);
|
|
375
|
+
if (!url) {
|
|
376
|
+
throw new Error('Unable to create account URL, make sure the adapter is not configured using a generic OIDC provider.');
|
|
377
|
+
}
|
|
378
|
+
const params = new URLSearchParams([
|
|
379
|
+
['referrer', /** @type {string} */ (this.clientId)],
|
|
380
|
+
['referrer_uri', __classPrivateFieldGet(this, _TideCloak_adapter, "f").redirectUri(options)]
|
|
381
|
+
]);
|
|
382
|
+
return `${url}/account?${params.toString()}`;
|
|
383
|
+
};
|
|
384
|
+
/**
|
|
385
|
+
* @returns {Promise<void>}
|
|
386
|
+
*/
|
|
387
|
+
this.accountManagement = () => {
|
|
388
|
+
return __classPrivateFieldGet(this, _TideCloak_adapter, "f").accountManagement();
|
|
389
|
+
};
|
|
390
|
+
/**
|
|
391
|
+
* @param {string} role
|
|
392
|
+
* @returns {boolean}
|
|
393
|
+
*/
|
|
394
|
+
this.hasRealmRole = (role) => {
|
|
395
|
+
const access = this.realmAccess;
|
|
396
|
+
return !!access && access.roles.indexOf(role) >= 0;
|
|
397
|
+
};
|
|
398
|
+
/**
|
|
399
|
+
* @param {string} role
|
|
400
|
+
* @param {string} [resource]
|
|
401
|
+
* @returns {boolean}
|
|
402
|
+
*/
|
|
403
|
+
this.hasResourceRole = (role, resource) => {
|
|
404
|
+
if (!this.resourceAccess) {
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
const access = this.resourceAccess[resource || /** @type {string} */ (this.clientId)];
|
|
408
|
+
return !!access && access.roles.indexOf(role) >= 0;
|
|
409
|
+
};
|
|
410
|
+
/**
|
|
411
|
+
* @returns {Promise<TideCloakProfile>}
|
|
412
|
+
*/
|
|
413
|
+
this.loadUserProfile = async () => {
|
|
414
|
+
const realmUrl = __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_getRealmUrl).call(this);
|
|
415
|
+
if (!realmUrl) {
|
|
416
|
+
throw new Error('Unable to load user profile, make sure the adapter is not configured using a generic OIDC provider.');
|
|
417
|
+
}
|
|
418
|
+
const url = `${realmUrl}/account`;
|
|
419
|
+
/** @type {TideCloakProfile} */
|
|
420
|
+
const profile = await fetchJSON(url, {
|
|
421
|
+
headers: [buildAuthorizationHeader(this.token)]
|
|
422
|
+
});
|
|
423
|
+
return (this.profile = profile);
|
|
424
|
+
};
|
|
425
|
+
/**
|
|
426
|
+
* @returns {Promise<{}>}
|
|
427
|
+
*/
|
|
428
|
+
this.loadUserInfo = async () => {
|
|
429
|
+
const url = this.endpoints.userinfo();
|
|
430
|
+
/** @type {{}} */
|
|
431
|
+
const userInfo = await fetchJSON(url, {
|
|
432
|
+
headers: [buildAuthorizationHeader(this.token)]
|
|
433
|
+
});
|
|
434
|
+
return (this.userInfo = userInfo);
|
|
435
|
+
};
|
|
436
|
+
/**
|
|
437
|
+
* @param {number} [minValidity]
|
|
438
|
+
* @returns {boolean}
|
|
439
|
+
*/
|
|
440
|
+
this.isTokenExpired = (minValidity) => {
|
|
441
|
+
if (!this.tokenParsed || (!this.refreshToken && this.flow !== 'implicit')) {
|
|
442
|
+
throw new Error('Not authenticated');
|
|
443
|
+
}
|
|
444
|
+
if (this.timeSkew == null) {
|
|
445
|
+
__classPrivateFieldGet(this, _TideCloak_logInfo, "f").call(this, '[TIDECLOAK] Unable to determine if token is expired as timeskew is not set');
|
|
446
|
+
return true;
|
|
447
|
+
}
|
|
448
|
+
if (typeof this.tokenParsed.exp !== 'number') {
|
|
449
|
+
return false;
|
|
450
|
+
}
|
|
451
|
+
let expiresIn = this.tokenParsed.exp - Math.ceil(new Date().getTime() / 1000) + this.timeSkew;
|
|
452
|
+
if (minValidity) {
|
|
453
|
+
if (isNaN(minValidity)) {
|
|
454
|
+
throw new Error('Invalid minValidity');
|
|
455
|
+
}
|
|
456
|
+
expiresIn -= minValidity;
|
|
457
|
+
}
|
|
458
|
+
return expiresIn < 0;
|
|
459
|
+
};
|
|
460
|
+
/**
|
|
461
|
+
* @param {number} minValidity
|
|
462
|
+
* @returns {Promise<boolean>}
|
|
463
|
+
*/
|
|
464
|
+
this.updateToken = async (minValidity) => {
|
|
465
|
+
var _a, _b;
|
|
466
|
+
if (!this.refreshToken) {
|
|
467
|
+
throw new Error('Unable to update token, no refresh token available.');
|
|
468
|
+
}
|
|
469
|
+
minValidity = minValidity || 5;
|
|
470
|
+
if (__classPrivateFieldGet(this, _TideCloak_loginIframe, "f").enable) {
|
|
471
|
+
await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_checkLoginIframe).call(this);
|
|
472
|
+
}
|
|
473
|
+
let refreshToken = false;
|
|
474
|
+
if (minValidity === -1) {
|
|
475
|
+
refreshToken = true;
|
|
476
|
+
__classPrivateFieldGet(this, _TideCloak_logInfo, "f").call(this, '[TIDECLOAK] Refreshing token: forced refresh');
|
|
477
|
+
}
|
|
478
|
+
else if (!this.tokenParsed || this.isTokenExpired(minValidity)) {
|
|
479
|
+
refreshToken = true;
|
|
480
|
+
__classPrivateFieldGet(this, _TideCloak_logInfo, "f").call(this, '[TIDECLOAK] Refreshing token: token expired');
|
|
481
|
+
}
|
|
482
|
+
if (!refreshToken) {
|
|
483
|
+
return false;
|
|
484
|
+
}
|
|
485
|
+
/** @type {PromiseWithResolvers<boolean>} */
|
|
486
|
+
const { promise, resolve, reject } = Promise.withResolvers();
|
|
487
|
+
__classPrivateFieldGet(this, _TideCloak_refreshQueue, "f").push({ resolve, reject });
|
|
488
|
+
if (__classPrivateFieldGet(this, _TideCloak_refreshQueue, "f").length === 1) {
|
|
489
|
+
const url = this.endpoints.token();
|
|
490
|
+
let timeLocal = new Date().getTime();
|
|
491
|
+
try {
|
|
492
|
+
const response = await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_fetchRefreshToken).call(this, url, this.refreshToken, /** @type {string} */ (this.clientId));
|
|
493
|
+
__classPrivateFieldGet(this, _TideCloak_logInfo, "f").call(this, '[TIDECLOAK] Token refreshed');
|
|
494
|
+
timeLocal = (timeLocal + new Date().getTime()) / 2;
|
|
495
|
+
__classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_setToken).call(this, response.access_token, response.refresh_token, response.id_token, timeLocal, response.doken);
|
|
496
|
+
(_a = this.onAuthRefreshSuccess) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
497
|
+
for (let p = __classPrivateFieldGet(this, _TideCloak_refreshQueue, "f").pop(); p != null; p = __classPrivateFieldGet(this, _TideCloak_refreshQueue, "f").pop()) {
|
|
498
|
+
p.resolve(true);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
catch (error) {
|
|
502
|
+
__classPrivateFieldGet(this, _TideCloak_logWarn, "f").call(this, '[TIDECLOAK] Failed to refresh token');
|
|
503
|
+
if (error instanceof NetworkError && error.response.status === 400) {
|
|
504
|
+
this.clearToken();
|
|
505
|
+
}
|
|
506
|
+
(_b = this.onAuthRefreshError) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
507
|
+
for (let p = __classPrivateFieldGet(this, _TideCloak_refreshQueue, "f").pop(); p != null; p = __classPrivateFieldGet(this, _TideCloak_refreshQueue, "f").pop()) {
|
|
508
|
+
p.reject(error);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return await promise;
|
|
513
|
+
};
|
|
514
|
+
this.clearToken = () => {
|
|
515
|
+
var _a;
|
|
516
|
+
if (this.token) {
|
|
517
|
+
__classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_setToken).call(this);
|
|
518
|
+
(_a = this.onAuthLogout) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
519
|
+
if (this.loginRequired) {
|
|
520
|
+
this.login();
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
this.secureFetch = async (url, init = {}) => {
|
|
525
|
+
var _a, _b;
|
|
526
|
+
const dpopProvider = __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f");
|
|
527
|
+
if (dpopProvider && this.authenticated && this.token) {
|
|
528
|
+
const existingAuth = new Headers(init.headers).get('Authorization');
|
|
529
|
+
const isOurBearerToken = existingAuth === `Bearer ${this.token}`;
|
|
530
|
+
if (!isOurBearerToken) {
|
|
531
|
+
// Quick escape - didn't put this check in first if statement as it's more expensive than other checks
|
|
532
|
+
return fetch(url, init);
|
|
533
|
+
}
|
|
534
|
+
const urlString = url instanceof URL ? url.href : url.toString();
|
|
535
|
+
const origin = new URL(urlString).origin;
|
|
536
|
+
const method = (_a = init.method) !== null && _a !== void 0 ? _a : 'GET';
|
|
537
|
+
const resourceNonce = dpopProvider.getResourceServerNonce(origin);
|
|
538
|
+
const proof = await dpopProvider.generateDPoPProof(urlString, method, this.token, resourceNonce);
|
|
539
|
+
const headers = new Headers(init.headers);
|
|
540
|
+
headers.set('Authorization', `DPoP ${this.token}`);
|
|
541
|
+
headers.set('DPoP', proof);
|
|
542
|
+
const resp = await fetch(url, { ...init, headers });
|
|
543
|
+
// Check for new nonce in response
|
|
544
|
+
const newNonce = resp.headers.get('DPoP-Nonce');
|
|
545
|
+
if (newNonce) {
|
|
546
|
+
dpopProvider.updateResourceServerNonce(origin, newNonce);
|
|
547
|
+
}
|
|
548
|
+
// https://datatracker.ietf.org/doc/html/rfc9449#section-9
|
|
549
|
+
// Resource servers signal via: WWW-Authenticate: DPoP error="use_dpop_nonce"
|
|
550
|
+
if (resp.status === 401 && newNonce) {
|
|
551
|
+
const wwwAuth = (_b = resp.headers.get('WWW-Authenticate')) !== null && _b !== void 0 ? _b : '';
|
|
552
|
+
if (wwwAuth.includes('DPoP') && wwwAuth.includes('error="use_dpop_nonce"')) {
|
|
553
|
+
const retryProof = await dpopProvider.generateDPoPProof(urlString, method, this.token, newNonce);
|
|
554
|
+
const retryHeaders = new Headers(init.headers);
|
|
555
|
+
retryHeaders.set('Authorization', `DPoP ${this.token}`);
|
|
556
|
+
retryHeaders.set('DPoP', retryProof);
|
|
557
|
+
const retryResp = await fetch(url, { ...init, headers: retryHeaders });
|
|
558
|
+
// Capture nonce from retry response for future requests
|
|
559
|
+
const retryNonce = retryResp.headers.get('DPoP-Nonce');
|
|
560
|
+
if (retryNonce) {
|
|
561
|
+
dpopProvider.updateResourceServerNonce(origin, retryNonce);
|
|
562
|
+
}
|
|
563
|
+
return retryResp;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
return resp;
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
return fetch(url, init);
|
|
570
|
+
}
|
|
571
|
+
};
|
|
108
572
|
if (typeof config !== 'string' && !isObject(config)) {
|
|
109
573
|
throw new Error("The 'TideCloak' constructor must be provided with a configuration object, or a URL to a JSON configuration file.");
|
|
110
574
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
575
|
+
if (isObject(config)) {
|
|
576
|
+
const requiredProperties = 'oidcProvider' in config
|
|
577
|
+
? ['clientId']
|
|
578
|
+
: ['url', 'realm', 'clientId'];
|
|
579
|
+
for (const property of requiredProperties) {
|
|
580
|
+
if (!(property in config)) {
|
|
581
|
+
throw new Error(`The configuration object is missing the required '${property}' property.`);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
121
585
|
if (!globalThis.isSecureContext) {
|
|
122
586
|
__classPrivateFieldGet(this, _TideCloak_logWarn, "f").call(this, "[TIDECLOAK] TideCloak JS must be used in a 'secure context' to function properly as it relies on browser APIs that are otherwise not available.\n" +
|
|
123
587
|
'Continuing to run your application insecurely will lead to unexpected behavior and breakage.\n\n' +
|
|
@@ -125,113 +589,7 @@ class TideCloak {
|
|
|
125
589
|
}
|
|
126
590
|
__classPrivateFieldSet(this, _TideCloak_config, config, "f");
|
|
127
591
|
}
|
|
128
|
-
/**
|
|
129
|
-
* @param {KeycloakInitOptions} initOptions
|
|
130
|
-
* @returns {Promise<boolean>}
|
|
131
|
-
*/
|
|
132
|
-
async init(initOptions = {}) {
|
|
133
|
-
var _a;
|
|
134
|
-
if (this.didInitialize) {
|
|
135
|
-
throw new Error("A 'TideCloak' instance can only be initialized once.");
|
|
136
|
-
}
|
|
137
|
-
this.didInitialize = true;
|
|
138
|
-
__classPrivateFieldSet(this, _TideCloak_callbackStorage, createCallbackStorage(), "f");
|
|
139
|
-
const adapters = ['default', 'cordova', 'cordova-native'];
|
|
140
|
-
if (typeof initOptions.adapter === 'string' && adapters.includes(initOptions.adapter)) {
|
|
141
|
-
__classPrivateFieldSet(this, _TideCloak_adapter, __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_loadAdapter).call(this, initOptions.adapter), "f");
|
|
142
|
-
}
|
|
143
|
-
else if (typeof initOptions.adapter === 'object') {
|
|
144
|
-
__classPrivateFieldSet(this, _TideCloak_adapter, initOptions.adapter, "f");
|
|
145
|
-
}
|
|
146
|
-
else if ('Cordova' in window || 'cordova' in window) {
|
|
147
|
-
__classPrivateFieldSet(this, _TideCloak_adapter, __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_loadAdapter).call(this, 'cordova'), "f");
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
__classPrivateFieldSet(this, _TideCloak_adapter, __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_loadAdapter).call(this, 'default'), "f");
|
|
151
|
-
}
|
|
152
|
-
if (typeof initOptions.useNonce !== 'undefined') {
|
|
153
|
-
__classPrivateFieldSet(this, _TideCloak_useNonce, initOptions.useNonce, "f");
|
|
154
|
-
}
|
|
155
|
-
if (typeof initOptions.checkLoginIframe !== 'undefined') {
|
|
156
|
-
__classPrivateFieldGet(this, _TideCloak_loginIframe, "f").enable = initOptions.checkLoginIframe;
|
|
157
|
-
}
|
|
158
|
-
if (initOptions.checkLoginIframeInterval) {
|
|
159
|
-
__classPrivateFieldGet(this, _TideCloak_loginIframe, "f").interval = initOptions.checkLoginIframeInterval;
|
|
160
|
-
}
|
|
161
|
-
if (initOptions.onLoad === 'login-required') {
|
|
162
|
-
this.loginRequired = true;
|
|
163
|
-
}
|
|
164
|
-
if (initOptions.responseMode) {
|
|
165
|
-
if (initOptions.responseMode === 'query' || initOptions.responseMode === 'fragment') {
|
|
166
|
-
this.responseMode = initOptions.responseMode;
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
throw new Error('Invalid value for responseMode');
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
if (initOptions.flow) {
|
|
173
|
-
switch (initOptions.flow) {
|
|
174
|
-
case 'standard':
|
|
175
|
-
this.responseType = 'code';
|
|
176
|
-
break;
|
|
177
|
-
case 'implicit':
|
|
178
|
-
this.responseType = 'id_token token';
|
|
179
|
-
break;
|
|
180
|
-
case 'hybrid':
|
|
181
|
-
this.responseType = 'code id_token token';
|
|
182
|
-
break;
|
|
183
|
-
default:
|
|
184
|
-
throw new Error('Invalid value for flow');
|
|
185
|
-
}
|
|
186
|
-
this.flow = initOptions.flow;
|
|
187
|
-
}
|
|
188
|
-
if (typeof initOptions.timeSkew === 'number') {
|
|
189
|
-
this.timeSkew = initOptions.timeSkew;
|
|
190
|
-
}
|
|
191
|
-
if (initOptions.redirectUri) {
|
|
192
|
-
this.redirectUri = initOptions.redirectUri;
|
|
193
|
-
}
|
|
194
|
-
if (initOptions.silentCheckSsoRedirectUri) {
|
|
195
|
-
this.silentCheckSsoRedirectUri = initOptions.silentCheckSsoRedirectUri;
|
|
196
|
-
}
|
|
197
|
-
if (typeof initOptions.silentCheckSsoFallback === 'boolean') {
|
|
198
|
-
this.silentCheckSsoFallback = initOptions.silentCheckSsoFallback;
|
|
199
|
-
}
|
|
200
|
-
if (typeof initOptions.pkceMethod !== 'undefined') {
|
|
201
|
-
if (initOptions.pkceMethod !== 'S256' && initOptions.pkceMethod !== false) {
|
|
202
|
-
throw new TypeError(`Invalid value for pkceMethod', expected 'S256' or false but got ${initOptions.pkceMethod}.`);
|
|
203
|
-
}
|
|
204
|
-
this.pkceMethod = initOptions.pkceMethod;
|
|
205
|
-
}
|
|
206
|
-
if (typeof initOptions.enableLogging === 'boolean') {
|
|
207
|
-
this.enableLogging = initOptions.enableLogging;
|
|
208
|
-
}
|
|
209
|
-
if (initOptions.logoutMethod === 'POST') {
|
|
210
|
-
this.logoutMethod = 'POST';
|
|
211
|
-
}
|
|
212
|
-
if (typeof initOptions.scope === 'string') {
|
|
213
|
-
this.scope = initOptions.scope;
|
|
214
|
-
}
|
|
215
|
-
if (typeof initOptions.acrValues === 'string') {
|
|
216
|
-
this.acrValues = initOptions.acrValues;
|
|
217
|
-
}
|
|
218
|
-
if (typeof initOptions.messageReceiveTimeout === 'number' && initOptions.messageReceiveTimeout > 0) {
|
|
219
|
-
this.messageReceiveTimeout = initOptions.messageReceiveTimeout;
|
|
220
|
-
}
|
|
221
|
-
await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_loadConfig).call(this);
|
|
222
|
-
await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_check3pCookiesSupported).call(this);
|
|
223
|
-
await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_processInit).call(this, initOptions);
|
|
224
|
-
(_a = this.onReady) === null || _a === void 0 ? void 0 : _a.call(this, this.authenticated);
|
|
225
|
-
return this.authenticated;
|
|
226
|
-
}
|
|
227
592
|
;
|
|
228
|
-
/**
|
|
229
|
-
* @param {KeycloakLoginOptions} [options]
|
|
230
|
-
* @returns {Promise<void>}
|
|
231
|
-
*/
|
|
232
|
-
login(options) {
|
|
233
|
-
return __classPrivateFieldGet(this, _TideCloak_adapter, "f").login(options);
|
|
234
|
-
}
|
|
235
593
|
/**
|
|
236
594
|
* Ensure the access token is valid, refreshing if needed.
|
|
237
595
|
* @returns {Promise<void>}
|
|
@@ -243,283 +601,6 @@ class TideCloak {
|
|
|
243
601
|
await this.updateToken(-1);
|
|
244
602
|
}
|
|
245
603
|
}
|
|
246
|
-
/**
|
|
247
|
-
* @param {KeycloakLoginOptions} [options]
|
|
248
|
-
* @returns {Promise<string>}
|
|
249
|
-
*/
|
|
250
|
-
async createLoginUrl(options) {
|
|
251
|
-
const state = createUUID();
|
|
252
|
-
const nonce = createUUID();
|
|
253
|
-
const redirectUri = __classPrivateFieldGet(this, _TideCloak_adapter, "f").redirectUri(options);
|
|
254
|
-
/** @type {CallbackState} */
|
|
255
|
-
const callbackState = {
|
|
256
|
-
state,
|
|
257
|
-
nonce,
|
|
258
|
-
redirectUri,
|
|
259
|
-
loginOptions: options
|
|
260
|
-
};
|
|
261
|
-
if (options === null || options === void 0 ? void 0 : options.prompt) {
|
|
262
|
-
callbackState.prompt = options.prompt;
|
|
263
|
-
}
|
|
264
|
-
const url = (options === null || options === void 0 ? void 0 : options.action) === 'register'
|
|
265
|
-
? this.endpoints.register()
|
|
266
|
-
: this.endpoints.authorize();
|
|
267
|
-
let scope = (options === null || options === void 0 ? void 0 : options.scope) || this.scope;
|
|
268
|
-
const scopeValues = scope ? scope.split(' ') : [];
|
|
269
|
-
// Ensure the 'openid' scope is always included.
|
|
270
|
-
if (!scopeValues.includes('openid')) {
|
|
271
|
-
scopeValues.unshift('openid');
|
|
272
|
-
}
|
|
273
|
-
scope = scopeValues.join(' ');
|
|
274
|
-
const params = new URLSearchParams([
|
|
275
|
-
['client_id', /** @type {string} */ (this.clientId)],
|
|
276
|
-
// The endpoint URI MUST NOT include a fragment component.
|
|
277
|
-
// https://datatracker.ietf.org/doc/html/rfc6749#section-3.1.2
|
|
278
|
-
['redirect_uri', stripHash(redirectUri)],
|
|
279
|
-
['state', state],
|
|
280
|
-
['response_mode', this.responseMode],
|
|
281
|
-
['response_type', this.responseType],
|
|
282
|
-
['scope', scope]
|
|
283
|
-
]);
|
|
284
|
-
if (__classPrivateFieldGet(this, _TideCloak_useNonce, "f")) {
|
|
285
|
-
params.append('nonce', nonce);
|
|
286
|
-
}
|
|
287
|
-
if (options === null || options === void 0 ? void 0 : options.prompt) {
|
|
288
|
-
params.append('prompt', options.prompt);
|
|
289
|
-
}
|
|
290
|
-
if (typeof (options === null || options === void 0 ? void 0 : options.maxAge) === 'number') {
|
|
291
|
-
params.append('max_age', options.maxAge.toString());
|
|
292
|
-
}
|
|
293
|
-
if (options === null || options === void 0 ? void 0 : options.loginHint) {
|
|
294
|
-
params.append('login_hint', options.loginHint);
|
|
295
|
-
}
|
|
296
|
-
if (options === null || options === void 0 ? void 0 : options.idpHint) {
|
|
297
|
-
params.append('kc_idp_hint', options.idpHint);
|
|
298
|
-
}
|
|
299
|
-
if ((options === null || options === void 0 ? void 0 : options.action) && options.action !== 'register') {
|
|
300
|
-
params.append('kc_action', options.action);
|
|
301
|
-
}
|
|
302
|
-
if (options === null || options === void 0 ? void 0 : options.locale) {
|
|
303
|
-
params.append('ui_locales', options.locale);
|
|
304
|
-
}
|
|
305
|
-
if (options === null || options === void 0 ? void 0 : options.acr) {
|
|
306
|
-
params.append('claims', buildClaimsParameter(options.acr));
|
|
307
|
-
}
|
|
308
|
-
if ((options === null || options === void 0 ? void 0 : options.acrValues) || this.acrValues) {
|
|
309
|
-
params.append('acr_values', options.acrValues || this.acrValues);
|
|
310
|
-
}
|
|
311
|
-
if (this.pkceMethod) {
|
|
312
|
-
try {
|
|
313
|
-
const codeVerifier = generateCodeVerifier(96);
|
|
314
|
-
const pkceChallenge = await generatePkceChallenge(this.pkceMethod, codeVerifier);
|
|
315
|
-
callbackState.pkceCodeVerifier = codeVerifier;
|
|
316
|
-
params.append('code_challenge', pkceChallenge);
|
|
317
|
-
params.append('code_challenge_method', this.pkceMethod);
|
|
318
|
-
}
|
|
319
|
-
catch (error) {
|
|
320
|
-
throw new Error('Failed to generate PKCE challenge.', { cause: error });
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
__classPrivateFieldGet(this, _TideCloak_callbackStorage, "f").add(callbackState);
|
|
324
|
-
return `${url}?${params.toString()}`;
|
|
325
|
-
}
|
|
326
|
-
/**
|
|
327
|
-
* @param {KeycloakLogoutOptions} [options]
|
|
328
|
-
* @returns {Promise<void>}
|
|
329
|
-
*/
|
|
330
|
-
logout(options) {
|
|
331
|
-
return __classPrivateFieldGet(this, _TideCloak_adapter, "f").logout(options);
|
|
332
|
-
}
|
|
333
|
-
/**
|
|
334
|
-
* @param {KeycloakLogoutOptions} [options]
|
|
335
|
-
* @returns {string}
|
|
336
|
-
*/
|
|
337
|
-
createLogoutUrl(options) {
|
|
338
|
-
var _a;
|
|
339
|
-
const logoutMethod = (_a = options === null || options === void 0 ? void 0 : options.logoutMethod) !== null && _a !== void 0 ? _a : this.logoutMethod;
|
|
340
|
-
const url = this.endpoints.logout();
|
|
341
|
-
if (logoutMethod === 'POST') {
|
|
342
|
-
return url;
|
|
343
|
-
}
|
|
344
|
-
const params = new URLSearchParams([
|
|
345
|
-
['client_id', /** @type {string} */ (this.clientId)],
|
|
346
|
-
['post_logout_redirect_uri', __classPrivateFieldGet(this, _TideCloak_adapter, "f").redirectUri(options)]
|
|
347
|
-
]);
|
|
348
|
-
if (this.idToken) {
|
|
349
|
-
params.append('id_token_hint', this.idToken);
|
|
350
|
-
}
|
|
351
|
-
return `${url}?${params.toString()}`;
|
|
352
|
-
}
|
|
353
|
-
/**
|
|
354
|
-
* @param {KeycloakRegisterOptions} [options]
|
|
355
|
-
* @returns {Promise<void>}
|
|
356
|
-
*/
|
|
357
|
-
register(options) {
|
|
358
|
-
return __classPrivateFieldGet(this, _TideCloak_adapter, "f").register(options);
|
|
359
|
-
}
|
|
360
|
-
/**
|
|
361
|
-
* @param {KeycloakRegisterOptions} [options]
|
|
362
|
-
* @returns {Promise<string>}
|
|
363
|
-
*/
|
|
364
|
-
createRegisterUrl(options) {
|
|
365
|
-
return this.createLoginUrl({ ...options, action: 'register' });
|
|
366
|
-
}
|
|
367
|
-
/**
|
|
368
|
-
* @param {KeycloakAccountOptions} [options]
|
|
369
|
-
* @returns {string}
|
|
370
|
-
*/
|
|
371
|
-
createAccountUrl(options) {
|
|
372
|
-
const url = __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_getRealmUrl).call(this);
|
|
373
|
-
if (!url) {
|
|
374
|
-
throw new Error('Unable to create account URL, make sure the adapter is not configured using a generic OIDC provider.');
|
|
375
|
-
}
|
|
376
|
-
const params = new URLSearchParams([
|
|
377
|
-
['referrer', /** @type {string} */ (this.clientId)],
|
|
378
|
-
['referrer_uri', __classPrivateFieldGet(this, _TideCloak_adapter, "f").redirectUri(options)]
|
|
379
|
-
]);
|
|
380
|
-
return `${url}/account?${params.toString()}`;
|
|
381
|
-
}
|
|
382
|
-
/**
|
|
383
|
-
* @returns {Promise<void>}
|
|
384
|
-
*/
|
|
385
|
-
accountManagement() {
|
|
386
|
-
return __classPrivateFieldGet(this, _TideCloak_adapter, "f").accountManagement();
|
|
387
|
-
}
|
|
388
|
-
/**
|
|
389
|
-
* @param {string} role
|
|
390
|
-
* @returns {boolean}
|
|
391
|
-
*/
|
|
392
|
-
hasRealmRole(role) {
|
|
393
|
-
const access = this.realmAccess;
|
|
394
|
-
return !!access && access.roles.indexOf(role) >= 0;
|
|
395
|
-
}
|
|
396
|
-
/**
|
|
397
|
-
* @param {string} role
|
|
398
|
-
* @param {string} [resource]
|
|
399
|
-
* @returns {boolean}
|
|
400
|
-
*/
|
|
401
|
-
hasResourceRole(role, resource) {
|
|
402
|
-
if (!this.resourceAccess) {
|
|
403
|
-
return false;
|
|
404
|
-
}
|
|
405
|
-
const access = this.resourceAccess[resource || /** @type {string} */ (this.clientId)];
|
|
406
|
-
return !!access && access.roles.indexOf(role) >= 0;
|
|
407
|
-
}
|
|
408
|
-
/**
|
|
409
|
-
* @returns {Promise<KeycloakProfile>}
|
|
410
|
-
*/
|
|
411
|
-
async loadUserProfile() {
|
|
412
|
-
const realmUrl = __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_getRealmUrl).call(this);
|
|
413
|
-
if (!realmUrl) {
|
|
414
|
-
throw new Error('Unable to load user profile, make sure the adapter is not configured using a generic OIDC provider.');
|
|
415
|
-
}
|
|
416
|
-
const url = `${realmUrl}/account`;
|
|
417
|
-
/** @type {KeycloakProfile} */
|
|
418
|
-
const profile = await fetchJSON(url, {
|
|
419
|
-
headers: [buildAuthorizationHeader(this.token)]
|
|
420
|
-
});
|
|
421
|
-
return (this.profile = profile);
|
|
422
|
-
}
|
|
423
|
-
/**
|
|
424
|
-
* @returns {Promise<KeycloakUserInfo>}
|
|
425
|
-
*/
|
|
426
|
-
async loadUserInfo() {
|
|
427
|
-
const url = this.endpoints.userinfo();
|
|
428
|
-
/** @type {KeycloakUserInfo} */
|
|
429
|
-
const userInfo = await fetchJSON(url, {
|
|
430
|
-
headers: [buildAuthorizationHeader(this.token)]
|
|
431
|
-
});
|
|
432
|
-
return (this.userInfo = userInfo);
|
|
433
|
-
}
|
|
434
|
-
/**
|
|
435
|
-
* @param {number} [minValidity]
|
|
436
|
-
* @returns {boolean}
|
|
437
|
-
*/
|
|
438
|
-
isTokenExpired(minValidity) {
|
|
439
|
-
if (!this.tokenParsed || (!this.refreshToken && this.flow !== 'implicit')) {
|
|
440
|
-
throw new Error('Not authenticated');
|
|
441
|
-
}
|
|
442
|
-
if (this.timeSkew == null) {
|
|
443
|
-
__classPrivateFieldGet(this, _TideCloak_logInfo, "f").call(this, '[TIDECLOAK] Unable to determine if token is expired as timeskew is not set');
|
|
444
|
-
return true;
|
|
445
|
-
}
|
|
446
|
-
if (typeof this.tokenParsed.exp !== 'number') {
|
|
447
|
-
return false;
|
|
448
|
-
}
|
|
449
|
-
let expiresIn = this.tokenParsed.exp - Math.ceil(new Date().getTime() / 1000) + this.timeSkew;
|
|
450
|
-
if (minValidity) {
|
|
451
|
-
if (isNaN(minValidity)) {
|
|
452
|
-
throw new Error('Invalid minValidity');
|
|
453
|
-
}
|
|
454
|
-
expiresIn -= minValidity;
|
|
455
|
-
}
|
|
456
|
-
return expiresIn < 0;
|
|
457
|
-
}
|
|
458
|
-
/**
|
|
459
|
-
* Matches Keycloak: minValidity is optional.
|
|
460
|
-
* @param {number} [minValidity]
|
|
461
|
-
* @returns {Promise<boolean>}
|
|
462
|
-
*/
|
|
463
|
-
async updateToken(minValidity) {
|
|
464
|
-
var _a, _b;
|
|
465
|
-
if (!this.refreshToken) {
|
|
466
|
-
throw new Error('Unable to update token, no refresh token available.');
|
|
467
|
-
}
|
|
468
|
-
minValidity = minValidity || 5;
|
|
469
|
-
if (__classPrivateFieldGet(this, _TideCloak_loginIframe, "f").enable) {
|
|
470
|
-
await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_checkLoginIframe).call(this);
|
|
471
|
-
}
|
|
472
|
-
let refreshToken = false;
|
|
473
|
-
if (minValidity === -1) {
|
|
474
|
-
refreshToken = true;
|
|
475
|
-
__classPrivateFieldGet(this, _TideCloak_logInfo, "f").call(this, '[TIDECLOAK] Refreshing token: forced refresh');
|
|
476
|
-
}
|
|
477
|
-
else if (!this.tokenParsed || this.isTokenExpired(minValidity)) {
|
|
478
|
-
refreshToken = true;
|
|
479
|
-
__classPrivateFieldGet(this, _TideCloak_logInfo, "f").call(this, '[TIDECLOAK] Refreshing token: token expired');
|
|
480
|
-
}
|
|
481
|
-
if (!refreshToken) {
|
|
482
|
-
return false;
|
|
483
|
-
}
|
|
484
|
-
/** @type {PromiseWithResolvers<boolean>} */
|
|
485
|
-
const { promise, resolve, reject } = Promise.withResolvers();
|
|
486
|
-
__classPrivateFieldGet(this, _TideCloak_refreshQueue, "f").push({ resolve, reject });
|
|
487
|
-
if (__classPrivateFieldGet(this, _TideCloak_refreshQueue, "f").length === 1) {
|
|
488
|
-
const url = this.endpoints.token();
|
|
489
|
-
let timeLocal = new Date().getTime();
|
|
490
|
-
try {
|
|
491
|
-
const response = await fetchRefreshToken(url, this.refreshToken, /** @type {string} */ (this.clientId));
|
|
492
|
-
__classPrivateFieldGet(this, _TideCloak_logInfo, "f").call(this, '[TIDECLOAK] Token refreshed');
|
|
493
|
-
timeLocal = (timeLocal + new Date().getTime()) / 2;
|
|
494
|
-
__classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_setToken).call(this, response.access_token, response.refresh_token, response.id_token, timeLocal, response.doken);
|
|
495
|
-
(_a = this.onAuthRefreshSuccess) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
496
|
-
for (let p = __classPrivateFieldGet(this, _TideCloak_refreshQueue, "f").pop(); p != null; p = __classPrivateFieldGet(this, _TideCloak_refreshQueue, "f").pop()) {
|
|
497
|
-
p.resolve(true);
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
catch (error) {
|
|
501
|
-
__classPrivateFieldGet(this, _TideCloak_logWarn, "f").call(this, '[TIDECLOAK] Failed to refresh token');
|
|
502
|
-
if (error instanceof NetworkError && error.response.status === 400) {
|
|
503
|
-
this.clearToken();
|
|
504
|
-
}
|
|
505
|
-
(_b = this.onAuthRefreshError) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
506
|
-
for (let p = __classPrivateFieldGet(this, _TideCloak_refreshQueue, "f").pop(); p != null; p = __classPrivateFieldGet(this, _TideCloak_refreshQueue, "f").pop()) {
|
|
507
|
-
p.reject(error);
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
return await promise;
|
|
512
|
-
}
|
|
513
|
-
clearToken() {
|
|
514
|
-
var _a;
|
|
515
|
-
if (this.token) {
|
|
516
|
-
__classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_setToken).call(this);
|
|
517
|
-
(_a = this.onAuthLogout) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
518
|
-
if (this.loginRequired) {
|
|
519
|
-
this.login();
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
604
|
/**
|
|
524
605
|
* Initialize Tide RequestEnclave.
|
|
525
606
|
*/
|
|
@@ -703,7 +784,7 @@ class TideCloak {
|
|
|
703
784
|
return decrypted.map((d, i) => (dataToSend[i].isRaw ? d : StringFromUint8Array(d)));
|
|
704
785
|
}
|
|
705
786
|
}
|
|
706
|
-
_TideCloak_refreshQueue = new WeakMap(), _TideCloak_adapter = new WeakMap(), _TideCloak_useNonce = new WeakMap(), _TideCloak_callbackStorage = new WeakMap(), _TideCloak_logInfo = new WeakMap(), _TideCloak_logWarn = new WeakMap(), _TideCloak_loginIframe = new WeakMap(), _TideCloak_config = new WeakMap(), _TideCloak_instances = new WeakSet(), _TideCloak_loadAdapter = function _TideCloak_loadAdapter(type) {
|
|
787
|
+
_TideCloak_refreshQueue = new WeakMap(), _TideCloak_adapter = new WeakMap(), _TideCloak_useNonce = new WeakMap(), _TideCloak_callbackStorage = new WeakMap(), _TideCloak_logInfo = new WeakMap(), _TideCloak_logWarn = new WeakMap(), _TideCloak_loginIframe = new WeakMap(), _TideCloak_dpopProvider = new WeakMap(), _TideCloak_config = new WeakMap(), _TideCloak_instances = new WeakSet(), _TideCloak_loadAdapter = function _TideCloak_loadAdapter(type) {
|
|
707
788
|
if (type === 'default') {
|
|
708
789
|
return __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_loadDefaultAdapter).call(this);
|
|
709
790
|
}
|
|
@@ -717,7 +798,7 @@ _TideCloak_refreshQueue = new WeakMap(), _TideCloak_adapter = new WeakMap(), _Ti
|
|
|
717
798
|
}
|
|
718
799
|
throw new Error('invalid adapter type: ' + type);
|
|
719
800
|
}, _TideCloak_loadDefaultAdapter = function _TideCloak_loadDefaultAdapter() {
|
|
720
|
-
/** @type {
|
|
801
|
+
/** @type {TideCloakAdapter['redirectUri']}{} */
|
|
721
802
|
const redirectUri = (options) => {
|
|
722
803
|
return (options === null || options === void 0 ? void 0 : options.redirectUri) || this.redirectUri || globalThis.location.href;
|
|
723
804
|
};
|
|
@@ -1021,7 +1102,7 @@ async function _TideCloak_loadConfig() {
|
|
|
1021
1102
|
this.authServerUrl = jsonConfig['auth-server-url'];
|
|
1022
1103
|
this.realm = jsonConfig.realm;
|
|
1023
1104
|
this.clientId = jsonConfig.resource;
|
|
1024
|
-
__classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_setupEndpoints).call(this);
|
|
1105
|
+
await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_setupEndpoints).call(this);
|
|
1025
1106
|
}
|
|
1026
1107
|
else {
|
|
1027
1108
|
this.clientId = __classPrivateFieldGet(this, _TideCloak_config, "f").clientId;
|
|
@@ -1031,10 +1112,31 @@ async function _TideCloak_loadConfig() {
|
|
|
1031
1112
|
else {
|
|
1032
1113
|
this.authServerUrl = __classPrivateFieldGet(this, _TideCloak_config, "f").url;
|
|
1033
1114
|
this.realm = __classPrivateFieldGet(this, _TideCloak_config, "f").realm;
|
|
1034
|
-
__classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_setupEndpoints).call(this);
|
|
1115
|
+
await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_setupEndpoints).call(this);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
}, _TideCloak_setupEndpoints =
|
|
1119
|
+
/**
|
|
1120
|
+
* @returns {Promise<void>}
|
|
1121
|
+
*/
|
|
1122
|
+
async function _TideCloak_setupEndpoints() {
|
|
1123
|
+
// Fetch OIDC metadata to get DPoP supported algorithms (only if DPoP is enabled)
|
|
1124
|
+
if (this.useDPoP) {
|
|
1125
|
+
const issuerUrl = __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_getIssuerUrl).call(this);
|
|
1126
|
+
if (!issuerUrl) {
|
|
1127
|
+
__classPrivateFieldGet(this, _TideCloak_logWarn, "f").call(this, '[TIDECLOAK] Cannot fetch OIDC metadata: issuer URL is not available');
|
|
1128
|
+
}
|
|
1129
|
+
else {
|
|
1130
|
+
const url = `${stripTrailingSlash(issuerUrl)}/.well-known/openid-configuration`;
|
|
1131
|
+
try {
|
|
1132
|
+
const openIdConfig = await fetchOpenIdConfig(url);
|
|
1133
|
+
this.dpopSigningAlgValuesSupported = openIdConfig.dpop_signing_alg_values_supported ? openIdConfig.dpop_signing_alg_values_supported : undefined;
|
|
1134
|
+
}
|
|
1135
|
+
catch (error) {
|
|
1136
|
+
__classPrivateFieldGet(this, _TideCloak_logWarn, "f").call(this, '[TIDECLOAK] Failed to fetch OIDC metadata for DPoP configuration: ' + (error instanceof Error ? error.message : error));
|
|
1137
|
+
}
|
|
1035
1138
|
}
|
|
1036
1139
|
}
|
|
1037
|
-
}, _TideCloak_setupEndpoints = function _TideCloak_setupEndpoints() {
|
|
1038
1140
|
this.endpoints = {
|
|
1039
1141
|
authorize: () => {
|
|
1040
1142
|
return __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_getRealmUrl).call(this) + '/protocol/openid-connect/auth';
|
|
@@ -1073,6 +1175,9 @@ async function _TideCloak_loadOidcConfig(oidcProvider) {
|
|
|
1073
1175
|
__classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_setupOidcEndpoints).call(this, oidcProvider);
|
|
1074
1176
|
}
|
|
1075
1177
|
}, _TideCloak_setupOidcEndpoints = function _TideCloak_setupOidcEndpoints(config) {
|
|
1178
|
+
// Store DPoP supported algorithms if present
|
|
1179
|
+
this.dpopSigningAlgValuesSupported = config.dpop_signing_alg_values_supported;
|
|
1180
|
+
this.issuer = config.issuer;
|
|
1076
1181
|
this.endpoints = {
|
|
1077
1182
|
authorize() {
|
|
1078
1183
|
return config.authorization_endpoint;
|
|
@@ -1102,6 +1207,11 @@ async function _TideCloak_loadOidcConfig(oidcProvider) {
|
|
|
1102
1207
|
return config.userinfo_endpoint;
|
|
1103
1208
|
}
|
|
1104
1209
|
};
|
|
1210
|
+
}, _TideCloak_getIssuerUrl = function _TideCloak_getIssuerUrl() {
|
|
1211
|
+
if (this.issuer)
|
|
1212
|
+
return this.issuer;
|
|
1213
|
+
const realmUrl = __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_getRealmUrl).call(this);
|
|
1214
|
+
return realmUrl || undefined;
|
|
1105
1215
|
}, _TideCloak_check3pCookiesSupported =
|
|
1106
1216
|
/**
|
|
1107
1217
|
* @returns {Promise<void>}
|
|
@@ -1147,14 +1257,14 @@ async function _TideCloak_check3pCookiesSupported() {
|
|
|
1147
1257
|
return await applyTimeoutToPromise(promise, this.messageReceiveTimeout, 'Timeout when waiting for 3rd party check iframe message.');
|
|
1148
1258
|
}, _TideCloak_processInit =
|
|
1149
1259
|
/**
|
|
1150
|
-
* @param {
|
|
1260
|
+
* @param {TideCloakInitOptions} initOptions
|
|
1151
1261
|
* @returns {Promise<void>}
|
|
1152
1262
|
*/
|
|
1153
1263
|
async function _TideCloak_processInit(initOptions) {
|
|
1154
1264
|
var _a, _b, _c;
|
|
1155
1265
|
const callback = __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_parseCallback).call(this, window.location.href);
|
|
1156
|
-
if (callback === null || callback === void 0 ? void 0 : callback.
|
|
1157
|
-
window.history.replaceState(window.history.state, '', callback.
|
|
1266
|
+
if (callback === null || callback === void 0 ? void 0 : callback.newUrl) {
|
|
1267
|
+
window.history.replaceState(window.history.state, '', callback.newUrl);
|
|
1158
1268
|
}
|
|
1159
1269
|
if (callback && callback.valid) {
|
|
1160
1270
|
await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_setupCheckLoginIframe).call(this);
|
|
@@ -1163,7 +1273,7 @@ async function _TideCloak_processInit(initOptions) {
|
|
|
1163
1273
|
}
|
|
1164
1274
|
/** @param {boolean} prompt */
|
|
1165
1275
|
const doLogin = async (prompt) => {
|
|
1166
|
-
/** @type {
|
|
1276
|
+
/** @type {TideCloakLoginOptions} */
|
|
1167
1277
|
const options = {};
|
|
1168
1278
|
if (!prompt) {
|
|
1169
1279
|
options.prompt = 'none';
|
|
@@ -1364,28 +1474,28 @@ async function _TideCloak_checkSsoSilently() {
|
|
|
1364
1474
|
supportedParams.push('error_description');
|
|
1365
1475
|
supportedParams.push('error_uri');
|
|
1366
1476
|
const url = new URL(urlString);
|
|
1367
|
-
let
|
|
1477
|
+
let newUrl = '';
|
|
1368
1478
|
let parsed;
|
|
1369
1479
|
if (this.responseMode === 'query' && url.searchParams.size > 0) {
|
|
1370
1480
|
parsed = __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_parseCallbackParams).call(this, url.search, supportedParams);
|
|
1371
1481
|
url.search = parsed.paramsString;
|
|
1372
|
-
|
|
1482
|
+
newUrl = url.toString();
|
|
1373
1483
|
}
|
|
1374
1484
|
else if (this.responseMode === 'fragment' && url.hash.length > 0) {
|
|
1375
1485
|
parsed = __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_parseCallbackParams).call(this, url.hash.substring(1), supportedParams);
|
|
1376
|
-
url.hash =
|
|
1377
|
-
|
|
1486
|
+
url.hash = parsed.paramsString;
|
|
1487
|
+
newUrl = url.toString();
|
|
1378
1488
|
}
|
|
1379
1489
|
if (parsed === null || parsed === void 0 ? void 0 : parsed.oauthParams) {
|
|
1380
1490
|
if (this.flow === 'standard' || this.flow === 'hybrid') {
|
|
1381
1491
|
if ((parsed.oauthParams.code || parsed.oauthParams.error) && parsed.oauthParams.state) {
|
|
1382
|
-
parsed.oauthParams.
|
|
1492
|
+
parsed.oauthParams.newUrl = newUrl;
|
|
1383
1493
|
return parsed.oauthParams;
|
|
1384
1494
|
}
|
|
1385
1495
|
}
|
|
1386
1496
|
else if (this.flow === 'implicit') {
|
|
1387
1497
|
if ((parsed.oauthParams.access_token || parsed.oauthParams.error) && parsed.oauthParams.state) {
|
|
1388
|
-
parsed.oauthParams.
|
|
1498
|
+
parsed.oauthParams.newUrl = newUrl;
|
|
1389
1499
|
return parsed.oauthParams;
|
|
1390
1500
|
}
|
|
1391
1501
|
}
|
|
@@ -1445,7 +1555,7 @@ async function _TideCloak_checkSsoSilently() {
|
|
|
1445
1555
|
}
|
|
1446
1556
|
if ((this.flow !== 'implicit') && code) {
|
|
1447
1557
|
try {
|
|
1448
|
-
const response = await
|
|
1558
|
+
const response = await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_fetchAccessToken).call(this, this.endpoints.token(), code, /** @type {string} */ (this.clientId), oauth.redirectUri, oauth.pkceCodeVerifier);
|
|
1449
1559
|
authSuccess(response.access_token, response.refresh_token, response.id_token, response.doken);
|
|
1450
1560
|
if (this.flow === 'standard') {
|
|
1451
1561
|
(_c = this.onAuthSuccess) === null || _c === void 0 ? void 0 : _c.call(this);
|
|
@@ -1465,6 +1575,116 @@ async function _TideCloak_checkSsoSilently() {
|
|
|
1465
1575
|
await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_scheduleCheckIframe).call(this);
|
|
1466
1576
|
}
|
|
1467
1577
|
}
|
|
1578
|
+
}, _TideCloak_fetchAccessToken =
|
|
1579
|
+
/**
|
|
1580
|
+
* @typedef {Object} AccessTokenResponse The successful token response from the authorization server, based on the {@link https://datatracker.ietf.org/doc/html/rfc6749#section-5.1 OAuth 2.0 Authorization Framework specification}.
|
|
1581
|
+
* @property {string} access_token The access token issued by the authorization server.
|
|
1582
|
+
* @property {string} token_type The type of the token issued by the authorization server.
|
|
1583
|
+
* @property {number} [expires_in] The lifetime in seconds of the access token.
|
|
1584
|
+
* @property {string} [refresh_token] The refresh token issued by the authorization server.
|
|
1585
|
+
* @property {string} [id_token] The ID token issued by the authorization server, if requested.
|
|
1586
|
+
* @property {string} [scope] The scope of the access token.
|
|
1587
|
+
* @property {string} [doken] The Tide doken issued by the authorization server.
|
|
1588
|
+
*/
|
|
1589
|
+
/**
|
|
1590
|
+
* Fetch the access token from the given URL.
|
|
1591
|
+
* @param {string} url
|
|
1592
|
+
* @param {string} code
|
|
1593
|
+
* @param {string} clientId
|
|
1594
|
+
* @param {string} redirectUri
|
|
1595
|
+
* @param {string} [pkceCodeVerifier]
|
|
1596
|
+
* @returns {Promise<AccessTokenResponse>}
|
|
1597
|
+
*/
|
|
1598
|
+
async function _TideCloak_fetchAccessToken(url, code, clientId, redirectUri, pkceCodeVerifier) {
|
|
1599
|
+
const body = new URLSearchParams([
|
|
1600
|
+
['code', code],
|
|
1601
|
+
['grant_type', 'authorization_code'],
|
|
1602
|
+
['client_id', clientId],
|
|
1603
|
+
['redirect_uri', redirectUri]
|
|
1604
|
+
]);
|
|
1605
|
+
if (pkceCodeVerifier) {
|
|
1606
|
+
body.append('code_verifier', pkceCodeVerifier);
|
|
1607
|
+
}
|
|
1608
|
+
/** @type {Record<string, string>} */
|
|
1609
|
+
const headers = {};
|
|
1610
|
+
if (__classPrivateFieldGet(this, _TideCloak_dpopProvider, "f")) {
|
|
1611
|
+
const nonce = await __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f").getAuthServerNonce();
|
|
1612
|
+
headers['DPoP'] = await __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f").generateDPoPProof(url, 'POST', undefined, nonce);
|
|
1613
|
+
}
|
|
1614
|
+
try {
|
|
1615
|
+
return await fetchJSON(url, {
|
|
1616
|
+
method: 'POST',
|
|
1617
|
+
credentials: 'include',
|
|
1618
|
+
headers,
|
|
1619
|
+
body
|
|
1620
|
+
});
|
|
1621
|
+
}
|
|
1622
|
+
catch (error) {
|
|
1623
|
+
// Handle DPoP nonce retry for token endpoint
|
|
1624
|
+
if (__classPrivateFieldGet(this, _TideCloak_dpopProvider, "f") && error instanceof NetworkError) {
|
|
1625
|
+
const newNonce = error.response.headers.get('DPoP-Nonce');
|
|
1626
|
+
if (newNonce) {
|
|
1627
|
+
await __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f").updateAuthServerNonce(newNonce);
|
|
1628
|
+
headers['DPoP'] = await __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f").generateDPoPProof(url, 'POST', undefined, newNonce);
|
|
1629
|
+
return await fetchJSON(url, {
|
|
1630
|
+
method: 'POST',
|
|
1631
|
+
credentials: 'include',
|
|
1632
|
+
headers,
|
|
1633
|
+
body
|
|
1634
|
+
});
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
throw error;
|
|
1638
|
+
}
|
|
1639
|
+
}, _TideCloak_fetchRefreshToken =
|
|
1640
|
+
/**
|
|
1641
|
+
* Fetch the refresh token from the given URL.
|
|
1642
|
+
* @param {string} url
|
|
1643
|
+
* @param {string} refreshToken
|
|
1644
|
+
* @param {string} clientId
|
|
1645
|
+
* @returns {Promise<AccessTokenResponse>}
|
|
1646
|
+
*/
|
|
1647
|
+
async function _TideCloak_fetchRefreshToken(url, refreshToken, clientId) {
|
|
1648
|
+
const body = new URLSearchParams([
|
|
1649
|
+
['grant_type', 'refresh_token'],
|
|
1650
|
+
['refresh_token', refreshToken],
|
|
1651
|
+
['client_id', clientId]
|
|
1652
|
+
]);
|
|
1653
|
+
/** @type {Record<string, string>} */
|
|
1654
|
+
const headers = {};
|
|
1655
|
+
if (__classPrivateFieldGet(this, _TideCloak_dpopProvider, "f")) {
|
|
1656
|
+
const nonce = await __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f").getAuthServerNonce();
|
|
1657
|
+
headers['DPoP'] = await __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f").generateDPoPProof(url, 'POST', undefined, nonce);
|
|
1658
|
+
}
|
|
1659
|
+
try {
|
|
1660
|
+
return await fetchJSON(url, {
|
|
1661
|
+
method: 'POST',
|
|
1662
|
+
credentials: 'include',
|
|
1663
|
+
headers,
|
|
1664
|
+
body
|
|
1665
|
+
});
|
|
1666
|
+
}
|
|
1667
|
+
catch (error) {
|
|
1668
|
+
// Handle DPoP nonce retry for token endpoint
|
|
1669
|
+
if (__classPrivateFieldGet(this, _TideCloak_dpopProvider, "f") && error instanceof NetworkError) {
|
|
1670
|
+
const newNonce = error.response.headers.get('DPoP-Nonce');
|
|
1671
|
+
if (newNonce) {
|
|
1672
|
+
await __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f").updateAuthServerNonce(newNonce);
|
|
1673
|
+
headers['DPoP'] = await __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f").generateDPoPProof(url, 'POST', undefined, newNonce);
|
|
1674
|
+
return await fetchJSON(url, {
|
|
1675
|
+
method: 'POST',
|
|
1676
|
+
credentials: 'include',
|
|
1677
|
+
headers,
|
|
1678
|
+
body
|
|
1679
|
+
});
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
throw error;
|
|
1683
|
+
}
|
|
1684
|
+
}, _TideCloak_ensureRequestEnclaveOpen = function _TideCloak_ensureRequestEnclaveOpen() {
|
|
1685
|
+
if (!this.requestEnclave)
|
|
1686
|
+
return;
|
|
1687
|
+
this.requestEnclave.checkEnclaveOpen();
|
|
1468
1688
|
}, _TideCloak_getVoucherUrl = function _TideCloak_getVoucherUrl() {
|
|
1469
1689
|
if (!this.tokenParsed)
|
|
1470
1690
|
throw new Error('User authentication required to access voucher service');
|
|
@@ -1660,8 +1880,8 @@ const STORAGE_KEY_PREFIX = 'kc-callback-';
|
|
|
1660
1880
|
* @property {string} state
|
|
1661
1881
|
* @property {string} nonce
|
|
1662
1882
|
* @property {string} redirectUri
|
|
1663
|
-
* @property {
|
|
1664
|
-
* @property {
|
|
1883
|
+
* @property {TideCloakLoginOptions} [loginOptions]
|
|
1884
|
+
* @property {TideCloakLoginOptions['prompt']} [prompt]
|
|
1665
1885
|
* @property {string} [pkceCodeVerifier]
|
|
1666
1886
|
*/
|
|
1667
1887
|
/**
|
|
@@ -1849,7 +2069,7 @@ async function sha256Digest(message) {
|
|
|
1849
2069
|
}
|
|
1850
2070
|
/**
|
|
1851
2071
|
* @param {string} token
|
|
1852
|
-
* @returns {
|
|
2072
|
+
* @returns {TideCloakTokenParsed}
|
|
1853
2073
|
*/
|
|
1854
2074
|
function decodeToken(token) {
|
|
1855
2075
|
const [, payload] = token.split('.');
|
|
@@ -1937,59 +2157,6 @@ async function fetchJsonConfig(url) {
|
|
|
1937
2157
|
async function fetchOpenIdConfig(url) {
|
|
1938
2158
|
return await fetchJSON(url);
|
|
1939
2159
|
}
|
|
1940
|
-
/**
|
|
1941
|
-
* @typedef {Object} AccessTokenResponse The successful token response from the authorization server, based on the {@link https://datatracker.ietf.org/doc/html/rfc6749#section-5.1 OAuth 2.0 Authorization Framework specification}.
|
|
1942
|
-
* @property {string} access_token The access token issued by the authorization server.
|
|
1943
|
-
* @property {string} token_type The type of the token issued by the authorization server.
|
|
1944
|
-
* @property {number} [expires_in] The lifetime in seconds of the access token.
|
|
1945
|
-
* @property {string} [refresh_token] The refresh token issued by the authorization server.
|
|
1946
|
-
* @property {string} [id_token] The ID token issued by the authorization server, if requested.
|
|
1947
|
-
* @property {string} [scope] The scope of the access token.
|
|
1948
|
-
*/
|
|
1949
|
-
/**
|
|
1950
|
-
* Fetch the access token from the given URL.
|
|
1951
|
-
* @param {string} url
|
|
1952
|
-
* @param {string} code
|
|
1953
|
-
* @param {string} clientId
|
|
1954
|
-
* @param {string} redirectUri
|
|
1955
|
-
* @param {string} [pkceCodeVerifier]
|
|
1956
|
-
* @returns {Promise<AccessTokenResponse>}
|
|
1957
|
-
*/
|
|
1958
|
-
async function fetchAccessToken(url, code, clientId, redirectUri, pkceCodeVerifier) {
|
|
1959
|
-
const body = new URLSearchParams([
|
|
1960
|
-
['code', code],
|
|
1961
|
-
['grant_type', 'authorization_code'],
|
|
1962
|
-
['client_id', clientId],
|
|
1963
|
-
['redirect_uri', stripHash(redirectUri)]
|
|
1964
|
-
]);
|
|
1965
|
-
if (pkceCodeVerifier) {
|
|
1966
|
-
body.append('code_verifier', pkceCodeVerifier);
|
|
1967
|
-
}
|
|
1968
|
-
return await fetchJSON(url, {
|
|
1969
|
-
method: 'POST',
|
|
1970
|
-
credentials: 'include',
|
|
1971
|
-
body
|
|
1972
|
-
});
|
|
1973
|
-
}
|
|
1974
|
-
/**
|
|
1975
|
-
* Fetch the refresh token from the given URL.
|
|
1976
|
-
* @param {string} url
|
|
1977
|
-
* @param {string} refreshToken
|
|
1978
|
-
* @param {string} clientId
|
|
1979
|
-
* @returns {Promise<AccessTokenResponse>}
|
|
1980
|
-
*/
|
|
1981
|
-
async function fetchRefreshToken(url, refreshToken, clientId) {
|
|
1982
|
-
const body = new URLSearchParams([
|
|
1983
|
-
['grant_type', 'refresh_token'],
|
|
1984
|
-
['refresh_token', refreshToken],
|
|
1985
|
-
['client_id', clientId]
|
|
1986
|
-
]);
|
|
1987
|
-
return await fetchJSON(url, {
|
|
1988
|
-
method: 'POST',
|
|
1989
|
-
credentials: 'include',
|
|
1990
|
-
body
|
|
1991
|
-
});
|
|
1992
|
-
}
|
|
1993
2160
|
/**
|
|
1994
2161
|
* @template [T=unknown]
|
|
1995
2162
|
* @param {string} url
|
|
@@ -2034,15 +2201,6 @@ function buildAuthorizationHeader(token) {
|
|
|
2034
2201
|
function stripTrailingSlash(url) {
|
|
2035
2202
|
return url.endsWith('/') ? url.slice(0, -1) : url;
|
|
2036
2203
|
}
|
|
2037
|
-
/**
|
|
2038
|
-
* @param {string} url
|
|
2039
|
-
* @returns {string}
|
|
2040
|
-
*/
|
|
2041
|
-
function stripHash(url) {
|
|
2042
|
-
const parsedUrl = new URL(url);
|
|
2043
|
-
parsedUrl.hash = '';
|
|
2044
|
-
return parsedUrl.toString();
|
|
2045
|
-
}
|
|
2046
2204
|
/**
|
|
2047
2205
|
* @typedef {Object} NetworkErrorOptionsProperties
|
|
2048
2206
|
* @property {Response} response
|