@tidecloak/js 0.13.14 → 0.13.15
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 +631 -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 +631 -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_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,494 @@ 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
|
+
return this.authenticated;
|
|
233
|
+
};
|
|
234
|
+
/**
|
|
235
|
+
* @param {TideCloakLoginOptions} [options]
|
|
236
|
+
* @returns {Promise<void>}
|
|
237
|
+
*/
|
|
238
|
+
this.login = (options) => {
|
|
239
|
+
return __classPrivateFieldGet(this, _TideCloak_adapter, "f").login(options);
|
|
240
|
+
};
|
|
241
|
+
/**
|
|
242
|
+
* @param {TideCloakLoginOptions} [options]
|
|
243
|
+
* @returns {Promise<string>}
|
|
244
|
+
*/
|
|
245
|
+
this.createLoginUrl = async (options) => {
|
|
246
|
+
const state = createUUID();
|
|
247
|
+
const nonce = createUUID();
|
|
248
|
+
const redirectUri = __classPrivateFieldGet(this, _TideCloak_adapter, "f").redirectUri(options);
|
|
249
|
+
/** @type {CallbackState} */
|
|
250
|
+
const callbackState = {
|
|
251
|
+
state,
|
|
252
|
+
nonce,
|
|
253
|
+
redirectUri,
|
|
254
|
+
loginOptions: options
|
|
255
|
+
};
|
|
256
|
+
if (options === null || options === void 0 ? void 0 : options.prompt) {
|
|
257
|
+
callbackState.prompt = options.prompt;
|
|
258
|
+
}
|
|
259
|
+
const url = (options === null || options === void 0 ? void 0 : options.action) === 'register'
|
|
260
|
+
? this.endpoints.register()
|
|
261
|
+
: this.endpoints.authorize();
|
|
262
|
+
let scope = (options === null || options === void 0 ? void 0 : options.scope) || this.scope;
|
|
263
|
+
const scopeValues = scope ? scope.split(' ') : [];
|
|
264
|
+
// Ensure the 'openid' scope is always included.
|
|
265
|
+
if (!scopeValues.includes('openid')) {
|
|
266
|
+
scopeValues.unshift('openid');
|
|
267
|
+
}
|
|
268
|
+
scope = scopeValues.join(' ');
|
|
269
|
+
const params = new URLSearchParams([
|
|
270
|
+
['client_id', /** @type {string} */ (this.clientId)],
|
|
271
|
+
['redirect_uri', redirectUri],
|
|
272
|
+
['state', state],
|
|
273
|
+
['response_mode', this.responseMode],
|
|
274
|
+
['response_type', this.responseType],
|
|
275
|
+
['scope', scope]
|
|
276
|
+
]);
|
|
277
|
+
if (__classPrivateFieldGet(this, _TideCloak_useNonce, "f")) {
|
|
278
|
+
params.append('nonce', nonce);
|
|
279
|
+
}
|
|
280
|
+
if (options === null || options === void 0 ? void 0 : options.prompt) {
|
|
281
|
+
params.append('prompt', options.prompt);
|
|
282
|
+
}
|
|
283
|
+
if (typeof (options === null || options === void 0 ? void 0 : options.maxAge) === 'number') {
|
|
284
|
+
params.append('max_age', options.maxAge.toString());
|
|
285
|
+
}
|
|
286
|
+
if (options === null || options === void 0 ? void 0 : options.loginHint) {
|
|
287
|
+
params.append('login_hint', options.loginHint);
|
|
288
|
+
}
|
|
289
|
+
if (options === null || options === void 0 ? void 0 : options.idpHint) {
|
|
290
|
+
params.append('kc_idp_hint', options.idpHint);
|
|
291
|
+
}
|
|
292
|
+
if ((options === null || options === void 0 ? void 0 : options.action) && options.action !== 'register') {
|
|
293
|
+
params.append('kc_action', options.action);
|
|
294
|
+
}
|
|
295
|
+
if (options === null || options === void 0 ? void 0 : options.locale) {
|
|
296
|
+
params.append('ui_locales', options.locale);
|
|
297
|
+
}
|
|
298
|
+
if (options === null || options === void 0 ? void 0 : options.acr) {
|
|
299
|
+
params.append('claims', buildClaimsParameter(options.acr));
|
|
300
|
+
}
|
|
301
|
+
if (options === null || options === void 0 ? void 0 : options.acrValues) {
|
|
302
|
+
params.append('acr_values', options.acrValues);
|
|
303
|
+
}
|
|
304
|
+
if (this.pkceMethod) {
|
|
305
|
+
try {
|
|
306
|
+
const codeVerifier = generateCodeVerifier(96);
|
|
307
|
+
const pkceChallenge = await generatePkceChallenge(this.pkceMethod, codeVerifier);
|
|
308
|
+
callbackState.pkceCodeVerifier = codeVerifier;
|
|
309
|
+
params.append('code_challenge', pkceChallenge);
|
|
310
|
+
params.append('code_challenge_method', this.pkceMethod);
|
|
311
|
+
}
|
|
312
|
+
catch (error) {
|
|
313
|
+
throw new Error('Failed to generate PKCE challenge.', { cause: error });
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
__classPrivateFieldGet(this, _TideCloak_callbackStorage, "f").add(callbackState);
|
|
317
|
+
return `${url}?${params.toString()}`;
|
|
318
|
+
};
|
|
319
|
+
/**
|
|
320
|
+
* @param {TideCloakLogoutOptions} [options]
|
|
321
|
+
* @returns {Promise<void>}
|
|
322
|
+
*/
|
|
323
|
+
this.logout = async (options) => {
|
|
324
|
+
var _a;
|
|
325
|
+
await ((_a = __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f")) === null || _a === void 0 ? void 0 : _a.flush());
|
|
326
|
+
return __classPrivateFieldGet(this, _TideCloak_adapter, "f").logout(options);
|
|
327
|
+
};
|
|
328
|
+
/**
|
|
329
|
+
* @param {TideCloakLogoutOptions} [options]
|
|
330
|
+
* @returns {string}
|
|
331
|
+
*/
|
|
332
|
+
this.createLogoutUrl = (options) => {
|
|
333
|
+
var _a;
|
|
334
|
+
const logoutMethod = (_a = options === null || options === void 0 ? void 0 : options.logoutMethod) !== null && _a !== void 0 ? _a : this.logoutMethod;
|
|
335
|
+
const url = this.endpoints.logout();
|
|
336
|
+
if (logoutMethod === 'POST') {
|
|
337
|
+
return url;
|
|
338
|
+
}
|
|
339
|
+
const params = new URLSearchParams([
|
|
340
|
+
['client_id', /** @type {string} */ (this.clientId)],
|
|
341
|
+
['post_logout_redirect_uri', __classPrivateFieldGet(this, _TideCloak_adapter, "f").redirectUri(options)]
|
|
342
|
+
]);
|
|
343
|
+
if (this.idToken) {
|
|
344
|
+
params.append('id_token_hint', this.idToken);
|
|
345
|
+
}
|
|
346
|
+
return `${url}?${params.toString()}`;
|
|
347
|
+
};
|
|
348
|
+
/**
|
|
349
|
+
* @param {TideCloakRegisterOptions} [options]
|
|
350
|
+
* @returns {Promise<void>}
|
|
351
|
+
*/
|
|
352
|
+
this.register = (options) => {
|
|
353
|
+
return __classPrivateFieldGet(this, _TideCloak_adapter, "f").register(options);
|
|
354
|
+
};
|
|
355
|
+
/**
|
|
356
|
+
* @param {TideCloakRegisterOptions} [options]
|
|
357
|
+
* @returns {Promise<string>}
|
|
358
|
+
*/
|
|
359
|
+
this.createRegisterUrl = (options) => {
|
|
360
|
+
return this.createLoginUrl({ ...options, action: 'register' });
|
|
361
|
+
};
|
|
362
|
+
/**
|
|
363
|
+
* @param {TideCloakAccountOptions} [options]
|
|
364
|
+
* @returns {string}
|
|
365
|
+
*/
|
|
366
|
+
this.createAccountUrl = (options) => {
|
|
367
|
+
const url = __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_getRealmUrl).call(this);
|
|
368
|
+
if (!url) {
|
|
369
|
+
throw new Error('Unable to create account URL, make sure the adapter is not configured using a generic OIDC provider.');
|
|
370
|
+
}
|
|
371
|
+
const params = new URLSearchParams([
|
|
372
|
+
['referrer', /** @type {string} */ (this.clientId)],
|
|
373
|
+
['referrer_uri', __classPrivateFieldGet(this, _TideCloak_adapter, "f").redirectUri(options)]
|
|
374
|
+
]);
|
|
375
|
+
return `${url}/account?${params.toString()}`;
|
|
376
|
+
};
|
|
377
|
+
/**
|
|
378
|
+
* @returns {Promise<void>}
|
|
379
|
+
*/
|
|
380
|
+
this.accountManagement = () => {
|
|
381
|
+
return __classPrivateFieldGet(this, _TideCloak_adapter, "f").accountManagement();
|
|
382
|
+
};
|
|
383
|
+
/**
|
|
384
|
+
* @param {string} role
|
|
385
|
+
* @returns {boolean}
|
|
386
|
+
*/
|
|
387
|
+
this.hasRealmRole = (role) => {
|
|
388
|
+
const access = this.realmAccess;
|
|
389
|
+
return !!access && access.roles.indexOf(role) >= 0;
|
|
390
|
+
};
|
|
391
|
+
/**
|
|
392
|
+
* @param {string} role
|
|
393
|
+
* @param {string} [resource]
|
|
394
|
+
* @returns {boolean}
|
|
395
|
+
*/
|
|
396
|
+
this.hasResourceRole = (role, resource) => {
|
|
397
|
+
if (!this.resourceAccess) {
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
const access = this.resourceAccess[resource || /** @type {string} */ (this.clientId)];
|
|
401
|
+
return !!access && access.roles.indexOf(role) >= 0;
|
|
402
|
+
};
|
|
403
|
+
/**
|
|
404
|
+
* @returns {Promise<TideCloakProfile>}
|
|
405
|
+
*/
|
|
406
|
+
this.loadUserProfile = async () => {
|
|
407
|
+
const realmUrl = __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_getRealmUrl).call(this);
|
|
408
|
+
if (!realmUrl) {
|
|
409
|
+
throw new Error('Unable to load user profile, make sure the adapter is not configured using a generic OIDC provider.');
|
|
410
|
+
}
|
|
411
|
+
const url = `${realmUrl}/account`;
|
|
412
|
+
/** @type {TideCloakProfile} */
|
|
413
|
+
const profile = await fetchJSON(url, {
|
|
414
|
+
headers: [buildAuthorizationHeader(this.token)]
|
|
415
|
+
});
|
|
416
|
+
return (this.profile = profile);
|
|
417
|
+
};
|
|
418
|
+
/**
|
|
419
|
+
* @returns {Promise<{}>}
|
|
420
|
+
*/
|
|
421
|
+
this.loadUserInfo = async () => {
|
|
422
|
+
const url = this.endpoints.userinfo();
|
|
423
|
+
/** @type {{}} */
|
|
424
|
+
const userInfo = await fetchJSON(url, {
|
|
425
|
+
headers: [buildAuthorizationHeader(this.token)]
|
|
426
|
+
});
|
|
427
|
+
return (this.userInfo = userInfo);
|
|
428
|
+
};
|
|
429
|
+
/**
|
|
430
|
+
* @param {number} [minValidity]
|
|
431
|
+
* @returns {boolean}
|
|
432
|
+
*/
|
|
433
|
+
this.isTokenExpired = (minValidity) => {
|
|
434
|
+
if (!this.tokenParsed || (!this.refreshToken && this.flow !== 'implicit')) {
|
|
435
|
+
throw new Error('Not authenticated');
|
|
436
|
+
}
|
|
437
|
+
if (this.timeSkew == null) {
|
|
438
|
+
__classPrivateFieldGet(this, _TideCloak_logInfo, "f").call(this, '[TIDECLOAK] Unable to determine if token is expired as timeskew is not set');
|
|
439
|
+
return true;
|
|
440
|
+
}
|
|
441
|
+
if (typeof this.tokenParsed.exp !== 'number') {
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
let expiresIn = this.tokenParsed.exp - Math.ceil(new Date().getTime() / 1000) + this.timeSkew;
|
|
445
|
+
if (minValidity) {
|
|
446
|
+
if (isNaN(minValidity)) {
|
|
447
|
+
throw new Error('Invalid minValidity');
|
|
448
|
+
}
|
|
449
|
+
expiresIn -= minValidity;
|
|
450
|
+
}
|
|
451
|
+
return expiresIn < 0;
|
|
452
|
+
};
|
|
453
|
+
/**
|
|
454
|
+
* @param {number} minValidity
|
|
455
|
+
* @returns {Promise<boolean>}
|
|
456
|
+
*/
|
|
457
|
+
this.updateToken = async (minValidity) => {
|
|
458
|
+
var _a, _b;
|
|
459
|
+
if (!this.refreshToken) {
|
|
460
|
+
throw new Error('Unable to update token, no refresh token available.');
|
|
461
|
+
}
|
|
462
|
+
minValidity = minValidity || 5;
|
|
463
|
+
if (__classPrivateFieldGet(this, _TideCloak_loginIframe, "f").enable) {
|
|
464
|
+
await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_checkLoginIframe).call(this);
|
|
465
|
+
}
|
|
466
|
+
let refreshToken = false;
|
|
467
|
+
if (minValidity === -1) {
|
|
468
|
+
refreshToken = true;
|
|
469
|
+
__classPrivateFieldGet(this, _TideCloak_logInfo, "f").call(this, '[TIDECLOAK] Refreshing token: forced refresh');
|
|
470
|
+
}
|
|
471
|
+
else if (!this.tokenParsed || this.isTokenExpired(minValidity)) {
|
|
472
|
+
refreshToken = true;
|
|
473
|
+
__classPrivateFieldGet(this, _TideCloak_logInfo, "f").call(this, '[TIDECLOAK] Refreshing token: token expired');
|
|
474
|
+
}
|
|
475
|
+
if (!refreshToken) {
|
|
476
|
+
return false;
|
|
477
|
+
}
|
|
478
|
+
/** @type {PromiseWithResolvers<boolean>} */
|
|
479
|
+
const { promise, resolve, reject } = Promise.withResolvers();
|
|
480
|
+
__classPrivateFieldGet(this, _TideCloak_refreshQueue, "f").push({ resolve, reject });
|
|
481
|
+
if (__classPrivateFieldGet(this, _TideCloak_refreshQueue, "f").length === 1) {
|
|
482
|
+
const url = this.endpoints.token();
|
|
483
|
+
let timeLocal = new Date().getTime();
|
|
484
|
+
try {
|
|
485
|
+
const response = await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_fetchRefreshToken).call(this, url, this.refreshToken, /** @type {string} */ (this.clientId));
|
|
486
|
+
__classPrivateFieldGet(this, _TideCloak_logInfo, "f").call(this, '[TIDECLOAK] Token refreshed');
|
|
487
|
+
timeLocal = (timeLocal + new Date().getTime()) / 2;
|
|
488
|
+
__classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_setToken).call(this, response.access_token, response.refresh_token, response.id_token, timeLocal, response.doken);
|
|
489
|
+
(_a = this.onAuthRefreshSuccess) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
490
|
+
for (let p = __classPrivateFieldGet(this, _TideCloak_refreshQueue, "f").pop(); p != null; p = __classPrivateFieldGet(this, _TideCloak_refreshQueue, "f").pop()) {
|
|
491
|
+
p.resolve(true);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
catch (error) {
|
|
495
|
+
__classPrivateFieldGet(this, _TideCloak_logWarn, "f").call(this, '[TIDECLOAK] Failed to refresh token');
|
|
496
|
+
if (error instanceof NetworkError && error.response.status === 400) {
|
|
497
|
+
this.clearToken();
|
|
498
|
+
}
|
|
499
|
+
(_b = this.onAuthRefreshError) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
500
|
+
for (let p = __classPrivateFieldGet(this, _TideCloak_refreshQueue, "f").pop(); p != null; p = __classPrivateFieldGet(this, _TideCloak_refreshQueue, "f").pop()) {
|
|
501
|
+
p.reject(error);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return await promise;
|
|
506
|
+
};
|
|
507
|
+
this.clearToken = () => {
|
|
508
|
+
var _a;
|
|
509
|
+
if (this.token) {
|
|
510
|
+
__classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_setToken).call(this);
|
|
511
|
+
(_a = this.onAuthLogout) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
512
|
+
if (this.loginRequired) {
|
|
513
|
+
this.login();
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
this.secureFetch = async (url, init = {}) => {
|
|
518
|
+
var _a, _b;
|
|
519
|
+
const dpopProvider = __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f");
|
|
520
|
+
if (dpopProvider && this.authenticated && this.token) {
|
|
521
|
+
const existingAuth = new Headers(init.headers).get('Authorization');
|
|
522
|
+
const isOurBearerToken = existingAuth === `Bearer ${this.token}`;
|
|
523
|
+
if (!isOurBearerToken) {
|
|
524
|
+
// Quick escape - didn't put this check in first if statement as it's more expensive than other checks
|
|
525
|
+
return fetch(url, init);
|
|
526
|
+
}
|
|
527
|
+
const urlString = url instanceof URL ? url.href : url.toString();
|
|
528
|
+
const origin = new URL(urlString).origin;
|
|
529
|
+
const method = (_a = init.method) !== null && _a !== void 0 ? _a : 'GET';
|
|
530
|
+
const resourceNonce = dpopProvider.getResourceServerNonce(origin);
|
|
531
|
+
const proof = await dpopProvider.generateDPoPProof(urlString, method, this.token, resourceNonce);
|
|
532
|
+
const headers = new Headers(init.headers);
|
|
533
|
+
headers.set('Authorization', `DPoP ${this.token}`);
|
|
534
|
+
headers.set('DPoP', proof);
|
|
535
|
+
const resp = await fetch(url, { ...init, headers });
|
|
536
|
+
// Check for new nonce in response
|
|
537
|
+
const newNonce = resp.headers.get('DPoP-Nonce');
|
|
538
|
+
if (newNonce) {
|
|
539
|
+
dpopProvider.updateResourceServerNonce(origin, newNonce);
|
|
540
|
+
}
|
|
541
|
+
// https://datatracker.ietf.org/doc/html/rfc9449#section-9
|
|
542
|
+
// Resource servers signal via: WWW-Authenticate: DPoP error="use_dpop_nonce"
|
|
543
|
+
if (resp.status === 401 && newNonce) {
|
|
544
|
+
const wwwAuth = (_b = resp.headers.get('WWW-Authenticate')) !== null && _b !== void 0 ? _b : '';
|
|
545
|
+
if (wwwAuth.includes('DPoP') && wwwAuth.includes('error="use_dpop_nonce"')) {
|
|
546
|
+
const retryProof = await dpopProvider.generateDPoPProof(urlString, method, this.token, newNonce);
|
|
547
|
+
const retryHeaders = new Headers(init.headers);
|
|
548
|
+
retryHeaders.set('Authorization', `DPoP ${this.token}`);
|
|
549
|
+
retryHeaders.set('DPoP', retryProof);
|
|
550
|
+
const retryResp = await fetch(url, { ...init, headers: retryHeaders });
|
|
551
|
+
// Capture nonce from retry response for future requests
|
|
552
|
+
const retryNonce = retryResp.headers.get('DPoP-Nonce');
|
|
553
|
+
if (retryNonce) {
|
|
554
|
+
dpopProvider.updateResourceServerNonce(origin, retryNonce);
|
|
555
|
+
}
|
|
556
|
+
return retryResp;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
return resp;
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
return fetch(url, init);
|
|
563
|
+
}
|
|
564
|
+
};
|
|
108
565
|
if (typeof config !== 'string' && !isObject(config)) {
|
|
109
566
|
throw new Error("The 'TideCloak' constructor must be provided with a configuration object, or a URL to a JSON configuration file.");
|
|
110
567
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
568
|
+
if (isObject(config)) {
|
|
569
|
+
const requiredProperties = 'oidcProvider' in config
|
|
570
|
+
? ['clientId']
|
|
571
|
+
: ['url', 'realm', 'clientId'];
|
|
572
|
+
for (const property of requiredProperties) {
|
|
573
|
+
if (!(property in config)) {
|
|
574
|
+
throw new Error(`The configuration object is missing the required '${property}' property.`);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
121
578
|
if (!globalThis.isSecureContext) {
|
|
122
579
|
__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
580
|
'Continuing to run your application insecurely will lead to unexpected behavior and breakage.\n\n' +
|
|
@@ -125,113 +582,7 @@ class TideCloak {
|
|
|
125
582
|
}
|
|
126
583
|
__classPrivateFieldSet(this, _TideCloak_config, config, "f");
|
|
127
584
|
}
|
|
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
585
|
;
|
|
228
|
-
/**
|
|
229
|
-
* @param {KeycloakLoginOptions} [options]
|
|
230
|
-
* @returns {Promise<void>}
|
|
231
|
-
*/
|
|
232
|
-
login(options) {
|
|
233
|
-
return __classPrivateFieldGet(this, _TideCloak_adapter, "f").login(options);
|
|
234
|
-
}
|
|
235
586
|
/**
|
|
236
587
|
* Ensure the access token is valid, refreshing if needed.
|
|
237
588
|
* @returns {Promise<void>}
|
|
@@ -243,283 +594,6 @@ class TideCloak {
|
|
|
243
594
|
await this.updateToken(-1);
|
|
244
595
|
}
|
|
245
596
|
}
|
|
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
597
|
/**
|
|
524
598
|
* Initialize Tide RequestEnclave.
|
|
525
599
|
*/
|
|
@@ -703,7 +777,7 @@ class TideCloak {
|
|
|
703
777
|
return decrypted.map((d, i) => (dataToSend[i].isRaw ? d : StringFromUint8Array(d)));
|
|
704
778
|
}
|
|
705
779
|
}
|
|
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) {
|
|
780
|
+
_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
781
|
if (type === 'default') {
|
|
708
782
|
return __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_loadDefaultAdapter).call(this);
|
|
709
783
|
}
|
|
@@ -717,7 +791,7 @@ _TideCloak_refreshQueue = new WeakMap(), _TideCloak_adapter = new WeakMap(), _Ti
|
|
|
717
791
|
}
|
|
718
792
|
throw new Error('invalid adapter type: ' + type);
|
|
719
793
|
}, _TideCloak_loadDefaultAdapter = function _TideCloak_loadDefaultAdapter() {
|
|
720
|
-
/** @type {
|
|
794
|
+
/** @type {TideCloakAdapter['redirectUri']}{} */
|
|
721
795
|
const redirectUri = (options) => {
|
|
722
796
|
return (options === null || options === void 0 ? void 0 : options.redirectUri) || this.redirectUri || globalThis.location.href;
|
|
723
797
|
};
|
|
@@ -1021,7 +1095,7 @@ async function _TideCloak_loadConfig() {
|
|
|
1021
1095
|
this.authServerUrl = jsonConfig['auth-server-url'];
|
|
1022
1096
|
this.realm = jsonConfig.realm;
|
|
1023
1097
|
this.clientId = jsonConfig.resource;
|
|
1024
|
-
__classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_setupEndpoints).call(this);
|
|
1098
|
+
await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_setupEndpoints).call(this);
|
|
1025
1099
|
}
|
|
1026
1100
|
else {
|
|
1027
1101
|
this.clientId = __classPrivateFieldGet(this, _TideCloak_config, "f").clientId;
|
|
@@ -1031,10 +1105,31 @@ async function _TideCloak_loadConfig() {
|
|
|
1031
1105
|
else {
|
|
1032
1106
|
this.authServerUrl = __classPrivateFieldGet(this, _TideCloak_config, "f").url;
|
|
1033
1107
|
this.realm = __classPrivateFieldGet(this, _TideCloak_config, "f").realm;
|
|
1034
|
-
__classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_setupEndpoints).call(this);
|
|
1108
|
+
await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_setupEndpoints).call(this);
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
}, _TideCloak_setupEndpoints =
|
|
1112
|
+
/**
|
|
1113
|
+
* @returns {Promise<void>}
|
|
1114
|
+
*/
|
|
1115
|
+
async function _TideCloak_setupEndpoints() {
|
|
1116
|
+
// Fetch OIDC metadata to get DPoP supported algorithms (only if DPoP is enabled)
|
|
1117
|
+
if (this.useDPoP) {
|
|
1118
|
+
const issuerUrl = __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_getIssuerUrl).call(this);
|
|
1119
|
+
if (!issuerUrl) {
|
|
1120
|
+
__classPrivateFieldGet(this, _TideCloak_logWarn, "f").call(this, '[TIDECLOAK] Cannot fetch OIDC metadata: issuer URL is not available');
|
|
1121
|
+
}
|
|
1122
|
+
else {
|
|
1123
|
+
const url = `${stripTrailingSlash(issuerUrl)}/.well-known/openid-configuration`;
|
|
1124
|
+
try {
|
|
1125
|
+
const openIdConfig = await fetchOpenIdConfig(url);
|
|
1126
|
+
this.dpopSigningAlgValuesSupported = openIdConfig.dpop_signing_alg_values_supported ? openIdConfig.dpop_signing_alg_values_supported : undefined;
|
|
1127
|
+
}
|
|
1128
|
+
catch (error) {
|
|
1129
|
+
__classPrivateFieldGet(this, _TideCloak_logWarn, "f").call(this, '[TIDECLOAK] Failed to fetch OIDC metadata for DPoP configuration: ' + (error instanceof Error ? error.message : error));
|
|
1130
|
+
}
|
|
1035
1131
|
}
|
|
1036
1132
|
}
|
|
1037
|
-
}, _TideCloak_setupEndpoints = function _TideCloak_setupEndpoints() {
|
|
1038
1133
|
this.endpoints = {
|
|
1039
1134
|
authorize: () => {
|
|
1040
1135
|
return __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_getRealmUrl).call(this) + '/protocol/openid-connect/auth';
|
|
@@ -1073,6 +1168,9 @@ async function _TideCloak_loadOidcConfig(oidcProvider) {
|
|
|
1073
1168
|
__classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_setupOidcEndpoints).call(this, oidcProvider);
|
|
1074
1169
|
}
|
|
1075
1170
|
}, _TideCloak_setupOidcEndpoints = function _TideCloak_setupOidcEndpoints(config) {
|
|
1171
|
+
// Store DPoP supported algorithms if present
|
|
1172
|
+
this.dpopSigningAlgValuesSupported = config.dpop_signing_alg_values_supported;
|
|
1173
|
+
this.issuer = config.issuer;
|
|
1076
1174
|
this.endpoints = {
|
|
1077
1175
|
authorize() {
|
|
1078
1176
|
return config.authorization_endpoint;
|
|
@@ -1102,6 +1200,11 @@ async function _TideCloak_loadOidcConfig(oidcProvider) {
|
|
|
1102
1200
|
return config.userinfo_endpoint;
|
|
1103
1201
|
}
|
|
1104
1202
|
};
|
|
1203
|
+
}, _TideCloak_getIssuerUrl = function _TideCloak_getIssuerUrl() {
|
|
1204
|
+
if (this.issuer)
|
|
1205
|
+
return this.issuer;
|
|
1206
|
+
const realmUrl = __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_getRealmUrl).call(this);
|
|
1207
|
+
return realmUrl || undefined;
|
|
1105
1208
|
}, _TideCloak_check3pCookiesSupported =
|
|
1106
1209
|
/**
|
|
1107
1210
|
* @returns {Promise<void>}
|
|
@@ -1147,14 +1250,14 @@ async function _TideCloak_check3pCookiesSupported() {
|
|
|
1147
1250
|
return await applyTimeoutToPromise(promise, this.messageReceiveTimeout, 'Timeout when waiting for 3rd party check iframe message.');
|
|
1148
1251
|
}, _TideCloak_processInit =
|
|
1149
1252
|
/**
|
|
1150
|
-
* @param {
|
|
1253
|
+
* @param {TideCloakInitOptions} initOptions
|
|
1151
1254
|
* @returns {Promise<void>}
|
|
1152
1255
|
*/
|
|
1153
1256
|
async function _TideCloak_processInit(initOptions) {
|
|
1154
1257
|
var _a, _b, _c;
|
|
1155
1258
|
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.
|
|
1259
|
+
if (callback === null || callback === void 0 ? void 0 : callback.newUrl) {
|
|
1260
|
+
window.history.replaceState(window.history.state, '', callback.newUrl);
|
|
1158
1261
|
}
|
|
1159
1262
|
if (callback && callback.valid) {
|
|
1160
1263
|
await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_setupCheckLoginIframe).call(this);
|
|
@@ -1163,7 +1266,7 @@ async function _TideCloak_processInit(initOptions) {
|
|
|
1163
1266
|
}
|
|
1164
1267
|
/** @param {boolean} prompt */
|
|
1165
1268
|
const doLogin = async (prompt) => {
|
|
1166
|
-
/** @type {
|
|
1269
|
+
/** @type {TideCloakLoginOptions} */
|
|
1167
1270
|
const options = {};
|
|
1168
1271
|
if (!prompt) {
|
|
1169
1272
|
options.prompt = 'none';
|
|
@@ -1364,28 +1467,28 @@ async function _TideCloak_checkSsoSilently() {
|
|
|
1364
1467
|
supportedParams.push('error_description');
|
|
1365
1468
|
supportedParams.push('error_uri');
|
|
1366
1469
|
const url = new URL(urlString);
|
|
1367
|
-
let
|
|
1470
|
+
let newUrl = '';
|
|
1368
1471
|
let parsed;
|
|
1369
1472
|
if (this.responseMode === 'query' && url.searchParams.size > 0) {
|
|
1370
1473
|
parsed = __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_parseCallbackParams).call(this, url.search, supportedParams);
|
|
1371
1474
|
url.search = parsed.paramsString;
|
|
1372
|
-
|
|
1475
|
+
newUrl = url.toString();
|
|
1373
1476
|
}
|
|
1374
1477
|
else if (this.responseMode === 'fragment' && url.hash.length > 0) {
|
|
1375
1478
|
parsed = __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_parseCallbackParams).call(this, url.hash.substring(1), supportedParams);
|
|
1376
|
-
url.hash =
|
|
1377
|
-
|
|
1479
|
+
url.hash = parsed.paramsString;
|
|
1480
|
+
newUrl = url.toString();
|
|
1378
1481
|
}
|
|
1379
1482
|
if (parsed === null || parsed === void 0 ? void 0 : parsed.oauthParams) {
|
|
1380
1483
|
if (this.flow === 'standard' || this.flow === 'hybrid') {
|
|
1381
1484
|
if ((parsed.oauthParams.code || parsed.oauthParams.error) && parsed.oauthParams.state) {
|
|
1382
|
-
parsed.oauthParams.
|
|
1485
|
+
parsed.oauthParams.newUrl = newUrl;
|
|
1383
1486
|
return parsed.oauthParams;
|
|
1384
1487
|
}
|
|
1385
1488
|
}
|
|
1386
1489
|
else if (this.flow === 'implicit') {
|
|
1387
1490
|
if ((parsed.oauthParams.access_token || parsed.oauthParams.error) && parsed.oauthParams.state) {
|
|
1388
|
-
parsed.oauthParams.
|
|
1491
|
+
parsed.oauthParams.newUrl = newUrl;
|
|
1389
1492
|
return parsed.oauthParams;
|
|
1390
1493
|
}
|
|
1391
1494
|
}
|
|
@@ -1445,7 +1548,7 @@ async function _TideCloak_checkSsoSilently() {
|
|
|
1445
1548
|
}
|
|
1446
1549
|
if ((this.flow !== 'implicit') && code) {
|
|
1447
1550
|
try {
|
|
1448
|
-
const response = await
|
|
1551
|
+
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
1552
|
authSuccess(response.access_token, response.refresh_token, response.id_token, response.doken);
|
|
1450
1553
|
if (this.flow === 'standard') {
|
|
1451
1554
|
(_c = this.onAuthSuccess) === null || _c === void 0 ? void 0 : _c.call(this);
|
|
@@ -1465,6 +1568,112 @@ async function _TideCloak_checkSsoSilently() {
|
|
|
1465
1568
|
await __classPrivateFieldGet(this, _TideCloak_instances, "m", _TideCloak_scheduleCheckIframe).call(this);
|
|
1466
1569
|
}
|
|
1467
1570
|
}
|
|
1571
|
+
}, _TideCloak_fetchAccessToken =
|
|
1572
|
+
/**
|
|
1573
|
+
* @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}.
|
|
1574
|
+
* @property {string} access_token The access token issued by the authorization server.
|
|
1575
|
+
* @property {string} token_type The type of the token issued by the authorization server.
|
|
1576
|
+
* @property {number} [expires_in] The lifetime in seconds of the access token.
|
|
1577
|
+
* @property {string} [refresh_token] The refresh token issued by the authorization server.
|
|
1578
|
+
* @property {string} [id_token] The ID token issued by the authorization server, if requested.
|
|
1579
|
+
* @property {string} [scope] The scope of the access token.
|
|
1580
|
+
* @property {string} [doken] The Tide doken issued by the authorization server.
|
|
1581
|
+
*/
|
|
1582
|
+
/**
|
|
1583
|
+
* Fetch the access token from the given URL.
|
|
1584
|
+
* @param {string} url
|
|
1585
|
+
* @param {string} code
|
|
1586
|
+
* @param {string} clientId
|
|
1587
|
+
* @param {string} redirectUri
|
|
1588
|
+
* @param {string} [pkceCodeVerifier]
|
|
1589
|
+
* @returns {Promise<AccessTokenResponse>}
|
|
1590
|
+
*/
|
|
1591
|
+
async function _TideCloak_fetchAccessToken(url, code, clientId, redirectUri, pkceCodeVerifier) {
|
|
1592
|
+
const body = new URLSearchParams([
|
|
1593
|
+
['code', code],
|
|
1594
|
+
['grant_type', 'authorization_code'],
|
|
1595
|
+
['client_id', clientId],
|
|
1596
|
+
['redirect_uri', redirectUri]
|
|
1597
|
+
]);
|
|
1598
|
+
if (pkceCodeVerifier) {
|
|
1599
|
+
body.append('code_verifier', pkceCodeVerifier);
|
|
1600
|
+
}
|
|
1601
|
+
/** @type {Record<string, string>} */
|
|
1602
|
+
const headers = {};
|
|
1603
|
+
if (__classPrivateFieldGet(this, _TideCloak_dpopProvider, "f")) {
|
|
1604
|
+
const nonce = await __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f").getAuthServerNonce();
|
|
1605
|
+
headers['DPoP'] = await __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f").generateDPoPProof(url, 'POST', undefined, nonce);
|
|
1606
|
+
}
|
|
1607
|
+
try {
|
|
1608
|
+
return await fetchJSON(url, {
|
|
1609
|
+
method: 'POST',
|
|
1610
|
+
credentials: 'include',
|
|
1611
|
+
headers,
|
|
1612
|
+
body
|
|
1613
|
+
});
|
|
1614
|
+
}
|
|
1615
|
+
catch (error) {
|
|
1616
|
+
// Handle DPoP nonce retry for token endpoint
|
|
1617
|
+
if (__classPrivateFieldGet(this, _TideCloak_dpopProvider, "f") && error instanceof NetworkError) {
|
|
1618
|
+
const newNonce = error.response.headers.get('DPoP-Nonce');
|
|
1619
|
+
if (newNonce) {
|
|
1620
|
+
await __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f").updateAuthServerNonce(newNonce);
|
|
1621
|
+
headers['DPoP'] = await __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f").generateDPoPProof(url, 'POST', undefined, newNonce);
|
|
1622
|
+
return await fetchJSON(url, {
|
|
1623
|
+
method: 'POST',
|
|
1624
|
+
credentials: 'include',
|
|
1625
|
+
headers,
|
|
1626
|
+
body
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
throw error;
|
|
1631
|
+
}
|
|
1632
|
+
}, _TideCloak_fetchRefreshToken =
|
|
1633
|
+
/**
|
|
1634
|
+
* Fetch the refresh token from the given URL.
|
|
1635
|
+
* @param {string} url
|
|
1636
|
+
* @param {string} refreshToken
|
|
1637
|
+
* @param {string} clientId
|
|
1638
|
+
* @returns {Promise<AccessTokenResponse>}
|
|
1639
|
+
*/
|
|
1640
|
+
async function _TideCloak_fetchRefreshToken(url, refreshToken, clientId) {
|
|
1641
|
+
const body = new URLSearchParams([
|
|
1642
|
+
['grant_type', 'refresh_token'],
|
|
1643
|
+
['refresh_token', refreshToken],
|
|
1644
|
+
['client_id', clientId]
|
|
1645
|
+
]);
|
|
1646
|
+
/** @type {Record<string, string>} */
|
|
1647
|
+
const headers = {};
|
|
1648
|
+
if (__classPrivateFieldGet(this, _TideCloak_dpopProvider, "f")) {
|
|
1649
|
+
const nonce = await __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f").getAuthServerNonce();
|
|
1650
|
+
headers['DPoP'] = await __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f").generateDPoPProof(url, 'POST', undefined, nonce);
|
|
1651
|
+
}
|
|
1652
|
+
try {
|
|
1653
|
+
return await fetchJSON(url, {
|
|
1654
|
+
method: 'POST',
|
|
1655
|
+
credentials: 'include',
|
|
1656
|
+
headers,
|
|
1657
|
+
body
|
|
1658
|
+
});
|
|
1659
|
+
}
|
|
1660
|
+
catch (error) {
|
|
1661
|
+
// Handle DPoP nonce retry for token endpoint
|
|
1662
|
+
if (__classPrivateFieldGet(this, _TideCloak_dpopProvider, "f") && error instanceof NetworkError) {
|
|
1663
|
+
const newNonce = error.response.headers.get('DPoP-Nonce');
|
|
1664
|
+
if (newNonce) {
|
|
1665
|
+
await __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f").updateAuthServerNonce(newNonce);
|
|
1666
|
+
headers['DPoP'] = await __classPrivateFieldGet(this, _TideCloak_dpopProvider, "f").generateDPoPProof(url, 'POST', undefined, newNonce);
|
|
1667
|
+
return await fetchJSON(url, {
|
|
1668
|
+
method: 'POST',
|
|
1669
|
+
credentials: 'include',
|
|
1670
|
+
headers,
|
|
1671
|
+
body
|
|
1672
|
+
});
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
throw error;
|
|
1676
|
+
}
|
|
1468
1677
|
}, _TideCloak_getVoucherUrl = function _TideCloak_getVoucherUrl() {
|
|
1469
1678
|
if (!this.tokenParsed)
|
|
1470
1679
|
throw new Error('User authentication required to access voucher service');
|
|
@@ -1660,8 +1869,8 @@ const STORAGE_KEY_PREFIX = 'kc-callback-';
|
|
|
1660
1869
|
* @property {string} state
|
|
1661
1870
|
* @property {string} nonce
|
|
1662
1871
|
* @property {string} redirectUri
|
|
1663
|
-
* @property {
|
|
1664
|
-
* @property {
|
|
1872
|
+
* @property {TideCloakLoginOptions} [loginOptions]
|
|
1873
|
+
* @property {TideCloakLoginOptions['prompt']} [prompt]
|
|
1665
1874
|
* @property {string} [pkceCodeVerifier]
|
|
1666
1875
|
*/
|
|
1667
1876
|
/**
|
|
@@ -1849,7 +2058,7 @@ async function sha256Digest(message) {
|
|
|
1849
2058
|
}
|
|
1850
2059
|
/**
|
|
1851
2060
|
* @param {string} token
|
|
1852
|
-
* @returns {
|
|
2061
|
+
* @returns {TideCloakTokenParsed}
|
|
1853
2062
|
*/
|
|
1854
2063
|
function decodeToken(token) {
|
|
1855
2064
|
const [, payload] = token.split('.');
|
|
@@ -1937,59 +2146,6 @@ async function fetchJsonConfig(url) {
|
|
|
1937
2146
|
async function fetchOpenIdConfig(url) {
|
|
1938
2147
|
return await fetchJSON(url);
|
|
1939
2148
|
}
|
|
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
2149
|
/**
|
|
1994
2150
|
* @template [T=unknown]
|
|
1995
2151
|
* @param {string} url
|
|
@@ -2034,15 +2190,6 @@ function buildAuthorizationHeader(token) {
|
|
|
2034
2190
|
function stripTrailingSlash(url) {
|
|
2035
2191
|
return url.endsWith('/') ? url.slice(0, -1) : url;
|
|
2036
2192
|
}
|
|
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
2193
|
/**
|
|
2047
2194
|
* @typedef {Object} NetworkErrorOptionsProperties
|
|
2048
2195
|
* @property {Response} response
|