@okta-dfuhriman/okta-auth-js
Version:
The Okta Auth SDK
86 lines (78 loc) • 3.69 kB
text/typescript
import { IdxResponse } from "@okta/okta-auth-js";
import CookieUtil from '../../util/CookieUtil';
import AppState from '../models/AppState';
import sessionStorageHelper from './sessionStorageHelper';
import { interactionCodeFlow } from './interactionCodeFlow';
import { FORMS } from "../ion/RemediationConstants";
import transformIdxResponse from '../ion/transformIdxResponse';
function hasAuthenticationSucceeded(idxResponse: IdxResponse) {
// Check whether authentication has succeeded. This is done by checking the server response
// and seeing if either the 'success' or 'successWithInteractionCode' objects are present.
return idxResponse?.rawIdxState?.success || idxResponse?.rawIdxState?.successWithInteractionCode;
}
/**
* When "Remember My Username" is enabled, we save the identifier in a cookie
* so that the next time the user visits the SIW, the identifier field can be
* pre-filled with this value.
*/
function updateIdentifierCookie(appState: AppState, idxResponse: IdxResponse) {
const settings = appState.settings;
if (settings.get('features.rememberMe')) {
// Update the cookie with the identifier
const user = idxResponse?.context?.user;
const { identifier } = user?.value || {};
if (identifier) {
CookieUtil.setUsernameCookie(identifier);
}
} else {
// We remove the cookie explicitly if this feature is disabled.
CookieUtil.removeUsernameCookie();
}
}
export async function updateAppState(appState: AppState, idxResponse: IdxResponse): Promise<void> {
const settings = appState.settings;
// Only update the cookie when the user has successfully authenticated themselves
// to avoid incorrect/unnecessary updates.
if (hasAuthenticationSucceeded(idxResponse) && settings.get('features.rememberMyUsernameOnOIE')) {
updateIdentifierCookie(appState, idxResponse);
}
const lastResponse = appState.get('idx');
const useInteractionCodeFlow = settings.get('oauth2Enabled');
if (useInteractionCodeFlow) {
if (idxResponse.interactionCode) {
// Although session.stateHandle isn't used by interation flow,
// it's better to clean up at the end of the flow.
sessionStorageHelper.removeStateHandle();
// This is the end of the IDX flow, now entering OAuth
const tokens = await interactionCodeFlow(settings, idxResponse);
// reset terminal view in case the were OAuth errors prior to successful token retrieval
if (appState.get('currentFormName') === FORMS.TERMINAL) {
appState.unset('currentFormName', { silent: true });
}
return tokens;
}
} else {
// Do not save state handle for the first page loads.
// Because there shall be no difference between following behavior
// 1. bootstrap widget
// -> save state handle to session storage
// -> refresh page
// -> introspect using sessionStorage.stateHandle
// 2. bootstrap widget
// -> do not save state handle to session storage
// -> refresh page
// -> introspect using options.stateHandle
if (lastResponse) {
sessionStorageHelper.setStateHandle(idxResponse?.context?.stateHandle);
}
// Login flows that mimic step up (moving forward in login pipeline) via internal api calls,
// need to clear stored stateHandles.
// This way the flow can maintain the latest state handle. For eg. Device probe calls
if (appState.get('currentFormName') === FORMS.CANCEL_TRANSACTION) {
sessionStorageHelper.removeStateHandle();
}
}
// transform response
const ionResponse = transformIdxResponse(settings, idxResponse, lastResponse);
await appState.setIonResponse(ionResponse);
}