@aws-amplify/auth
Version:
Auth category of aws-amplify
1,071 lines • 125 kB
JavaScript
"use strict";
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var types_1 = require("./types");
var core_1 = require("@aws-amplify/core");
var amazon_cognito_identity_js_1 = require("amazon-cognito-identity-js");
var url_1 = require("url");
var OAuth_1 = tslib_1.__importDefault(require("./OAuth/OAuth"));
var urlListener_1 = tslib_1.__importDefault(require("./urlListener"));
var Errors_1 = require("./Errors");
var Auth_1 = require("./types/Auth");
var logger = new core_1.ConsoleLogger('AuthClass');
var USER_ADMIN_SCOPE = 'aws.cognito.signin.user.admin';
// 10 sec, following this guide https://www.nngroup.com/articles/response-times-3-important-limits/
var OAUTH_FLOW_MS_TIMEOUT = 10 * 1000;
var AMPLIFY_SYMBOL = (typeof Symbol !== 'undefined' && typeof Symbol.for === 'function'
? Symbol.for('amplify_default')
: '@@amplify_default');
var dispatchAuthEvent = function (event, data, message) {
core_1.Hub.dispatch('auth', { event: event, data: data, message: message }, 'Auth', AMPLIFY_SYMBOL);
};
// Cognito Documentation for max device
// tslint:disable-next-line:max-line-length
// https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ListDevices.html#API_ListDevices_RequestSyntax
var MAX_DEVICES = 60;
var MAX_AUTOSIGNIN_POLLING_MS = 3 * 60 * 1000;
/**
* Provide authentication steps
*/
var AuthClass = /** @class */ (function () {
/**
* Initialize Auth with AWS configurations
* @param {Object} config - Configuration of the Auth
*/
function AuthClass(config) {
var _this = this;
this.userPool = null;
this.user = null;
this.oAuthFlowInProgress = false;
this.autoSignInInitiated = false;
this.inflightSessionPromise = null;
this.inflightSessionPromiseCounter = 0;
this.Credentials = core_1.Credentials;
this.wrapRefreshSessionCallback = function (callback) {
var wrapped = function (error, data) {
if (data) {
dispatchAuthEvent('tokenRefresh', undefined, "New token retrieved");
}
else {
dispatchAuthEvent('tokenRefresh_failure', error, "Failed to retrieve new token");
}
return callback(error, data);
};
return wrapped;
}; // prettier-ignore
this.configure(config);
this.currentCredentials = this.currentCredentials.bind(this);
this.currentUserCredentials = this.currentUserCredentials.bind(this);
core_1.Hub.listen('auth', function (_a) {
var payload = _a.payload;
var event = payload.event;
switch (event) {
case 'verify':
case 'signIn':
_this._storage.setItem('amplify-signin-with-hostedUI', 'false');
break;
case 'signOut':
_this._storage.removeItem('amplify-signin-with-hostedUI');
break;
case 'cognitoHostedUI':
_this._storage.setItem('amplify-signin-with-hostedUI', 'true');
break;
}
});
}
AuthClass.prototype.getModuleName = function () {
return 'Auth';
};
AuthClass.prototype.configure = function (config) {
var _this = this;
if (!config)
return this._config || {};
logger.debug('configure Auth');
var conf = Object.assign({}, this._config, core_1.parseAWSExports(config).Auth, config);
this._config = conf;
var _a = this._config, userPoolId = _a.userPoolId, userPoolWebClientId = _a.userPoolWebClientId, cookieStorage = _a.cookieStorage, oauth = _a.oauth, region = _a.region, identityPoolId = _a.identityPoolId, mandatorySignIn = _a.mandatorySignIn, refreshHandlers = _a.refreshHandlers, identityPoolRegion = _a.identityPoolRegion, clientMetadata = _a.clientMetadata, endpoint = _a.endpoint, storage = _a.storage;
if (!storage) {
// backward compatability
if (cookieStorage)
this._storage = new amazon_cognito_identity_js_1.CookieStorage(cookieStorage);
else {
this._storage = config.ssr
? new core_1.UniversalStorage()
: new core_1.StorageHelper().getStorage();
}
}
else {
if (!this._isValidAuthStorage(storage)) {
logger.error('The storage in the Auth config is not valid!');
throw new Error('Empty storage object');
}
this._storage = storage;
}
this._storageSync = Promise.resolve();
if (typeof this._storage['sync'] === 'function') {
this._storageSync = this._storage['sync']();
}
if (userPoolId) {
var userPoolData = {
UserPoolId: userPoolId,
ClientId: userPoolWebClientId,
endpoint: endpoint,
};
userPoolData.Storage = this._storage;
this.userPool = new amazon_cognito_identity_js_1.CognitoUserPool(userPoolData, this.wrapRefreshSessionCallback);
}
this.Credentials.configure({
mandatorySignIn: mandatorySignIn,
region: region,
userPoolId: userPoolId,
identityPoolId: identityPoolId,
refreshHandlers: refreshHandlers,
storage: this._storage,
identityPoolRegion: identityPoolRegion,
});
// initialize cognitoauth client if hosted ui options provided
// to keep backward compatibility:
var cognitoHostedUIConfig = oauth
? types_1.isCognitoHostedOpts(this._config.oauth)
? oauth
: oauth.awsCognito
: undefined;
if (cognitoHostedUIConfig) {
var cognitoAuthParams = Object.assign({
cognitoClientId: userPoolWebClientId,
UserPoolId: userPoolId,
domain: cognitoHostedUIConfig['domain'],
scopes: cognitoHostedUIConfig['scope'],
redirectSignIn: cognitoHostedUIConfig['redirectSignIn'],
redirectSignOut: cognitoHostedUIConfig['redirectSignOut'],
responseType: cognitoHostedUIConfig['responseType'],
Storage: this._storage,
urlOpener: cognitoHostedUIConfig['urlOpener'],
clientMetadata: clientMetadata,
}, cognitoHostedUIConfig['options']);
this._oAuthHandler = new OAuth_1.default({
scopes: cognitoAuthParams.scopes,
config: cognitoAuthParams,
cognitoClientId: cognitoAuthParams.cognitoClientId,
});
// **NOTE** - Remove this in a future major release as it is a breaking change
// Prevents _handleAuthResponse from being called multiple times in Expo
// See https://github.com/aws-amplify/amplify-js/issues/4388
var usedResponseUrls_1 = {};
urlListener_1.default(function (_a) {
var url = _a.url;
if (usedResponseUrls_1[url]) {
return;
}
usedResponseUrls_1[url] = true;
_this._handleAuthResponse(url);
});
}
dispatchAuthEvent('configured', null, "The Auth category has been configured successfully");
if (!this.autoSignInInitiated &&
typeof this._storage['getItem'] === 'function') {
var pollingInitiated = this.isTrueStorageValue('amplify-polling-started');
if (pollingInitiated) {
dispatchAuthEvent('autoSignIn_failure', null, Auth_1.AuthErrorTypes.AutoSignInError);
this._storage.removeItem('amplify-auto-sign-in');
}
this._storage.removeItem('amplify-polling-started');
}
return this._config;
};
/**
* Sign up with username, password and other attributes like phone, email
* @param {String | object} params - The user attributes used for signin
* @param {String[]} restOfAttrs - for the backward compatability
* @return - A promise resolves callback data if success
*/
AuthClass.prototype.signUp = function (params) {
var _this = this;
var restOfAttrs = [];
for (var _i = 1; _i < arguments.length; _i++) {
restOfAttrs[_i - 1] = arguments[_i];
}
var _a, _b, _c;
if (!this.userPool) {
return this.rejectNoUserPool();
}
var username = null;
var password = null;
var attributes = [];
var validationData = null;
var clientMetadata;
var autoSignIn = { enabled: false };
var autoSignInValidationData = {};
var autoSignInClientMetaData = {};
if (params && typeof params === 'string') {
username = params;
password = restOfAttrs ? restOfAttrs[0] : null;
var email = restOfAttrs ? restOfAttrs[1] : null;
var phone_number = restOfAttrs ? restOfAttrs[2] : null;
if (email)
attributes.push(new amazon_cognito_identity_js_1.CognitoUserAttribute({ Name: 'email', Value: email }));
if (phone_number)
attributes.push(new amazon_cognito_identity_js_1.CognitoUserAttribute({
Name: 'phone_number',
Value: phone_number,
}));
}
else if (params && typeof params === 'object') {
username = params['username'];
password = params['password'];
if (params && params.clientMetadata) {
clientMetadata = params.clientMetadata;
}
else if (this._config.clientMetadata) {
clientMetadata = this._config.clientMetadata;
}
var attrs_1 = params['attributes'];
if (attrs_1) {
Object.keys(attrs_1).map(function (key) {
attributes.push(new amazon_cognito_identity_js_1.CognitoUserAttribute({ Name: key, Value: attrs_1[key] }));
});
}
var validationDataObject_1 = params['validationData'];
if (validationDataObject_1) {
validationData = [];
Object.keys(validationDataObject_1).map(function (key) {
validationData.push(new amazon_cognito_identity_js_1.CognitoUserAttribute({
Name: key,
Value: validationDataObject_1[key],
}));
});
}
autoSignIn = (_a = params.autoSignIn) !== null && _a !== void 0 ? _a : { enabled: false };
if (autoSignIn.enabled) {
this._storage.setItem('amplify-auto-sign-in', 'true');
autoSignInValidationData = (_b = autoSignIn.validationData) !== null && _b !== void 0 ? _b : {};
autoSignInClientMetaData = (_c = autoSignIn.clientMetaData) !== null && _c !== void 0 ? _c : {};
}
}
else {
return this.rejectAuthError(Auth_1.AuthErrorTypes.SignUpError);
}
if (!username) {
return this.rejectAuthError(Auth_1.AuthErrorTypes.EmptyUsername);
}
if (!password) {
return this.rejectAuthError(Auth_1.AuthErrorTypes.EmptyPassword);
}
logger.debug('signUp attrs:', attributes);
logger.debug('signUp validation data:', validationData);
return new Promise(function (resolve, reject) {
_this.userPool.signUp(username, password, attributes, validationData, function (err, data) {
if (err) {
dispatchAuthEvent('signUp_failure', err, username + " failed to signup");
reject(err);
}
else {
dispatchAuthEvent('signUp', data, username + " has signed up successfully");
if (autoSignIn.enabled) {
_this.handleAutoSignIn(username, password, autoSignInValidationData, autoSignInClientMetaData, data);
}
resolve(data);
}
}, clientMetadata);
});
};
AuthClass.prototype.handleAutoSignIn = function (username, password, validationData, clientMetadata, data) {
this.autoSignInInitiated = true;
var authDetails = new amazon_cognito_identity_js_1.AuthenticationDetails({
Username: username,
Password: password,
ValidationData: validationData,
ClientMetadata: clientMetadata,
});
if (data.userConfirmed) {
this.signInAfterUserConfirmed(authDetails);
}
else if (this._config.signUpVerificationMethod === 'link') {
this.handleLinkAutoSignIn(authDetails);
}
else {
this.handleCodeAutoSignIn(authDetails);
}
};
AuthClass.prototype.handleCodeAutoSignIn = function (authDetails) {
var _this = this;
var listenEvent = function (_a) {
var payload = _a.payload;
if (payload.event === 'confirmSignUp') {
_this.signInAfterUserConfirmed(authDetails, listenEvent);
}
};
core_1.Hub.listen('auth', listenEvent);
};
AuthClass.prototype.handleLinkAutoSignIn = function (authDetails) {
var _this = this;
this._storage.setItem('amplify-polling-started', 'true');
var start = Date.now();
var autoSignInPollingIntervalId = setInterval(function () {
if (Date.now() - start > MAX_AUTOSIGNIN_POLLING_MS) {
clearInterval(autoSignInPollingIntervalId);
dispatchAuthEvent('autoSignIn_failure', null, 'Please confirm your account and use your credentials to sign in.');
_this._storage.removeItem('amplify-auto-sign-in');
}
else {
_this.signInAfterUserConfirmed(authDetails, null, autoSignInPollingIntervalId);
}
}, 5000);
};
AuthClass.prototype.signInAfterUserConfirmed = function (authDetails, listenEvent, autoSignInPollingIntervalId) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var user, error_1;
var _this = this;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
user = this.createCognitoUser(authDetails.getUsername());
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, user.authenticateUser(authDetails, this.authCallbacks(user, function (value) {
dispatchAuthEvent('autoSignIn', value, authDetails.getUsername() + " has signed in successfully");
if (listenEvent) {
core_1.Hub.remove('auth', listenEvent);
}
if (autoSignInPollingIntervalId) {
clearInterval(autoSignInPollingIntervalId);
_this._storage.removeItem('amplify-polling-started');
}
_this._storage.removeItem('amplify-auto-sign-in');
}, function (error) {
logger.error(error);
_this._storage.removeItem('amplify-auto-sign-in');
}))];
case 2:
_a.sent();
return [3 /*break*/, 4];
case 3:
error_1 = _a.sent();
logger.error(error_1);
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
}
});
});
};
/**
* Send the verification code to confirm sign up
* @param {String} username - The username to be confirmed
* @param {String} code - The verification code
* @param {ConfirmSignUpOptions} options - other options for confirm signup
* @return - A promise resolves callback data if success
*/
AuthClass.prototype.confirmSignUp = function (username, code, options) {
var _this = this;
if (!this.userPool) {
return this.rejectNoUserPool();
}
if (!username) {
return this.rejectAuthError(Auth_1.AuthErrorTypes.EmptyUsername);
}
if (!code) {
return this.rejectAuthError(Auth_1.AuthErrorTypes.EmptyCode);
}
var user = this.createCognitoUser(username);
var forceAliasCreation = options && typeof options.forceAliasCreation === 'boolean'
? options.forceAliasCreation
: true;
var clientMetadata;
if (options && options.clientMetadata) {
clientMetadata = options.clientMetadata;
}
else if (this._config.clientMetadata) {
clientMetadata = this._config.clientMetadata;
}
return new Promise(function (resolve, reject) {
user.confirmRegistration(code, forceAliasCreation, function (err, data) {
if (err) {
reject(err);
}
else {
dispatchAuthEvent('confirmSignUp', data, username + " has been confirmed successfully");
var autoSignIn = _this.isTrueStorageValue('amplify-auto-sign-in');
if (autoSignIn && !_this.autoSignInInitiated) {
dispatchAuthEvent('autoSignIn_failure', null, Auth_1.AuthErrorTypes.AutoSignInError);
_this._storage.removeItem('amplify-auto-sign-in');
}
resolve(data);
}
}, clientMetadata);
});
};
AuthClass.prototype.isTrueStorageValue = function (value) {
var item = this._storage.getItem(value);
return item ? item === 'true' : false;
};
/**
* Resend the verification code
* @param {String} username - The username to be confirmed
* @param {ClientMetadata} clientMetadata - Metadata to be passed to Cognito Lambda triggers
* @return - A promise resolves code delivery details if successful
*/
AuthClass.prototype.resendSignUp = function (username, clientMetadata) {
if (clientMetadata === void 0) { clientMetadata = this._config.clientMetadata; }
if (!this.userPool) {
return this.rejectNoUserPool();
}
if (!username) {
return this.rejectAuthError(Auth_1.AuthErrorTypes.EmptyUsername);
}
var user = this.createCognitoUser(username);
return new Promise(function (resolve, reject) {
user.resendConfirmationCode(function (err, data) {
if (err) {
reject(err);
}
else {
resolve(data);
}
}, clientMetadata);
});
};
/**
* Sign in
* @param {String | SignInOpts} usernameOrSignInOpts - The username to be signed in or the sign in options
* @param {String} pw - The password of the username
* @param {ClientMetaData} clientMetadata - Client metadata for custom workflows
* @return - A promise resolves the CognitoUser
*/
AuthClass.prototype.signIn = function (usernameOrSignInOpts, pw, clientMetadata) {
if (clientMetadata === void 0) { clientMetadata = this._config.clientMetadata; }
if (!this.userPool) {
return this.rejectNoUserPool();
}
var username = null;
var password = null;
var validationData = {};
// for backward compatibility
if (typeof usernameOrSignInOpts === 'string') {
username = usernameOrSignInOpts;
password = pw;
}
else if (types_1.isUsernamePasswordOpts(usernameOrSignInOpts)) {
if (typeof pw !== 'undefined') {
logger.warn('The password should be defined under the first parameter object!');
}
username = usernameOrSignInOpts.username;
password = usernameOrSignInOpts.password;
validationData = usernameOrSignInOpts.validationData;
}
else {
return this.rejectAuthError(Auth_1.AuthErrorTypes.InvalidUsername);
}
if (!username) {
return this.rejectAuthError(Auth_1.AuthErrorTypes.EmptyUsername);
}
var authDetails = new amazon_cognito_identity_js_1.AuthenticationDetails({
Username: username,
Password: password,
ValidationData: validationData,
ClientMetadata: clientMetadata,
});
if (password) {
return this.signInWithPassword(authDetails);
}
else {
return this.signInWithoutPassword(authDetails);
}
};
/**
* Return an object with the authentication callbacks
* @param {CognitoUser} user - the cognito user object
* @param {} resolve - function called when resolving the current step
* @param {} reject - function called when rejecting the current step
* @return - an object with the callback methods for user authentication
*/
AuthClass.prototype.authCallbacks = function (user, resolve, reject) {
var _this = this;
var that = this;
return {
onSuccess: function (session) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var cred, e_1, currentUser, e_2;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
logger.debug(session);
delete user['challengeName'];
delete user['challengeParam'];
_a.label = 1;
case 1:
_a.trys.push([1, 4, 5, 9]);
return [4 /*yield*/, this.Credentials.clear()];
case 2:
_a.sent();
return [4 /*yield*/, this.Credentials.set(session, 'session')];
case 3:
cred = _a.sent();
logger.debug('succeed to get cognito credentials', cred);
return [3 /*break*/, 9];
case 4:
e_1 = _a.sent();
logger.debug('cannot get cognito credentials', e_1);
return [3 /*break*/, 9];
case 5:
_a.trys.push([5, 7, , 8]);
return [4 /*yield*/, this.currentUserPoolUser()];
case 6:
currentUser = _a.sent();
that.user = currentUser;
dispatchAuthEvent('signIn', currentUser, "A user " + user.getUsername() + " has been signed in");
resolve(currentUser);
return [3 /*break*/, 8];
case 7:
e_2 = _a.sent();
logger.error('Failed to get the signed in user', e_2);
reject(e_2);
return [3 /*break*/, 8];
case 8: return [7 /*endfinally*/];
case 9: return [2 /*return*/];
}
});
}); },
onFailure: function (err) {
logger.debug('signIn failure', err);
dispatchAuthEvent('signIn_failure', err, user.getUsername() + " failed to signin");
reject(err);
},
customChallenge: function (challengeParam) {
logger.debug('signIn custom challenge answer required');
user['challengeName'] = 'CUSTOM_CHALLENGE';
user['challengeParam'] = challengeParam;
resolve(user);
},
mfaRequired: function (challengeName, challengeParam) {
logger.debug('signIn MFA required');
user['challengeName'] = challengeName;
user['challengeParam'] = challengeParam;
resolve(user);
},
mfaSetup: function (challengeName, challengeParam) {
logger.debug('signIn mfa setup', challengeName);
user['challengeName'] = challengeName;
user['challengeParam'] = challengeParam;
resolve(user);
},
newPasswordRequired: function (userAttributes, requiredAttributes) {
logger.debug('signIn new password');
user['challengeName'] = 'NEW_PASSWORD_REQUIRED';
user['challengeParam'] = {
userAttributes: userAttributes,
requiredAttributes: requiredAttributes,
};
resolve(user);
},
totpRequired: function (challengeName, challengeParam) {
logger.debug('signIn totpRequired');
user['challengeName'] = challengeName;
user['challengeParam'] = challengeParam;
resolve(user);
},
selectMFAType: function (challengeName, challengeParam) {
logger.debug('signIn selectMFAType', challengeName);
user['challengeName'] = challengeName;
user['challengeParam'] = challengeParam;
resolve(user);
},
};
};
/**
* Sign in with a password
* @private
* @param {AuthenticationDetails} authDetails - the user sign in data
* @return - A promise resolves the CognitoUser object if success or mfa required
*/
AuthClass.prototype.signInWithPassword = function (authDetails) {
var _this = this;
if (this.pendingSignIn) {
throw new Error('Pending sign-in attempt already in progress');
}
var user = this.createCognitoUser(authDetails.getUsername());
this.pendingSignIn = new Promise(function (resolve, reject) {
user.authenticateUser(authDetails, _this.authCallbacks(user, function (value) {
_this.pendingSignIn = null;
resolve(value);
}, function (error) {
_this.pendingSignIn = null;
reject(error);
}));
});
return this.pendingSignIn;
};
/**
* Sign in without a password
* @private
* @param {AuthenticationDetails} authDetails - the user sign in data
* @return - A promise resolves the CognitoUser object if success or mfa required
*/
AuthClass.prototype.signInWithoutPassword = function (authDetails) {
var _this = this;
var user = this.createCognitoUser(authDetails.getUsername());
user.setAuthenticationFlowType('CUSTOM_AUTH');
return new Promise(function (resolve, reject) {
user.initiateAuth(authDetails, _this.authCallbacks(user, resolve, reject));
});
};
/**
* This was previously used by an authenticated user to get MFAOptions,
* but no longer returns a meaningful response. Refer to the documentation for
* how to setup and use MFA: https://docs.amplify.aws/lib/auth/mfa/q/platform/js
* @deprecated
* @param {CognitoUser} user - the current user
* @return - A promise resolves the current preferred mfa option if success
*/
AuthClass.prototype.getMFAOptions = function (user) {
return new Promise(function (res, rej) {
user.getMFAOptions(function (err, mfaOptions) {
if (err) {
logger.debug('get MFA Options failed', err);
rej(err);
return;
}
logger.debug('get MFA options success', mfaOptions);
res(mfaOptions);
return;
});
});
};
/**
* get preferred mfa method
* @param {CognitoUser} user - the current cognito user
* @param {GetPreferredMFAOpts} params - options for getting the current user preferred MFA
*/
AuthClass.prototype.getPreferredMFA = function (user, params) {
var _this = this;
var that = this;
return new Promise(function (res, rej) {
var clientMetadata = _this._config.clientMetadata; // TODO: verify behavior if this is override during signIn
var bypassCache = params ? params.bypassCache : false;
user.getUserData(function (err, data) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var cleanUpError_1, mfaType;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!err) return [3 /*break*/, 5];
logger.debug('getting preferred mfa failed', err);
if (!this.isSessionInvalid(err)) return [3 /*break*/, 4];
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, this.cleanUpInvalidSession(user)];
case 2:
_a.sent();
return [3 /*break*/, 4];
case 3:
cleanUpError_1 = _a.sent();
rej(new Error("Session is invalid due to: " + err.message + " and failed to clean up invalid session: " + cleanUpError_1.message));
return [2 /*return*/];
case 4:
rej(err);
return [2 /*return*/];
case 5:
mfaType = that._getMfaTypeFromUserData(data);
if (!mfaType) {
rej('invalid MFA Type');
return [2 /*return*/];
}
else {
res(mfaType);
return [2 /*return*/];
}
return [2 /*return*/];
}
});
}); }, { bypassCache: bypassCache, clientMetadata: clientMetadata });
});
};
AuthClass.prototype._getMfaTypeFromUserData = function (data) {
var ret = null;
var preferredMFA = data.PreferredMfaSetting;
// if the user has used Auth.setPreferredMFA() to setup the mfa type
// then the "PreferredMfaSetting" would exist in the response
if (preferredMFA) {
ret = preferredMFA;
}
else {
// if mfaList exists but empty, then its noMFA
var mfaList = data.UserMFASettingList;
if (!mfaList) {
// if SMS was enabled by using Auth.enableSMS(),
// the response would contain MFAOptions
// as for now Cognito only supports for SMS, so we will say it is 'SMS_MFA'
// if it does not exist, then it should be NOMFA
var MFAOptions = data.MFAOptions;
if (MFAOptions) {
ret = 'SMS_MFA';
}
else {
ret = 'NOMFA';
}
}
else if (mfaList.length === 0) {
ret = 'NOMFA';
}
else {
logger.debug('invalid case for getPreferredMFA', data);
}
}
return ret;
};
AuthClass.prototype._getUserData = function (user, params) {
var _this = this;
return new Promise(function (res, rej) {
user.getUserData(function (err, data) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var cleanUpError_2;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!err) return [3 /*break*/, 5];
logger.debug('getting user data failed', err);
if (!this.isSessionInvalid(err)) return [3 /*break*/, 4];
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, this.cleanUpInvalidSession(user)];
case 2:
_a.sent();
return [3 /*break*/, 4];
case 3:
cleanUpError_2 = _a.sent();
rej(new Error("Session is invalid due to: " + err.message + " and failed to clean up invalid session: " + cleanUpError_2.message));
return [2 /*return*/];
case 4:
rej(err);
return [2 /*return*/];
case 5:
res(data);
_a.label = 6;
case 6: return [2 /*return*/];
}
});
}); }, params);
});
};
/**
* set preferred MFA method
* @param {CognitoUser} user - the current Cognito user
* @param {string} mfaMethod - preferred mfa method
* @return - A promise resolve if success
*/
AuthClass.prototype.setPreferredMFA = function (user, mfaMethod) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var clientMetadata, userData, smsMfaSettings, totpMfaSettings, _a, mfaList, currentMFAType, that;
var _this = this;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
clientMetadata = this._config.clientMetadata;
return [4 /*yield*/, this._getUserData(user, {
bypassCache: true,
clientMetadata: clientMetadata,
})];
case 1:
userData = _b.sent();
smsMfaSettings = null;
totpMfaSettings = null;
_a = mfaMethod;
switch (_a) {
case 'TOTP': return [3 /*break*/, 2];
case 'SOFTWARE_TOKEN_MFA': return [3 /*break*/, 2];
case 'SMS': return [3 /*break*/, 3];
case 'SMS_MFA': return [3 /*break*/, 3];
case 'NOMFA': return [3 /*break*/, 4];
}
return [3 /*break*/, 6];
case 2:
totpMfaSettings = {
PreferredMfa: true,
Enabled: true,
};
return [3 /*break*/, 7];
case 3:
smsMfaSettings = {
PreferredMfa: true,
Enabled: true,
};
return [3 /*break*/, 7];
case 4:
mfaList = userData['UserMFASettingList'];
return [4 /*yield*/, this._getMfaTypeFromUserData(userData)];
case 5:
currentMFAType = _b.sent();
if (currentMFAType === 'NOMFA') {
return [2 /*return*/, Promise.resolve('No change for mfa type')];
}
else if (currentMFAType === 'SMS_MFA') {
smsMfaSettings = {
PreferredMfa: false,
Enabled: false,
};
}
else if (currentMFAType === 'SOFTWARE_TOKEN_MFA') {
totpMfaSettings = {
PreferredMfa: false,
Enabled: false,
};
}
else {
return [2 /*return*/, this.rejectAuthError(Auth_1.AuthErrorTypes.InvalidMFA)];
}
// if there is a UserMFASettingList in the response
// we need to disable every mfa type in that list
if (mfaList && mfaList.length !== 0) {
// to disable SMS or TOTP if exists in that list
mfaList.forEach(function (mfaType) {
if (mfaType === 'SMS_MFA') {
smsMfaSettings = {
PreferredMfa: false,
Enabled: false,
};
}
else if (mfaType === 'SOFTWARE_TOKEN_MFA') {
totpMfaSettings = {
PreferredMfa: false,
Enabled: false,
};
}
});
}
return [3 /*break*/, 7];
case 6:
logger.debug('no validmfa method provided');
return [2 /*return*/, this.rejectAuthError(Auth_1.AuthErrorTypes.NoMFA)];
case 7:
that = this;
return [2 /*return*/, new Promise(function (res, rej) {
user.setUserMfaPreference(smsMfaSettings, totpMfaSettings, function (err, result) {
if (err) {
logger.debug('Set user mfa preference error', err);
return rej(err);
}
logger.debug('Set user mfa success', result);
logger.debug('Caching the latest user data into local');
// cache the latest result into user data
user.getUserData(function (err, data) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var cleanUpError_3;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!err) return [3 /*break*/, 5];
logger.debug('getting user data failed', err);
if (!this.isSessionInvalid(err)) return [3 /*break*/, 4];
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, this.cleanUpInvalidSession(user)];
case 2:
_a.sent();
return [3 /*break*/, 4];
case 3:
cleanUpError_3 = _a.sent();
rej(new Error("Session is invalid due to: " + err.message + " and failed to clean up invalid session: " + cleanUpError_3.message));
return [2 /*return*/];
case 4: return [2 /*return*/, rej(err)];
case 5: return [2 /*return*/, res(result)];
}
});
}); }, {
bypassCache: true,
clientMetadata: clientMetadata,
});
});
})];
}
});
});
};
/**
* disable SMS
* @deprecated
* @param {CognitoUser} user - the current user
* @return - A promise resolves is success
*/
AuthClass.prototype.disableSMS = function (user) {
return new Promise(function (res, rej) {
user.disableMFA(function (err, data) {
if (err) {
logger.debug('disable mfa failed', err);
rej(err);
return;
}
logger.debug('disable mfa succeed', data);
res(data);
return;
});
});
};
/**
* enable SMS
* @deprecated
* @param {CognitoUser} user - the current user
* @return - A promise resolves is success
*/
AuthClass.prototype.enableSMS = function (user) {
return new Promise(function (res, rej) {
user.enableMFA(function (err, data) {
if (err) {
logger.debug('enable mfa failed', err);
rej(err);
return;
}
logger.debug('enable mfa succeed', data);
res(data);
return;
});
});
};
/**
* Setup TOTP
* @param {CognitoUser} user - the current user
* @return - A promise resolves with the secret code if success
*/
AuthClass.prototype.setupTOTP = function (user) {
return new Promise(function (res, rej) {
user.associateSoftwareToken({
onFailure: function (err) {
logger.debug('associateSoftwareToken failed', err);
rej(err);
return;
},
associateSecretCode: function (secretCode) {
logger.debug('associateSoftwareToken sucess', secretCode);
res(secretCode);
return;
},
});
});
};
/**
* verify TOTP setup
* @param {CognitoUser} user - the current user
* @param {string} challengeAnswer - challenge answer
* @return - A promise resolves is success
*/
AuthClass.prototype.verifyTotpToken = function (user, challengeAnswer) {
logger.debug('verification totp token', user, challengeAnswer);
var signInUserSession;
if (user && typeof user.getSignInUserSession === 'function') {
signInUserSession = user.getSignInUserSession();
}
var isLoggedIn = signInUserSession === null || signInUserSession === void 0 ? void 0 : signInUserSession.isValid();
return new Promise(function (res, rej) {
user.verifySoftwareToken(challengeAnswer, 'My TOTP device', {
onFailure: function (err) {
logger.debug('verifyTotpToken failed', err);
rej(err);
return;
},
onSuccess: function (data) {
if (!isLoggedIn) {
dispatchAuthEvent('signIn', user, "A user " + user.getUsername() + " has been signed in");
}
dispatchAuthEvent('verify', user, "A user " + user.getUsername() + " has been verified");
logger.debug('verifyTotpToken success', data);
res(data);
return;
},
});
});
};
/**
* Send MFA code to confirm sign in
* @param {Object} user - The CognitoUser object
* @param {String} code - The confirmation code
*/
AuthClass.prototype.confirmSignIn = function (user, code, mfaType, clientMetadata) {
var _this = this;
if (clientMetadata === void 0) { clientMetadata = this._config.clientMetadata; }
if (!code) {
return this.rejectAuthError(Auth_1.AuthErrorTypes.EmptyCode);
}
var that = this;
return new Promise(function (resolve, reject) {
user.sendMFACode(code, {
onSuccess: function (session) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var cred, e_3, currentUser, e_4;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
logger.debug(session);
_a.label = 1;
case 1:
_a.trys.push([1, 4, 5, 10]);
return [4 /*yield*/, this.Credentials.clear()];
case 2:
_a.sent();
return [4 /*yield*/, this.Credentials.set(session, 'session')];
case 3:
cred = _a.sent();
logger.debug('succeed to get cognito credentials', cred);
return [3 /*break*/, 10];
case 4:
e_3 = _a.sent();
logger.debug('cannot get cognito credentials', e_3);
return [3 /*break*/, 10];
case 5:
that.user = user;
_a.label = 6;
case 6:
_a.trys.push([6, 8, , 9]);
return [4 /*yield*/, this.currentUserPoolUser()];
case 7:
currentUser = _a.sent();
user.attributes = currentUser.attributes;
return [3 /*break*/, 9];
case 8:
e_4 = _a.sent();
logger.debug('cannot get updated Cognito User', e_4);
return [3 /*break*/, 9];
case 9:
dispatchAuthEvent('signIn', user, "A user " + user.getUsername() + " has been signed in");
resolve(user);
return [7 /*endfinally*/];
case 10: return [2 /*return*/];
}
});
}); },
onFailure: function (err) {
logger.debug('confirm signIn failure', err);
reject(err);
},
}, mfaType, clientMetadata);
});
};
AuthClass.prototype.completeNewPassword = function (user, password, requiredAttributes, clientMetadata) {
var _this = this;
if (requiredAttributes === void 0) { requiredAttributes = {}; }
if (clientMetadata === void 0) { clientMetadata = this._config.clientMetadata; }
if (!password) {
return this.rejectAuthError(Auth_1.AuthErrorTypes.EmptyPassword);
}
var that = this;
return new Promise(function (resolve, reject) {
user.completeNewPasswordChallenge(password, requiredAttributes, {
onSuccess: function (session) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var cred, e_5;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
logger.debug(session);
_a.label = 1;
case 1:
_a.trys.push([1, 4, 5, 6]);
return [4 /*yield*/, this.Credentials.clear()];
case 2:
_a.sent();
return [4 /*yield*/, this.Credentials.set(session, 'session')];
case 3:
cred = _a.sent();
logger.debug('succeed to get cognito credentials', cred);
return [3 /*break*/, 6];
case 4:
e_5 = _a.sent();
logger.debug('cannot get cognito credentials', e_5);
return [3 /*b