@okta/okta-auth-js
Version:
The Okta Auth SDK
231 lines (227 loc) • 9.13 kB
JavaScript
/*!
* Copyright (c) 2015-present, Okta, Inc. and/or its affiliates. All rights reserved.
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
*
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and limitations under the License.
*/
import { removeNils, clone } from '../util/object.js';
import { isString } from '../util/types.js';
import { isAbsoluteUrl } from '../util/url.js';
import { STATE_TOKEN_KEY_NAME, DEFAULT_CACHE_DURATION, IOS_MAX_RETRY_COUNT } from '../constants.js';
import AuthApiError from '../errors/AuthApiError.js';
import OAuthError from '../errors/OAuthError.js';
import WWWAuthError from '../errors/WWWAuthError.js';
import { isBrowser } from '../features.js';
let dateDocumentBecameVisible = 0;
let trackDateDocumentBecameVisible;
if (isBrowser()) {
dateDocumentBecameVisible = Date.now();
trackDateDocumentBecameVisible = () => {
if (!document.hidden) {
dateDocumentBecameVisible = Date.now();
}
};
document.addEventListener('visibilitychange', trackDateDocumentBecameVisible);
}
const formatError = (sdk, error) => {
var _a;
if (error instanceof Error) {
return new AuthApiError({
errorSummary: error.message,
});
}
let resp = error;
let err;
let serverErr = {};
if (resp.responseText && isString(resp.responseText)) {
try {
serverErr = JSON.parse(resp.responseText);
}
catch (e) {
serverErr = {
errorSummary: 'Unknown error'
};
}
}
if (resp.status >= 500) {
serverErr.errorSummary = 'Unknown error';
}
if (sdk.options.transformErrorXHR) {
resp = sdk.options.transformErrorXHR(clone(resp));
}
const wwwAuthHeader = (_a = WWWAuthError.getWWWAuthenticateHeader(resp === null || resp === void 0 ? void 0 : resp.headers)) !== null && _a !== void 0 ? _a : '';
if (serverErr.error && serverErr.error_description) {
err = new OAuthError(serverErr.error, serverErr.error_description, resp);
}
else {
err = new AuthApiError(serverErr, resp, { wwwAuthHeader });
}
if (wwwAuthHeader && (resp === null || resp === void 0 ? void 0 : resp.status) >= 400 && (resp === null || resp === void 0 ? void 0 : resp.status) < 500) {
const wwwAuthErr = WWWAuthError.parseHeader(wwwAuthHeader);
if (resp.status === 403 && (wwwAuthErr === null || wwwAuthErr === void 0 ? void 0 : wwwAuthErr.error) === 'insufficient_authentication_context') {
const { max_age, acr_values } = wwwAuthErr.parameters;
err = new AuthApiError({
errorSummary: wwwAuthErr.error,
errorCauses: [{ errorSummary: wwwAuthErr.errorDescription }]
}, resp, Object.assign({
max_age: +max_age }, (acr_values && { acr_values })));
}
else if ((wwwAuthErr === null || wwwAuthErr === void 0 ? void 0 : wwwAuthErr.scheme) === 'DPoP') {
err = wwwAuthErr;
}
}
return err;
};
function httpRequest(sdk, options) {
var _a;
options = options || {};
if (sdk.options.httpRequestInterceptors) {
for (const interceptor of sdk.options.httpRequestInterceptors) {
interceptor(options);
}
}
var url = options.url, method = options.method, args = options.args, saveAuthnState = options.saveAuthnState, accessToken = options.accessToken, withCredentials = options.withCredentials === true,
storageUtil = sdk.options.storageUtil, storage = storageUtil.storage, httpCache = sdk.storageManager.getHttpCache(sdk.options.cookies), pollingIntent = options.pollingIntent, pollDelay = (_a = sdk.options.pollDelay) !== null && _a !== void 0 ? _a : 0;
if (options.cacheResponse) {
var cacheContents = httpCache.getStorage();
var cachedResponse = cacheContents[url];
if (cachedResponse && Date.now() / 1000 < cachedResponse.expiresAt) {
return Promise.resolve(cachedResponse.response);
}
}
var oktaUserAgentHeader = sdk._oktaUserAgent.getHttpHeader();
var headers = Object.assign({ 'Accept': 'application/json', 'Content-Type': 'application/json' }, oktaUserAgentHeader);
Object.assign(headers, sdk.options.headers, options.headers);
headers = removeNils(headers);
if (accessToken && isString(accessToken)) {
headers['Authorization'] = 'Bearer ' + accessToken;
}
var ajaxOptions = {
headers,
data: args || undefined,
withCredentials
};
var err, res, promise;
if (pollingIntent && isBrowser() && pollDelay > 0) {
let waitForVisibleAndAwakenDocument;
let waitForAwakenDocument;
let recursiveFetch;
let retryCount = 0;
waitForAwakenDocument = () => {
const timeSinceDocumentIsVisible = Date.now() - dateDocumentBecameVisible;
if (timeSinceDocumentIsVisible < pollDelay) {
return new Promise((resolve) => setTimeout(() => {
if (!document.hidden) {
resolve();
}
else {
resolve(waitForVisibleAndAwakenDocument());
}
}, pollDelay - timeSinceDocumentIsVisible));
}
else {
return Promise.resolve();
}
};
waitForVisibleAndAwakenDocument = () => {
if (document.hidden) {
let pageVisibilityHandler;
return new Promise((resolve) => {
pageVisibilityHandler = () => {
if (!document.hidden) {
document.removeEventListener('visibilitychange', pageVisibilityHandler);
resolve(waitForAwakenDocument());
}
};
document.addEventListener('visibilitychange', pageVisibilityHandler);
});
}
else {
return waitForAwakenDocument();
}
};
const retryableFetch = () => {
return sdk.options.httpRequestClient(method, url, ajaxOptions).catch((err) => {
const isNetworkError = (err === null || err === void 0 ? void 0 : err.message) === 'Load failed';
if (isNetworkError && retryCount < IOS_MAX_RETRY_COUNT) {
retryCount++;
return recursiveFetch();
}
throw err;
});
};
recursiveFetch = () => {
return waitForVisibleAndAwakenDocument().then(retryableFetch);
};
promise = recursiveFetch();
}
else {
promise = sdk.options.httpRequestClient(method, url, ajaxOptions);
}
return promise
.then(function (resp) {
res = resp.responseText;
if (res && isString(res)) {
res = JSON.parse(res);
if (res && typeof res === 'object' && !res.headers) {
if (Array.isArray(res)) {
res.forEach(item => {
item.headers = resp.headers;
});
}
else {
res.headers = resp.headers;
}
}
}
if (saveAuthnState) {
if (!res.stateToken) {
storage.delete(STATE_TOKEN_KEY_NAME);
}
}
if (res && res.stateToken && res.expiresAt) {
storage.set(STATE_TOKEN_KEY_NAME, res.stateToken, res.expiresAt, sdk.options.cookies);
}
if (res && options.cacheResponse) {
httpCache.updateStorage(url, {
expiresAt: Math.floor(Date.now() / 1000) + DEFAULT_CACHE_DURATION,
response: res
});
}
return res;
})
.catch(function (resp) {
err = formatError(sdk, resp);
if (err.errorCode === 'E0000011') {
storage.delete(STATE_TOKEN_KEY_NAME);
}
throw err;
});
}
function get(sdk, url, options) {
url = isAbsoluteUrl(url) ? url : sdk.getIssuerOrigin() + url;
var getOptions = {
url: url,
method: 'GET'
};
Object.assign(getOptions, options);
return httpRequest(sdk, getOptions);
}
function post(sdk, url, args, options) {
url = isAbsoluteUrl(url) ? url : sdk.getIssuerOrigin() + url;
var postOptions = {
url: url,
method: 'POST',
args: args,
saveAuthnState: true
};
Object.assign(postOptions, options);
return httpRequest(sdk, postOptions);
}
export { get, httpRequest, post };
//# sourceMappingURL=request.js.map