Skip to content

Commit

Permalink
removes support for legacy PKCE / oauth storage
Browse files Browse the repository at this point in the history
OKTA-362589
<<<Jenkins Check-In of Tested SHA: 64c5b97 for [email protected]>>>
Artifact: okta-auth-js
Files changed count: 17
PR Link: "#1181"
  • Loading branch information
aarongranick-okta committed Jul 5, 2022
1 parent 8cf02df commit f4140c7
Show file tree
Hide file tree
Showing 17 changed files with 122 additions and 1,127 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## 7.0.0

### Breaking Changes

- [#1181](https://github.com/okta/okta-auth-js/pull/1181) - Removes legacy PKCE/OAuth storage


## 6.8.0

### Other
Expand Down
6 changes: 0 additions & 6 deletions lib/OktaAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,12 +200,6 @@ class OktaAuth implements OktaAuthInterface, SigninAPI, SignoutAPI {
computeChallenge: PKCE.computeChallenge
};

// Add shims for compatibility, these will be removed in next major version. OKTA-362589
Object.assign(this.options.storageUtil || {}, {
getPKCEStorage: this.storageManager.getLegacyPKCEStorage.bind(this.storageManager),
getHttpCache: this.storageManager.getHttpCache.bind(this.storageManager),
});

this._pending = { handleLogin: false };

if (isBrowser()) {
Expand Down
21 changes: 3 additions & 18 deletions lib/StorageManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,17 @@


import {
PKCE_STORAGE_NAME,
TOKEN_STORAGE_NAME,
TRANSACTION_STORAGE_NAME,
SHARED_TRANSACTION_STORAGE_NAME,
ORIGINAL_URI_STORAGE_NAME,
IDX_RESPONSE_STORAGE_NAME,
CACHE_STORAGE_NAME,
REDIRECT_OAUTH_PARAMS_NAME
} from './constants';
import {
StorageUtil,
StorageProvider,
StorageOptions,
PKCEStorage,
CookieOptions,
TransactionStorage,
IdxResponseStorage,
Expand Down Expand Up @@ -76,7 +73,9 @@ export class StorageManager {
options.sessionCookie = true;
}

// Maintain compatibility. Automatically fallback. May change in next major version. OKTA-362589
// If both storageType and storageTypes are specified, then storageType will be used first
// If storageType cannot be used but it matches an entry in storageTypes, subsequent entries may be used as fallback
// if storageType does not match an entry in storageTypes then storageType is used with no fallback.
if (storageType && storageTypes) {
const idx = storageTypes.indexOf(storageType);
if (idx >= 0) {
Expand Down Expand Up @@ -187,18 +186,4 @@ export class StorageManager {
return new SavedObject(storage, storageKey);
}

// Will be removed in an upcoming major version. OKTA-362589
getLegacyPKCEStorage(options?: StorageOptions): PKCEStorage {
options = this.getOptionsForSection('legacy-pkce', options);
const storage = this.getStorage(options);
const storageKey = options.storageKey || PKCE_STORAGE_NAME;
return new SavedObject(storage, storageKey);
}

getLegacyOAuthParamsStorage(options?: StorageOptions): StorageProvider {
options = this.getOptionsForSection('legacy-oauth-params', options);
const storage = this.getStorage(options);
const storageKey = options.storageKey || REDIRECT_OAUTH_PARAMS_NAME;
return new SavedObject(storage, storageKey);
}
}
183 changes: 0 additions & 183 deletions lib/TransactionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,13 @@
*/


import { AuthSdkError } from './errors';
import { REDIRECT_NONCE_COOKIE_NAME, REDIRECT_OAUTH_PARAMS_NAME, REDIRECT_STATE_COOKIE_NAME } from './constants';
import { StorageManager } from './StorageManager';
import {
StorageProvider,
TransactionMeta,
isTransactionMeta,
isOAuthTransactionMeta,
PKCETransactionMeta,
OAuthTransactionMeta,
TransactionMetaOptions,
TransactionManagerOptions,
CookieStorage,
SavedIdxResponse,
IntrospectOptions
} from './types';
Expand All @@ -43,20 +37,12 @@ export interface ClearTransactionMetaOptions extends TransactionMetaOptions {
export default class TransactionManager {
options: TransactionManagerOptions;
storageManager: StorageManager;
legacyWidgetSupport: boolean;
saveNonceCookie: boolean;
saveStateCookie: boolean;
saveParamsCookie: boolean;
enableSharedStorage: boolean;
saveLastResponse: boolean;

constructor(options: TransactionManagerOptions) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.storageManager = options.storageManager!;
this.legacyWidgetSupport = options.legacyWidgetSupport === false ? false : true;
this.saveNonceCookie = options.saveNonceCookie === false ? false : true;
this.saveStateCookie = options.saveStateCookie === false ? false : true;
this.saveParamsCookie = options.saveParamsCookie === false ? false : true;
this.enableSharedStorage = options.enableSharedStorage === false ? false : true;
this.saveLastResponse = options.saveLastResponse === false ? false : true;
this.options = options;
Expand All @@ -81,19 +67,6 @@ export default class TransactionManager {
if (options.clearIdxResponse !== false) {
this.clearIdxResponse();
}

if (!this.legacyWidgetSupport) {
return;
}

// This is for compatibility with older versions of the signin widget. OKTA-304806
if (options.oauth) {
this.clearLegacyOAuthParams();
}

if (options.pkce) {
this.clearLegacyPKCE();
}
}

// eslint-disable-next-line complexity
Expand All @@ -118,47 +91,6 @@ export default class TransactionManager {
if (this.enableSharedStorage && meta.state) {
saveTransactionToSharedStorage(this.storageManager, meta.state, meta);
}

if (!options.oauth) {
return;
}

// Legacy cookie storage
if (this.saveNonceCookie || this.saveStateCookie || this.saveParamsCookie) {
const cookieStorage: CookieStorage = this.storageManager.getStorage({ storageType: 'cookie' }) as CookieStorage;

if (this.saveParamsCookie) {
const {
responseType,
state,
nonce,
scopes,
clientId,
urls,
ignoreSignature
} = meta;
const oauthParams = {
responseType,
state,
nonce,
scopes,
clientId,
urls,
ignoreSignature
};
cookieStorage.setItem(REDIRECT_OAUTH_PARAMS_NAME, JSON.stringify(oauthParams), null);
}

if (this.saveNonceCookie && meta.nonce) {
// Set nonce cookie for servers to validate nonce in id_token
cookieStorage.setItem(REDIRECT_NONCE_COOKIE_NAME, meta.nonce, null);
}

if (this.saveStateCookie && meta.state) {
// Set state cookie for servers to validate state
cookieStorage.setItem(REDIRECT_STATE_COOKIE_NAME, meta.state, null);
}
}
}

exists(options: TransactionMetaOptions = {}): boolean {
Expand Down Expand Up @@ -192,124 +124,9 @@ export default class TransactionManager {
return meta;
}

if (!this.legacyWidgetSupport) {
return null;
}

// This is for compatibility with older versions of the signin widget. OKTA-304806
if (options.oauth) {
try {
const oauthParams = this.loadLegacyOAuthParams();
Object.assign(meta, oauthParams);
} finally {
this.clearLegacyOAuthParams();
}
}

if (options.pkce) {
try {
const pkceMeta: PKCETransactionMeta = this.loadLegacyPKCE();
Object.assign(meta, pkceMeta);
} finally {
this.clearLegacyPKCE();
}
}

if (isTransactionMeta(meta)) {
return meta;
}
return null;
}

// This is for compatibility with older versions of the signin widget. OKTA-304806
clearLegacyPKCE(): void {
// clear storages
let storage: StorageProvider;

if (this.storageManager.storageUtil.testStorageType('localStorage')) {
storage = this.storageManager.getLegacyPKCEStorage({ storageType: 'localStorage' });
storage.clearStorage();
}

if (this.storageManager.storageUtil.testStorageType('sessionStorage')) {
storage = this.storageManager.getLegacyPKCEStorage({ storageType: 'sessionStorage' });
storage.clearStorage();
}
}

loadLegacyPKCE(): PKCETransactionMeta {
let storage: StorageProvider;
let obj;

// Try reading from localStorage first.
if (this.storageManager.storageUtil.testStorageType('localStorage')) {
storage = this.storageManager.getLegacyPKCEStorage({ storageType: 'localStorage' });
obj = storage.getStorage();
if (obj && obj.codeVerifier) {
return obj;
}
}

// If meta is not valid, read from sessionStorage. This is expected for more recent versions of the widget.
if (this.storageManager.storageUtil.testStorageType('sessionStorage')) {
storage = this.storageManager.getLegacyPKCEStorage({ storageType: 'sessionStorage' });
obj = storage.getStorage();
if (obj && obj.codeVerifier) {
return obj;
}
}

// If meta is not valid, throw an exception to avoid misleading server-side error
// The most likely cause of this error is trying to handle a callback twice
// eslint-disable-next-line max-len
throw new AuthSdkError('Could not load PKCE codeVerifier from storage. This may indicate the auth flow has already completed or multiple auth flows are executing concurrently.', undefined);
}

clearLegacyOAuthParams(): void {
// clear storages
let storage: StorageProvider;

if (this.storageManager.storageUtil.testStorageType('sessionStorage')) {
storage = this.storageManager.getLegacyOAuthParamsStorage({ storageType: 'sessionStorage' });
storage.clearStorage();
}

if (this.storageManager.storageUtil.testStorageType('cookie')) {
storage = this.storageManager.getLegacyOAuthParamsStorage({ storageType: 'cookie' });
storage.clearStorage();
}
}

loadLegacyOAuthParams(): OAuthTransactionMeta {
let storage: StorageProvider;
let oauthParams;

// load first from session storage
if (this.storageManager.storageUtil.testStorageType('sessionStorage')) {
storage = this.storageManager.getLegacyOAuthParamsStorage({ storageType: 'sessionStorage' });
oauthParams = storage.getStorage();
}
if (isOAuthTransactionMeta(oauthParams)) {
return oauthParams;
}

// try to load from cookie
if (this.storageManager.storageUtil.testStorageType('cookie')) {
storage = this.storageManager.getLegacyOAuthParamsStorage({ storageType: 'cookie' });
oauthParams = storage.getStorage();
}

if (isOAuthTransactionMeta(oauthParams)) {
return oauthParams;
}


throw new AuthSdkError('Unable to retrieve OAuth redirect params from storage');

// Something is there but we don't recognize it
// throw new AuthSdkError('Unable to parse the ' + REDIRECT_OAUTH_PARAMS_NAME + ' value from storage');
}

saveIdxResponse(data: SavedIdxResponse): void {
if (!this.saveLastResponse) {
return;
Expand Down
11 changes: 0 additions & 11 deletions lib/browser/browserStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
import Cookies from 'js-cookie';
import AuthSdkError from '../errors/AuthSdkError';
import {
StorageProvider,
StorageOptions,
PKCEStorage,
CookieOptions,
SimpleStorage,
StorageType,
Expand All @@ -30,15 +28,6 @@ import { isIE11OrLess } from '../features';
// Building this as an object allows us to mock the functions in our tests
var storageUtil: BrowserStorageUtil = {

// These are shimmed in `OktaAuthBase.ts`
getHttpCache(): StorageProvider {
return null as never as StorageProvider;
},

getPKCEStorage(): PKCEStorage {
return null as never as PKCEStorage;
},

// IE11 bug that Microsoft doesn't plan to fix
// https://connect.microsoft.com/IE/Feedback/Details/1496040
browserHasLocalStorage: function() {
Expand Down
3 changes: 0 additions & 3 deletions lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ export const STATE_TOKEN_KEY_NAME = 'oktaStateToken';
export const DEFAULT_POLLING_DELAY = 500;
export const DEFAULT_MAX_CLOCK_SKEW = 300;
export const DEFAULT_CACHE_DURATION = 86400;
export const REDIRECT_OAUTH_PARAMS_NAME = 'okta-oauth-redirect-params';
export const REDIRECT_STATE_COOKIE_NAME = 'okta-oauth-state';
export const REDIRECT_NONCE_COOKIE_NAME = 'okta-oauth-nonce';
export const TOKEN_STORAGE_NAME = 'okta-token-storage';
export const CACHE_STORAGE_NAME = 'okta-cache-storage';
export const PKCE_STORAGE_NAME = 'okta-pkce-storage';
Expand Down
2 changes: 1 addition & 1 deletion lib/oidc/getWithRedirect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ export async function getWithRedirect(sdk: OktaAuthOIDCInterface, options?: Toke
const tokenParams = await prepareTokenParams(sdk, options);
const meta = createOAuthMeta(sdk, tokenParams);
const requestUrl = meta.urls.authorizeUrl + buildAuthorizeParams(tokenParams);
sdk.transactionManager.save(meta, { oauth: true });
sdk.transactionManager.save(meta);
sdk.token.getWithRedirect._setLocation(requestUrl);
}
8 changes: 5 additions & 3 deletions lib/oidc/parseFromUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,14 @@ export async function parseFromUrl(sdk, options?: string | ParseFromUrlOptions):
const res: OAuthResponse = parseOAuthResponseFromUrl(sdk, options);
const state = res.state;
const oauthParams: TransactionMeta = sdk.transactionManager.load({
oauth: true,
pkce: sdk.options.pkce,
state
});
if (!oauthParams) {
return Promise.reject(new AuthSdkError('Unable to retrieve OAuth redirect params from storage'));
if (sdk.options.pkce) {
// eslint-disable-next-line max-len
throw new AuthSdkError('Could not load PKCE codeVerifier from storage. This may indicate the auth flow has already completed or multiple auth flows are executing concurrently.', undefined);
}
throw new AuthSdkError('Unable to retrieve OAuth redirect params from storage');
}
const urls: CustomUrls = oauthParams.urls as CustomUrls;
delete oauthParams.urls;
Expand Down
5 changes: 0 additions & 5 deletions lib/server/serverStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,6 @@ class ServerStorage implements StorageUtil {
return 'memory';
}

// will be removed in next version. OKTA-362589
getHttpCache() {
return null; // stubbed in server.js
}

// shared in-memory using node cache
getStorage(): SimpleStorage {
return {
Expand Down
Loading

0 comments on commit f4140c7

Please sign in to comment.