in packages/auth/src/Auth.ts [2086:2225]
private async _handleAuthResponse(URL?: string) {
if (this.oAuthFlowInProgress) {
logger.debug(`Skipping URL ${URL} current flow in progress`);
return;
}
try {
this.oAuthFlowInProgress = true;
if (!this._config.userPoolId) {
throw new Error(
`OAuth responses require a User Pool defined in config`
);
}
dispatchAuthEvent(
'parsingCallbackUrl',
{ url: URL },
`The callback url is being parsed`
);
const currentUrl =
URL || (JS.browserOrNode().isBrowser ? window.location.href : '');
const hasCodeOrError = !!(parse(currentUrl).query || '')
.split('&')
.map(entry => entry.split('='))
.find(([k]) => k === 'code' || k === 'error');
const hasTokenOrError = !!(parse(currentUrl).hash || '#')
.substr(1)
.split('&')
.map(entry => entry.split('='))
.find(([k]) => k === 'access_token' || k === 'error');
if (hasCodeOrError || hasTokenOrError) {
this._storage.setItem('amplify-redirected-from-hosted-ui', 'true');
try {
const { accessToken, idToken, refreshToken, state } =
await this._oAuthHandler.handleAuthResponse(currentUrl);
const session = new CognitoUserSession({
IdToken: new CognitoIdToken({ IdToken: idToken }),
RefreshToken: new CognitoRefreshToken({
RefreshToken: refreshToken,
}),
AccessToken: new CognitoAccessToken({
AccessToken: accessToken,
}),
});
let credentials;
// Get AWS Credentials & store if Identity Pool is defined
if (this._config.identityPoolId) {
credentials = await this.Credentials.set(session, 'session');
logger.debug('AWS credentials', credentials);
}
/*
Prior to the request we do sign the custom state along with the state we set. This check will verify
if there is a dash indicated when setting custom state from the request. If a dash is contained
then there is custom state present on the state string.
*/
const isCustomStateIncluded = /-/.test(state);
/*
The following is to create a user for the Cognito Identity SDK to store the tokens
When we remove this SDK later that logic will have to be centralized in our new version
*/
//#region
const currentUser = this.createCognitoUser(
session.getIdToken().decodePayload()['cognito:username']
);
// This calls cacheTokens() in Cognito SDK
currentUser.setSignInUserSession(session);
if (window && typeof window.history !== 'undefined') {
window.history.replaceState(
{},
null,
(this._config.oauth as AwsCognitoOAuthOpts).redirectSignIn
);
}
dispatchAuthEvent(
'signIn',
currentUser,
`A user ${currentUser.getUsername()} has been signed in`
);
dispatchAuthEvent(
'cognitoHostedUI',
currentUser,
`A user ${currentUser.getUsername()} has been signed in via Cognito Hosted UI`
);
if (isCustomStateIncluded) {
const customState = state.split('-').splice(1).join('-');
dispatchAuthEvent(
'customOAuthState',
urlSafeDecode(customState),
`State for user ${currentUser.getUsername()}`
);
}
//#endregion
return credentials;
} catch (err) {
logger.debug('Error in cognito hosted auth response', err);
// Just like a successful handling of `?code`, replace the window history to "dispose" of the `code`.
// Otherwise, reloading the page will throw errors as the `code` has already been spent.
if (window && typeof window.history !== 'undefined') {
window.history.replaceState(
{},
null,
(this._config.oauth as AwsCognitoOAuthOpts).redirectSignIn
);
}
dispatchAuthEvent(
'signIn_failure',
err,
`The OAuth response flow failed`
);
dispatchAuthEvent(
'cognitoHostedUI_failure',
err,
`A failure occurred when returning to the Cognito Hosted UI`
);
dispatchAuthEvent(
'customState_failure',
err,
`A failure occurred when returning state`
);
}
}
} finally {
this.oAuthFlowInProgress = false;
}
}