diff --git a/jest.browser.js b/jest.browser.js index 6cff302f9..a2741e5e1 100644 --- a/jest.browser.js +++ b/jest.browser.js @@ -9,7 +9,10 @@ const config = Object.assign({}, baseConfig, { testPathIgnorePatterns: baseConfig.testPathIgnorePatterns.concat([ '/test/spec/serverStorage.js', '/test/spec/features/server' - ]) + ]), + moduleNameMapper: Object.assign({}, baseConfig.moduleNameMapper, { + '^./node$': './browser' + }) }); module.exports = config; diff --git a/lib/options.ts b/lib/options.ts deleted file mode 100644 index 3010832a3..000000000 --- a/lib/options.ts +++ /dev/null @@ -1,175 +0,0 @@ -/*! - * 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. - */ - - -/* eslint-disable complexity */ -import { removeTrailingSlash, warn, removeNils } from './util'; -import { assertValidConfig } from './builderUtil'; -import { OktaAuthOptions, StorageManagerOptions } from './types'; - -import fetchRequest from './fetch/fetchRequest'; -import browserStorage from './browser/browserStorage'; -import serverStorage from './server/serverStorage'; -import { isBrowser, isHTTPS } from './features'; - -const BROWSER_STORAGE: StorageManagerOptions = { - token: { - storageTypes: [ - 'localStorage', - 'sessionStorage', - 'cookie' - ] - }, - cache: { - storageTypes: [ - 'localStorage', - 'sessionStorage', - 'cookie' - ] - }, - transaction: { - storageTypes: [ - 'sessionStorage', - 'localStorage', - 'cookie' - ] - }, - 'shared-transaction': { - storageTypes: [ - 'localStorage' - ] - }, - 'original-uri': { - storageTypes: [ - 'localStorage' - ] - } -}; - -const SERVER_STORAGE: StorageManagerOptions = { - token: { - storageTypes: [ - 'memory' - ] - }, - cache: { - storageTypes: [ - 'memory' - ] - }, - transaction: { - storageTypes: [ - 'memory' - ] - } -}; - -function getCookieSettings(args: OktaAuthOptions = {}, isHTTPS: boolean) { - // Secure cookies will be automatically used on a HTTPS connection - // Non-secure cookies will be automatically used on a HTTP connection - // secure option can override the automatic behavior - var cookieSettings = args.cookies || {}; - if (typeof cookieSettings.secure === 'undefined') { - cookieSettings.secure = isHTTPS; - } - if (typeof cookieSettings.sameSite === 'undefined') { - cookieSettings.sameSite = cookieSettings.secure ? 'none' : 'lax'; - } - - // If secure=true, but the connection is not HTTPS, set secure=false. - if (cookieSettings.secure && !isHTTPS) { - // eslint-disable-next-line no-console - warn( - 'The current page is not being served with the HTTPS protocol.\n' + - 'For security reasons, we strongly recommend using HTTPS.\n' + - 'If you cannot use HTTPS, set "cookies.secure" option to false.' - ); - cookieSettings.secure = false; - } - - // Chrome >= 80 will block cookies with SameSite=None unless they are also Secure - // If sameSite=none, but the connection is not HTTPS, set sameSite=lax. - if (cookieSettings.sameSite === 'none' && !cookieSettings.secure) { - cookieSettings.sameSite = 'lax'; - } - - return cookieSettings; -} - - -export function getDefaultOptions(): OktaAuthOptions { - const storageUtil = isBrowser() ? browserStorage : serverStorage; - const storageManager = isBrowser() ? BROWSER_STORAGE : SERVER_STORAGE; - const enableSharedStorage = isBrowser() ? true : false; // localStorage for multi-tab flows (browser only) - return { - devMode: false, - httpRequestClient: fetchRequest, - storageUtil, - storageManager, - transactionManager: { - enableSharedStorage - } - }; -} - -function mergeOptions(options, args): OktaAuthOptions { - return Object.assign({}, options, removeNils(args), { - storageManager: Object.assign({}, options.storageManager, args.storageManager), - transactionManager: Object.assign({}, options.transactionManager, args.transactionManager), - }); -} - -export function buildOptions(args: OktaAuthOptions = {}): OktaAuthOptions { - assertValidConfig(args); - args = mergeOptions(getDefaultOptions(), args); - return removeNils({ - // OIDC configuration - issuer: removeTrailingSlash(args.issuer), - tokenUrl: removeTrailingSlash(args.tokenUrl), - authorizeUrl: removeTrailingSlash(args.authorizeUrl), - userinfoUrl: removeTrailingSlash(args.userinfoUrl), - revokeUrl: removeTrailingSlash(args.revokeUrl), - logoutUrl: removeTrailingSlash(args.logoutUrl), - clientId: args.clientId, - redirectUri: args.redirectUri, - state: args.state, - scopes: args.scopes, - postLogoutRedirectUri: args.postLogoutRedirectUri, - responseMode: args.responseMode, - responseType: args.responseType, - pkce: args.pkce === false ? false : true, // PKCE defaults to true - useInteractionCodeFlow: args.useInteractionCodeFlow, - - // Internal options - httpRequestClient: args.httpRequestClient, - transformErrorXHR: args.transformErrorXHR, - transformAuthState: args.transformAuthState, - restoreOriginalUri: args.restoreOriginalUri, - storageUtil: args.storageUtil, - headers: args.headers, - devMode: !!args.devMode, - storageManager: args.storageManager, - transactionManager: args.transactionManager, - cookies: isBrowser() ? getCookieSettings(args, isHTTPS()) : args.cookies, - flow: args.flow, - codeChallenge: args.codeChallenge, - codeChallengeMethod: args.codeChallengeMethod, - recoveryToken: args.recoveryToken, - activationToken: args.activationToken, - - // Give the developer the ability to disable token signature validation. - ignoreSignature: !!args.ignoreSignature, - - // Server-side web applications - clientSecret: args.clientSecret - }); -} diff --git a/lib/options/browser.ts b/lib/options/browser.ts new file mode 100644 index 000000000..648193d3f --- /dev/null +++ b/lib/options/browser.ts @@ -0,0 +1,85 @@ +/*! + * 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. + */ + +/* eslint-disable complexity */ +import { StorageManagerOptions, OktaAuthOptions } from '../types'; +import { warn } from '../util'; + +export { default as storage } from '../browser/browserStorage'; + +export const STORAGE_MANAGER_OPTIONS: StorageManagerOptions = { + token: { + storageTypes: [ + 'localStorage', + 'sessionStorage', + 'cookie' + ] + }, + cache: { + storageTypes: [ + 'localStorage', + 'sessionStorage', + 'cookie' + ] + }, + transaction: { + storageTypes: [ + 'sessionStorage', + 'localStorage', + 'cookie' + ] + }, + 'shared-transaction': { + storageTypes: [ + 'localStorage' + ] + }, + 'original-uri': { + storageTypes: [ + 'localStorage' + ] + } +}; + +export const enableSharedStorage = true; + +export function getCookieSettings(args: OktaAuthOptions = {}, isHTTPS: boolean) { + // Secure cookies will be automatically used on a HTTPS connection + // Non-secure cookies will be automatically used on a HTTP connection + // secure option can override the automatic behavior + var cookieSettings = args.cookies || {}; + if (typeof cookieSettings.secure === 'undefined') { + cookieSettings.secure = isHTTPS; + } + if (typeof cookieSettings.sameSite === 'undefined') { + cookieSettings.sameSite = cookieSettings.secure ? 'none' : 'lax'; + } + + // If secure=true, but the connection is not HTTPS, set secure=false. + if (cookieSettings.secure && !isHTTPS) { + // eslint-disable-next-line no-console + warn( + 'The current page is not being served with the HTTPS protocol.\n' + + 'For security reasons, we strongly recommend using HTTPS.\n' + + 'If you cannot use HTTPS, set "cookies.secure" option to false.' + ); + cookieSettings.secure = false; + } + + // Chrome >= 80 will block cookies with SameSite=None unless they are also Secure + // If sameSite=none, but the connection is not HTTPS, set sameSite=lax. + if (cookieSettings.sameSite === 'none' && !cookieSettings.secure) { + cookieSettings.sameSite = 'lax'; + } + + return cookieSettings; +} diff --git a/lib/options/index.ts b/lib/options/index.ts new file mode 100644 index 000000000..4b488643f --- /dev/null +++ b/lib/options/index.ts @@ -0,0 +1,85 @@ +/*! + * 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 { removeTrailingSlash, removeNils } from '../util'; +import { assertValidConfig } from '../builderUtil'; +import { OktaAuthOptions } from '../types'; + +import fetchRequest from '../fetch/fetchRequest'; +import { storage, STORAGE_MANAGER_OPTIONS, enableSharedStorage, getCookieSettings } from './node'; +import { isHTTPS } from '../features'; + +export function getDefaultOptions(): OktaAuthOptions { + const options = { + devMode: false, + httpRequestClient: fetchRequest, + storageUtil: storage, + storageManager: STORAGE_MANAGER_OPTIONS, + transactionManager: { + enableSharedStorage + } + }; + return options; +} + +function mergeOptions(options, args): OktaAuthOptions { + return Object.assign({}, options, removeNils(args), { + storageManager: Object.assign({}, options.storageManager, args.storageManager), + transactionManager: Object.assign({}, options.transactionManager, args.transactionManager), + }); +} + +export function buildOptions(args: OktaAuthOptions = {}): OktaAuthOptions { + assertValidConfig(args); + args = mergeOptions(getDefaultOptions(), args); + return removeNils({ + // OIDC configuration + issuer: removeTrailingSlash(args.issuer), + tokenUrl: removeTrailingSlash(args.tokenUrl), + authorizeUrl: removeTrailingSlash(args.authorizeUrl), + userinfoUrl: removeTrailingSlash(args.userinfoUrl), + revokeUrl: removeTrailingSlash(args.revokeUrl), + logoutUrl: removeTrailingSlash(args.logoutUrl), + clientId: args.clientId, + redirectUri: args.redirectUri, + state: args.state, + scopes: args.scopes, + postLogoutRedirectUri: args.postLogoutRedirectUri, + responseMode: args.responseMode, + responseType: args.responseType, + pkce: args.pkce === false ? false : true, // PKCE defaults to true + useInteractionCodeFlow: args.useInteractionCodeFlow, + + // Internal options + httpRequestClient: args.httpRequestClient, + transformErrorXHR: args.transformErrorXHR, + transformAuthState: args.transformAuthState, + restoreOriginalUri: args.restoreOriginalUri, + storageUtil: args.storageUtil, + headers: args.headers, + devMode: !!args.devMode, + storageManager: args.storageManager, + transactionManager: args.transactionManager, + cookies: getCookieSettings(args, isHTTPS()), + flow: args.flow, + codeChallenge: args.codeChallenge, + codeChallengeMethod: args.codeChallengeMethod, + recoveryToken: args.recoveryToken, + activationToken: args.activationToken, + + // Give the developer the ability to disable token signature validation. + ignoreSignature: !!args.ignoreSignature, + + // Server-side web applications + clientSecret: args.clientSecret + }); +} diff --git a/lib/options/node.ts b/lib/options/node.ts new file mode 100644 index 000000000..f4bd6d7b8 --- /dev/null +++ b/lib/options/node.ts @@ -0,0 +1,40 @@ +/*! + * 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 { StorageManagerOptions, OktaAuthOptions } from '../types'; + +export { default as storage } from '../server/serverStorage'; + +export const STORAGE_MANAGER_OPTIONS: StorageManagerOptions = { + token: { + storageTypes: [ + 'memory' + ] + }, + cache: { + storageTypes: [ + 'memory' + ] + }, + transaction: { + storageTypes: [ + 'memory' + ] + } +}; + +export const enableSharedStorage = false; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars +export function getCookieSettings(args: OktaAuthOptions = {}, isHTTPS?: boolean) { + return args.cookies; +} diff --git a/test/spec/AuthStateManager.js b/test/spec/AuthStateManager.js index 39e3c6012..4d5990137 100644 --- a/test/spec/AuthStateManager.js +++ b/test/spec/AuthStateManager.js @@ -15,7 +15,8 @@ import Emitter from 'tiny-emitter'; import { AuthStateManager, INITIAL_AUTH_STATE } from '../../lib/AuthStateManager'; -import { OktaAuth, AuthSdkError } from '@okta/okta-auth-js'; +import { AuthSdkError } from '../../lib/errors'; +import { OktaAuth } from '@okta/okta-auth-js'; import tokens from '@okta/test.support/tokens'; function createAuth() { diff --git a/test/spec/OktaAuth/constructor.ts b/test/spec/OktaAuth/constructor.ts index bb1d44f88..5f9ad4e2e 100644 --- a/test/spec/OktaAuth/constructor.ts +++ b/test/spec/OktaAuth/constructor.ts @@ -98,7 +98,13 @@ describe('OktaAuth (constructor)', () => { }, transaction: { storageTypes: ['a', 'b'] - } + }, + 'original-uri': { + storageTypes: ['a'], + }, + 'shared-transaction': { + storageTypes: ['a'], + }, }; break; case 'cookies': diff --git a/webpack.common.config.js b/webpack.common.config.js index 0211a906a..bd16bac1c 100644 --- a/webpack.common.config.js +++ b/webpack.common.config.js @@ -14,7 +14,7 @@ var babelOptions = { shouldPrintComment: () => false }; -var babelExclude = /node_modules\/(?!p-cancelable|node-cache)/; +var babelExclude = /node_modules\/(?!p-cancelable)/; module.exports = { module: { @@ -44,7 +44,6 @@ module.exports = { extensions: ['.js', '.ts'], alias: { './node$': './browser', // use browser built-in objects and functions - 'node-cache': false // do not webpack node-only modules } }, plugins: [