diff --git a/packages/auth/demo/public/script.js b/packages/auth/demo/public/script.js index de941d4c0de..55c7bea41e0 100644 --- a/packages/auth/demo/public/script.js +++ b/packages/auth/demo/public/script.js @@ -296,8 +296,8 @@ function onSetPersistence() { function onSignUp() { var email = $('#signup-email').val(); var password = $('#signup-password').val(); - auth.createUserWithEmailAndPassword(email, password) - .then(onAuthSuccess, onAuthError); + auth.createUserAndRetrieveDataWithEmailAndPassword(email, password) + .then(onAuthUserCredentialSuccess, onAuthError); } @@ -307,8 +307,8 @@ function onSignUp() { function onSignInWithEmailAndPassword() { var email = $('#signin-email').val(); var password = $('#signin-password').val(); - auth.signInWithEmailAndPassword(email, password) - .then(onAuthSuccess, onAuthError); + auth.signInAndRetrieveDataWithEmailAndPassword(email, password) + .then(onAuthUserCredentialSuccess, onAuthError); } @@ -320,8 +320,8 @@ function onSignInWithCustomToken(event) { // The token can be directly specified on the html element. var token = $('#user-custom-token').val(); - auth.signInWithCustomToken(token) - .then(onAuthSuccess, onAuthError); + auth.signInAndRetrieveDataWithCustomToken(token) + .then(onAuthUserCredentialSuccess, onAuthError); } @@ -329,7 +329,8 @@ function onSignInWithCustomToken(event) { * Signs in anonymously. */ function onSignInAnonymously() { - auth.signInAnonymously().then(onAuthSuccess, onAuthError); + auth.signInAnonymouslyAndRetrieveData() + .then(onAuthUserCredentialSuccess, onAuthError); } diff --git a/packages/auth/src/additionaluserinfo.js b/packages/auth/src/additionaluserinfo.js index 23c7a17508f..70ecabb317a 100644 --- a/packages/auth/src/additionaluserinfo.js +++ b/packages/auth/src/additionaluserinfo.js @@ -95,6 +95,7 @@ fireauth.AdditionalUserInfo.fromPlainObject = function(resp) { fireauth.AdditionalUserInfo.VerifyAssertionField = { ID_TOKEN: 'idToken', IS_NEW_USER: 'isNewUser', + KIND: 'kind', PROVIDER_ID: 'providerId', RAW_USER_INFO: 'rawUserInfo', SCREEN_NAME: 'screenName' @@ -129,9 +130,23 @@ fireauth.GenericAdditionalUserInfo = function(info) { // This is internal only. throw new Error('Invalid additional user info!'); } - // Check whether user is new. If not provided, default to false. - var isNewUser = - !!info[fireauth.AdditionalUserInfo.VerifyAssertionField.IS_NEW_USER]; + // For custom token and anonymous token, set provider ID to null. + if (providerId == fireauth.idp.ProviderId.ANONYMOUS || + providerId == fireauth.idp.ProviderId.CUSTOM) { + providerId = null; + } + // Check whether user is new. Temporary Solution since backend does not return + // isNewUser field for SignupNewUserResponse. + var isNewUser = false; + if (typeof info[fireauth.AdditionalUserInfo.VerifyAssertionField.IS_NEW_USER] + !== 'undefined') { + isNewUser = + !!info[fireauth.AdditionalUserInfo.VerifyAssertionField.IS_NEW_USER]; + } else if (info[fireauth.AdditionalUserInfo.VerifyAssertionField.KIND] + === 'identitytoolkit#SignupNewUserResponse') { + //For SignupNewUserResponse, always set isNewUser to true. + isNewUser = true; + } // Set required providerId. fireauth.object.setReadonlyProperty(this, 'providerId', providerId); // Set read-only isNewUser property. diff --git a/packages/auth/src/auth.js b/packages/auth/src/auth.js index 8634104658c..7585b5b757d 100644 --- a/packages/auth/src/auth.js +++ b/packages/auth/src/auth.js @@ -1353,11 +1353,26 @@ fireauth.Auth.prototype.getIdTokenInternal = function(opt_forceRefresh) { /** - * Sign in using a custom token (Bring Your Own Auth). + * Signs in a user asynchronously using a custom token. * @param {string} token The custom token to sign in with. * @return {!goog.Promise} */ fireauth.Auth.prototype.signInWithCustomToken = function(token) { + // Get signInAndRetrieveDataWithCustomToken result and return the user only. + return this.signInAndRetrieveDataWithCustomToken(token) + .then(function(result) { + return result['user']; + }); +}; + + +/** + * Signs in a user asynchronously using a custom token and returns any + * additional user info data or credentials returned form the backend. + * @param {string} token The custom token to sign in with. + * @return {!goog.Promise} + */ +fireauth.Auth.prototype.signInAndRetrieveDataWithCustomToken = function(token) { var self = this; // Wait for the redirect state to be determined before proceeding. If critical // errors like web storage unsupported are detected, fail before RPC, instead @@ -1371,20 +1386,20 @@ fireauth.Auth.prototype.signInWithCustomToken = function(token) { // response will look like an anonymous user (no credentials visible). user.updateProperty('isAnonymous', false); // Save isAnonymous flag changes to current user in storage. - return self.handleUserStateChange_(user); - }).then(function() { - return self.currentUser_(); + self.handleUserStateChange_(user); + return result; }); }; /** - * Sign in using an email and password. + * Sign in using an email and password and returns any additional user info + * data or credentials returned form the backend. * @param {string} email The email to sign in with. * @param {string} password The password to sign in with. - * @return {!goog.Promise} + * @return {!goog.Promise} */ -fireauth.Auth.prototype.signInWithEmailAndPassword = +fireauth.Auth.prototype.signInAndRetrieveDataWithEmailAndPassword = function(email, password) { var self = this; // Wait for the redirect state to be determined before proceeding. If critical @@ -1393,12 +1408,27 @@ fireauth.Auth.prototype.signInWithEmailAndPassword = return this.redirectStateIsReady_.then(function() { return self.signInWithIdTokenProvider_( self.getRpcHandler().verifyPassword(email, password)); - }).then(function(result) { - return result['user']; }); }; +/** + * Sign in using an email and password. + * @param {string} email The email to sign in with. + * @param {string} password The password to sign in with. + * @return {!goog.Promise} + */ +fireauth.Auth.prototype.signInWithEmailAndPassword = + function(email, password) { + // Get signInAndRetrieveDataWithEmailAndPassword result and return + // the user only. + return this.signInAndRetrieveDataWithEmailAndPassword(email, password) + .then(function(result) { + return result['user']; + }); +}; + + /** * Create a new email and password account. * @param {string} email The email to sign up with. @@ -1407,6 +1437,24 @@ fireauth.Auth.prototype.signInWithEmailAndPassword = */ fireauth.Auth.prototype.createUserWithEmailAndPassword = function(email, password) { + // Get createUserAndRetrieveDataWithEmailAndPassword result and return + // the user only. + return this.createUserAndRetrieveDataWithEmailAndPassword(email, password) + .then(function(result) { + return result['user']; + }); +}; + + +/** + * Creates a new email and password account and returns any additional user + * info data or credentials returned form the backend. + * @param {string} email The email to sign up with. + * @param {string} password The password to sign up with. + * @return {!goog.Promise} + */ +fireauth.Auth.prototype.createUserAndRetrieveDataWithEmailAndPassword = + function(email, password) { var self = this; // Wait for the redirect state to be determined before proceeding. If critical // errors like web storage unsupported are detected, fail before RPC, instead @@ -1414,8 +1462,6 @@ fireauth.Auth.prototype.createUserWithEmailAndPassword = return this.redirectStateIsReady_.then(function() { return self.signInWithIdTokenProvider_( self.getRpcHandler().createAccount(email, password)); - }).then(function(result) { - return result['user']; }); }; @@ -1457,10 +1503,24 @@ fireauth.Auth.prototype.signInAndRetrieveDataWithCredential = /** - * Sign in using anonymously a user. + * Signs in a user anonymously. * @return {!goog.Promise} */ fireauth.Auth.prototype.signInAnonymously = function() { + // Get signInAnonymouslyAndRetrieveData result and return the user only. + return this.signInAnonymouslyAndRetrieveData() + .then(function(result) { + return result['user']; + }); +}; + + +/** + * Signs in a user anonymously and returns any additional user info data or + * credentials returned form the backend. + * @return {!goog.Promise} + */ +fireauth.Auth.prototype.signInAnonymouslyAndRetrieveData = function() { var self = this; // Wait for the redirect state to be determined before proceeding. If critical // errors like web storage unsupported are detected, fail before RPC, instead @@ -1469,7 +1529,20 @@ fireauth.Auth.prototype.signInAnonymously = function() { var user = self.currentUser_(); // If an anonymous user is already signed in, no need to sign him again. if (user && user['isAnonymous']) { - return user; + var additionalUserInfo = fireauth.object.makeReadonlyCopy({ + 'providerId': null, + 'isNewUser': false + }); + return fireauth.object.makeReadonlyCopy({ + // Return the signed in user reference. + 'user': user, + // Do not return credential for anonymous user. + 'credential': null, + // Return any additional IdP data. + 'additionalUserInfo': additionalUserInfo, + // Sign in operation type. + 'operationType': fireauth.constants.OperationType.SIGN_IN + }); } else { // No anonymous user currently signed in. return self.signInWithIdTokenProvider_( @@ -1484,9 +1557,8 @@ fireauth.Auth.prototype.signInAnonymously = function() { // overwrites. user.updateProperty('isAnonymous', true); // Save isAnonymous flag changes to current user in storage. - return self.handleUserStateChange_(user); - }).then(function() { - return self.currentUser_(); + self.handleUserStateChange_(user); + return result; }); } }); diff --git a/packages/auth/src/exports_auth.js b/packages/auth/src/exports_auth.js index d332fcadc74..8f93162e404 100644 --- a/packages/auth/src/exports_auth.js +++ b/packages/auth/src/exports_auth.js @@ -58,6 +58,10 @@ fireauth.exportlib.exportPrototypeMethods( name: 'createUserWithEmailAndPassword', args: [fireauth.args.string('email'), fireauth.args.string('password')] }, + createUserAndRetrieveDataWithEmailAndPassword: { + name: 'createUserAndRetrieveDataWithEmailAndPassword', + args: [fireauth.args.string('email'), fireauth.args.string('password')] + }, fetchProvidersForEmail: { name: 'fetchProvidersForEmail', args: [fireauth.args.string('email')] @@ -111,6 +115,10 @@ fireauth.exportlib.exportPrototypeMethods( name: 'signInAnonymously', args: [] }, + signInAnonymouslyAndRetrieveData: { + name: 'signInAnonymouslyAndRetrieveData', + args: [] + }, signInWithCredential: { name: 'signInWithCredential', args: [fireauth.args.authCredential()] @@ -119,10 +127,18 @@ fireauth.exportlib.exportPrototypeMethods( name: 'signInWithCustomToken', args: [fireauth.args.string('token')] }, + signInAndRetrieveDataWithCustomToken: { + name: 'signInAndRetrieveDataWithCustomToken', + args: [fireauth.args.string('token')] + }, signInWithEmailAndPassword: { name: 'signInWithEmailAndPassword', args: [fireauth.args.string('email'), fireauth.args.string('password')] }, + signInAndRetrieveDataWithEmailAndPassword: { + name: 'signInAndRetrieveDataWithEmailAndPassword', + args: [fireauth.args.string('email'), fireauth.args.string('password')] + }, signInWithPhoneNumber: { name: 'signInWithPhoneNumber', args: [ diff --git a/packages/auth/src/idp.js b/packages/auth/src/idp.js index 2415c96f3ae..1391b9a95ee 100644 --- a/packages/auth/src/idp.js +++ b/packages/auth/src/idp.js @@ -25,11 +25,14 @@ goog.provide('fireauth.idp.Settings'); /** - * Enums for supported provider IDs. + * Enums for supported provider IDs. These provider IDs correspond to the + * sign_in_provider in the Firebase ID token and do not correspond to the + * supported client exposed firebase.auth.AuthProviders. * @enum {string} */ fireauth.idp.ProviderId = { ANONYMOUS: 'anonymous', + CUSTOM: 'custom', FACEBOOK: 'facebook.com', FIREBASE: 'firebase', GITHUB: 'github.com', diff --git a/packages/auth/test/additionaluserinfo_test.js b/packages/auth/test/additionaluserinfo_test.js index aabb045fd77..0163f2bacfb 100644 --- a/packages/auth/test/additionaluserinfo_test.js +++ b/packages/auth/test/additionaluserinfo_test.js @@ -73,6 +73,48 @@ var expectedGenericAdditionalUserInfo = { 'providerId': 'phone' }; +// "iss": "https://securetoken.google.com/12345678", +// "picture": "https://plus.google.com/abcdefghijklmnopqrstu", +// "aud": "12345678", +// "auth_time": 1510357622, +// "user_id": "abcdefghijklmnopqrstu", +// "sub": "abcdefghijklmnopqrstu", +// "iat": 1510357622, +// "exp": 1510361222, +// "email": "user@example.com", +// "email_verified": true, +// "firebase": {"identities": { +// "email": ["user@example.com"] +// }, "sign_in_provider": "password"} +var tokenEmail = 'HEAD.ew0KICAiaXNzIjogImh0dHBzOi8vc2VjdXJldG9rZW4uZ29vZ2xlL' + + 'mNvbS8xMjM0NTY3OCIsDQogICJwaWN0dXJlIjogImh0dHBzOi8vcGx1cy5' + + 'nb29nbGUuY29tL2FiY2RlZmdoaWprbG1ub3BxcnN0dSIsDQogICJhdWQiO' + + 'iAiMTIzNDU2NzgiLA0KICAiYXV0aF90aW1lIjogMTUxMDM1NzYyMiwNCiA' + + 'gInVzZXJfaWQiOiAiYWJjZGVmZ2hpamtsbW5vcHFyc3R1IiwNCiAgInN1Y' + + 'iI6ICJhYmNkZWZnaGlqa2xtbm9wcXJzdHUiLA0KICAiaWF0IjogMTUxMDM' + + '1NzYyMiwNCiAgImV4cCI6IDE1MTAzNjEyMjIsDQogICJlbWFpbCI6ICJ1c' + + '2VyQGV4YW1wbGUuY29tIiwNCiAgImVtYWlsX3ZlcmlmaWVkIjogdHJ1ZSw' + + 'NCiAgImZpcmViYXNlIjogew0KICAgICJpZGVudGl0aWVzIjogew0KICAgI' + + 'CAgImVtYWlsIjogWw0KICAgICAgICAidXNlckBleGFtcGxlLmNvbSINCiA' + + 'gICAgIF0NCiAgICB9LA0KICAgICJzaWduX2luX3Byb3ZpZGVyIjogInBhc' + + '3N3b3JkIg0KICB9DQp9.SIGNATURE'; + +// SignupNewUserResponse response without isNewUser field. +var signUpNewUserResponse = { + 'kind': 'identitytoolkit#SignupNewUserResponse', + 'idToken': tokenEmail, + 'refreshToken': 'REFRESH_TOKEN', + 'expiresIn': '3600', + 'localId': '123456' +}; + +// Expected generic additional user info object for the above signUpNewUser +// response. +var expectedGenericAdditionalUserInfoForSignUpNewUser = { + 'isNewUser': true, + 'providerId': 'password' +}; + // Typical minimal verifyAssertion response for generic IdP user with no profile // data. var noProfileVerifyAssertion = { @@ -371,6 +413,101 @@ function testGenericAdditionalUserInfo() { } + +function testGenericAdditionalUserInfo_fromSignUpNewUserResponse() { + var genericAdditionalUserInfo = new fireauth.GenericAdditionalUserInfo( + signUpNewUserResponse); + assertObjectEquals( + expectedGenericAdditionalUserInfoForSignUpNewUser, + genericAdditionalUserInfo); + assertObjectEquals( + genericAdditionalUserInfo, + fireauth.AdditionalUserInfo.fromPlainObject(signUpNewUserResponse)); +} + + +function testGenericAdditionalUserInfo_fromAnonymousSignInResponse() { + // "iss": "https://securetoken.google.com/12345678", + // "provider_id": "anonymous", + // "aud": "12345678", + // "auth_time": 1510874749, + // "user_id": "abcdefghijklmnopqrstu", + // "sub": "abcdefghijklmnopqrstu", + // "iat": 1510874749, + // "exp": 1510878349, + // "firebase": { "identities": {}, + // "sign_in_provider": "anonymous"} + var tokenAnonymous = 'HEAD.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5' + + 'jb20vMTIzNDU2NzgiLCJwcm92aWRlcl9pZCI6ImFub255bW91cyI' + + 'sImF1ZCI6IjEyMzQ1Njc4IiwiYXV0aF90aW1lIjoxNTEwODc0NzQ' + + '5LCJ1c2VyX2lkIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1Iiwic3V' + + 'iIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1IiwiaWF0IjoxNTEwODc' + + '0NzQ5LCJleHAiOjE1MTA4NzgzNDksImZpcmViYXNlIjp7ImlkZW5' + + '0aXRpZXMiOnt9LCJzaWduX2luX3Byb3ZpZGVyIjoiYW5vbnltb3V' + + 'zIn0sImFsZyI6IkhTMjU2In0.SIGNATURE'; + var anonymousSignInResponse = { + 'kind': 'identitytoolkit#SignupNewUserResponse', + 'idToken': tokenAnonymous, + 'refreshToken': 'REFRESH_TOKEN', + 'expiresIn': '3600', + 'localId': '123456' + }; + var expectedGenericAdditionalUserInfo = { + 'isNewUser': true, + 'providerId': null + }; + var genericAdditionalUserInfo = new fireauth.GenericAdditionalUserInfo( + anonymousSignInResponse); + assertObjectEquals( + expectedGenericAdditionalUserInfo, + genericAdditionalUserInfo); + assertObjectEquals( + genericAdditionalUserInfo, + fireauth.AdditionalUserInfo.fromPlainObject(anonymousSignInResponse)); + +} + + +function testGenericAdditionalUserInfo_fromCustomTokenSignInResponse() { + // "iss": "https://securetoken.google.com/12345678", + // "aud": "12345678", + // "auth_time": 1511378629, + // "user_id": "abcdefghijklmnopqrstu", + // "sub": "abcdefghijklmnopqrstu", + // "iat": 1511378630, + // "exp": 1511382230, + // "firebase": { "identities": {}, + // "sign_in_provider": "custom"} + var tokenCustom = 'HEAD.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb2' + + '0vMTIzNDU2NzgiLCJhdWQiOiIxMjM0NTY3OCIsImF1dGhfdGltZSI6M' + + 'TUxMTM3ODYyOSwidXNlcl9pZCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0' + + 'dSIsInN1YiI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dSIsImlhdCI6MTU' + + 'xMTM3ODYzMCwiZXhwIjoxNTExMzgyMjMwLCJmaXJlYmFzZSI6eyJpZG' + + 'VudGl0aWVzIjp7fSwic2lnbl9pbl9wcm92aWRlciI6ImN1c3RvbSJ9L' + + 'CJhbGciOiJIUzI1NiJ9.SIGNATURE'; + var customTokenSignInResponse = { + 'kind': 'identitytoolkit#VerifyCustomTokenResponse', + 'idToken': tokenCustom, + 'refreshToken': 'REFRESH_TOKEN', + 'expiresIn': '3600', + 'localId': '123456' + }; + var expectedGenericAdditionalUserInfo = { + 'isNewUser': false, + 'providerId': null + }; + var genericAdditionalUserInfo = new fireauth.GenericAdditionalUserInfo( + customTokenSignInResponse); + assertObjectEquals( + expectedGenericAdditionalUserInfo, + genericAdditionalUserInfo); + assertObjectEquals( + genericAdditionalUserInfo, + fireauth.AdditionalUserInfo.fromPlainObject(customTokenSignInResponse)); + +} + + function testFederatedAdditionalUserInfo_withProfile() { var federatedAdditionalUserInfo = new fireauth.FederatedAdditionalUserInfo(facebookVerifyAssertion); diff --git a/packages/auth/test/auth_test.js b/packages/auth/test/auth_test.js index ab046791bff..516d09ea30a 100644 --- a/packages/auth/test/auth_test.js +++ b/packages/auth/test/auth_test.js @@ -118,6 +118,7 @@ var idTokenGmail = { var expectedTokenResponse; var expectedTokenResponse2; var expectedTokenResponse3; +var expectedTokenResponse4; var expectedTokenResponseWithIdPData; var expectedAdditionalUserInfo; var expectedGoogleCredential; @@ -219,6 +220,23 @@ function setUp() { 'refreshToken': 'REFRESH_TOKEN3', 'expiresIn': '3600' }; + expectedTokenResponse4 = { + //Sample ID token with provider password and email user@example.com. + 'idToken': 'HEAD.ew0KICAiaXNzIjogImh0dHBzOi8vc2VjdXJldG9rZW4uZ29vZ2xlL' + + 'mNvbS8xMjM0NTY3OCIsDQogICJwaWN0dXJlIjogImh0dHBzOi8vcGx1cy5' + + 'nb29nbGUuY29tL2FiY2RlZmdoaWprbG1ub3BxcnN0dSIsDQogICJhdWQiO' + + 'iAiMTIzNDU2NzgiLA0KICAiYXV0aF90aW1lIjogMTUxMDM1NzYyMiwNCiA' + + 'gInVzZXJfaWQiOiAiYWJjZGVmZ2hpamtsbW5vcHFyc3R1IiwNCiAgInN1Y' + + 'iI6ICJhYmNkZWZnaGlqa2xtbm9wcXJzdHUiLA0KICAiaWF0IjogMTUxMDM' + + '1NzYyMiwNCiAgImV4cCI6IDE1MTAzNjEyMjIsDQogICJlbWFpbCI6ICJ1c' + + '2VyQGV4YW1wbGUuY29tIiwNCiAgImVtYWlsX3ZlcmlmaWVkIjogdHJ1ZSw' + + 'NCiAgImZpcmViYXNlIjogew0KICAgICJpZGVudGl0aWVzIjogew0KICAgI' + + 'CAgImVtYWlsIjogWw0KICAgICAgICAidXNlckBleGFtcGxlLmNvbSINCiA' + + 'gICAgIF0NCiAgICB9LA0KICAgICJzaWduX2luX3Byb3ZpZGVyIjogInBhc' + + '3N3b3JkIg0KICB9DQp9.SIGNATURE', + 'refreshToken': 'REFRESH_TOKEN4', + 'expiresIn': '3600' + }; expectedTokenResponseWithIdPData = { 'idToken': 'ID_TOKEN', 'refreshToken': 'REFRESH_TOKEN', @@ -3600,6 +3618,121 @@ function testAuth_signInWithCustomToken_error() { } +function testAuth_signInAndRetrieveDataWithCustomToken_success() { + // Tests successful signInAndRetrieveDataWithCustomToken. + fireauth.AuthEventManager.ENABLED = true; + var expectedCustomToken = 'CUSTOM_TOKEN'; + var expectedIdToken = 'HEAD.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2ds' + + 'ZS5jb20vMTIzNDU2NzgiLCJhdWQiOiIxMjM0NTY3OCIsImF1d' + + 'GhfdGltZSI6MTUxMTM3ODYyOSwidXNlcl9pZCI6ImFiY2RlZm' + + 'doaWprbG1ub3BxcnN0dSIsInN1YiI6ImFiY2RlZmdoaWprbG1' + + 'ub3BxcnN0dSIsImlhdCI6MTUxMTM3ODYzMCwiZXhwIjoxNTEx' + + 'MzgyMjMwLCJmaXJlYmFzZSI6eyJpZGVudGl0aWVzIjp7fSwic' + + '2lnbl9pbl9wcm92aWRlciI6ImN1c3RvbSJ9LCJhbGciOiJIUz' + + 'I1NiJ9.SIGNATURE'; + expectedTokenResponse['idToken'] = expectedIdToken; + // Stub OAuth sign in handler. + fakeOAuthSignInHandler(); + // signInAndRetrieveDataWithCustomToken should lead to an Auth user being + // initialized with the returned STS token response. + stubs.replace( + fireauth.Auth.prototype, + 'signInWithIdTokenResponse', + function(tokenResponse) { + // Token response should match RpcHandler response. + assertObjectEquals(expectedTokenResponse, tokenResponse); + // Simulate user sign in completed and returned. + auth1.setCurrentUser_(user1); + asyncTestCase.signal(); + return goog.Promise.resolve(); + }); + // verifyCustomToken should be called with expected parameters and resolved + // with expected token response. + stubs.replace( + fireauth.RpcHandler.prototype, + 'verifyCustomToken', + function(customToken) { + assertEquals(expectedCustomToken, customToken); + asyncTestCase.signal(); + return goog.Promise.resolve(expectedTokenResponse); + }); + asyncTestCase.waitForSignals(4); + // Initialize expected user. + var user1 = new fireauth.AuthUser( + config3, expectedTokenResponse, accountInfo); + // Set to true for testing to make sure this is changed during processing. + user1.updateProperty('isAnonymous', true); + var expectedResult = { + 'user': user1, + 'credential': null, + 'additionalUserInfo': {'providerId': null, 'isNewUser': false}, + 'operationType': fireauth.constants.OperationType.SIGN_IN + }; + app1 = firebase.initializeApp(config3, appId1); + auth1 = app1.auth(); + currentUserStorageManager = new fireauth.storage.UserManager( + auth1.getStorageKey()); + // Sign in with custom token. + auth1.signInAndRetrieveDataWithCustomToken(expectedCustomToken) + .then(function(result) { + // Anonymous status should be set to false. + assertFalse(result['user']['isAnonymous']); + // Returned user credential should match expected one. + fireauth.common.testHelper.assertUserCredentialResponse( + expectedResult['user'], + expectedResult['credential'], + expectedResult['additionalUserInfo'], + expectedResult['operationType'], + result); + // Confirm anonymous state saved. + currentUserStorageManager.getCurrentUser().then(function(user) { + assertUserEquals(user1, auth1['currentUser']); + assertFalse(user['isAnonymous']); + asyncTestCase.signal(); + }); + asyncTestCase.signal(); + }); +} + + +function testAuth_signInAndRetrieveDataWithCustomToken_error() { + // Tests unsuccessful signInAndRetrieveDataWithCustomToken. + fireauth.AuthEventManager.ENABLED = true; + // Expected RPC error. + var expectedError = + new fireauth.AuthError(fireauth.authenum.Error.INTERNAL_ERROR); + var expectedCustomToken = 'CUSTOM_TOKEN'; + // Stub OAuth sign in handler. + fakeOAuthSignInHandler(); + // Error should not lead to user creation. + stubs.replace( + fireauth.Auth.prototype, + 'signInWithIdTokenResponse', + function(tokenResponse) { + fail('signInWithIdTokenResponse should not be called!'); + }); + // verifyCustomToken should be called with expected parameters and throws the + // expected error. + stubs.replace( + fireauth.RpcHandler.prototype, + 'verifyCustomToken', + function(customToken) { + assertEquals(expectedCustomToken, customToken); + asyncTestCase.signal(); + return goog.Promise.reject(expectedError); + }); + asyncTestCase.waitForSignals(2); + app1 = firebase.initializeApp(config3, appId1); + auth1 = app1.auth(); + // signInAndRetrieveDataWithCustomToken should throw the expected error. + auth1.signInAndRetrieveDataWithCustomToken(expectedCustomToken) + .thenCatch(function(err) { + fireauth.common.testHelper.assertErrorEquals(expectedError, err); + asyncTestCase.signal(); + }); +} + + function testAuth_signInWithEmailAndPassword_success() { // Tests successful signInWithEmailAndPassword. fireauth.AuthEventManager.ENABLED = true; @@ -3688,6 +3821,105 @@ function testAuth_signInWithEmailAndPassword_error() { } +function testAuth_signInAndRetrieveDataWithEmailAndPassword_success() { + // Tests successful signInAndRetrieveDataWithEmailAndPassword. + fireauth.AuthEventManager.ENABLED = true; + // Expected email and password. + var expectedEmail = 'user@example.com'; + var expectedPass = 'password'; + + // Stub OAuth sign in handler. + fakeOAuthSignInHandler(); + // signInWithIdTokenResponse should initialize a user using the expected + // token response generated by RPC response. + stubs.replace( + fireauth.Auth.prototype, + 'signInWithIdTokenResponse', + function(tokenResponse) { + // Token response should match rpchandler response. + assertObjectEquals(expectedTokenResponse4, tokenResponse); + // Simulate user sign in completed and returned. + auth1.setCurrentUser_(user1); + asyncTestCase.signal(); + return goog.Promise.resolve(); + }); + // verifyPassword should be called with expected parameters and resolved + // with expected token response. + stubs.replace( + fireauth.RpcHandler.prototype, + 'verifyPassword', + function(email, password) { + assertEquals(expectedEmail, email); + assertEquals(expectedPass, password); + asyncTestCase.signal(); + return goog.Promise.resolve(expectedTokenResponse4); + }); + asyncTestCase.waitForSignals(3); + // Initialize expected user. + var user1 = new fireauth.AuthUser( + config3, expectedTokenResponse4, accountInfo); + var expectedResult = { + 'user': user1, + 'credential': null, + 'additionalUserInfo': {'providerId': 'password', 'isNewUser': false}, + 'operationType': fireauth.constants.OperationType.SIGN_IN + }; + app1 = firebase.initializeApp(config3, appId1); + auth1 = app1.auth(); + // Sign in and retrieve data with email and password. + auth1.signInAndRetrieveDataWithEmailAndPassword(expectedEmail, expectedPass) + .then(function(result) { + fireauth.common.testHelper.assertUserCredentialResponse( + expectedResult['user'], + expectedResult['credential'], + expectedResult['additionalUserInfo'], + expectedResult['operationType'], + result); + asyncTestCase.signal(); + }); +} + + +function testAuth_signInAndRetrieveDataWithEmailAndPassword_error() { + // Tests unsuccessful signInAndRetrieveDataWithEmailAndPassword. + fireauth.AuthEventManager.ENABLED = true; + // Expected email and password. + var expectedEmail = 'user@example.com'; + var expectedPass = 'password'; + // Expected RPC error. + var expectedError = + new fireauth.AuthError(fireauth.authenum.Error.INTERNAL_ERROR); + // Stub OAuth sign in handler. + fakeOAuthSignInHandler(); + // signInWithIdTokenResponse should not be called due to RPC error. + stubs.replace( + fireauth.Auth.prototype, + 'signInWithIdTokenResponse', + function(tokenResponse) { + fail('signInWithIdTokenResponse should not be called!'); + }); + // verifyPassword should be called with expected parameters and resolved + // with expected error. + stubs.replace( + fireauth.RpcHandler.prototype, + 'verifyPassword', + function(email, password) { + assertEquals(expectedEmail, email); + assertEquals(expectedPass, password); + asyncTestCase.signal(); + return goog.Promise.reject(expectedError); + }); + asyncTestCase.waitForSignals(2); + app1 = firebase.initializeApp(config3, appId1); + auth1 = app1.auth(); + auth1.signInAndRetrieveDataWithEmailAndPassword(expectedEmail, expectedPass) + .thenCatch(function(error) { + fireauth.common.testHelper.assertErrorEquals(expectedError, error); + asyncTestCase.signal(); + }); +} + + function testAuth_createUserWithEmailAndPassword_success() { // Tests successful createUserWithEmailAndPassword. fireauth.AuthEventManager.ENABLED = true; @@ -3776,6 +4008,106 @@ function testAuth_createUserWithEmailAndPassword_error() { } +function testAuth_createUserAndRetrieveDataWithEmailAndPassword_success() { + // Tests successful createUserAndRetrieveDataWithEmailAndPassword. + fireauth.AuthEventManager.ENABLED = true; + // Expected email and password. + var expectedEmail = 'user@example.com'; + var expectedPass = 'password'; + expectedTokenResponse4['kind'] = 'identitytoolkit#SignupNewUserResponse'; + // Stub OAuth sign in handler. + fakeOAuthSignInHandler(); + // signInWithIdTokenResponse should initialize a user using the expected + // token response generated by RPC response. + stubs.replace( + fireauth.Auth.prototype, + 'signInWithIdTokenResponse', + function(tokenResponse) { + // Token response should match rpchandler response. + assertObjectEquals(expectedTokenResponse4, tokenResponse); + // Simulate user sign in completed and returned. + auth1.setCurrentUser_(user1); + asyncTestCase.signal(); + return goog.Promise.resolve(); + }); + // createAccount should be called with expected parameters and resolved + // with expected token response. + stubs.replace( + fireauth.RpcHandler.prototype, + 'createAccount', + function(email, password) { + assertEquals(expectedEmail, email); + assertEquals(expectedPass, password); + asyncTestCase.signal(); + return goog.Promise.resolve(expectedTokenResponse4); + }); + asyncTestCase.waitForSignals(3); + // Initialize expected user. + var user1 = new fireauth.AuthUser( + config3, expectedTokenResponse4, accountInfo); + var expectedResult = { + 'user': user1, + 'credential': null, + 'additionalUserInfo': {'providerId': 'password', 'isNewUser': true}, + 'operationType': fireauth.constants.OperationType.SIGN_IN + }; + app1 = firebase.initializeApp(config3, appId1); + auth1 = app1.auth(); + auth1.createUserAndRetrieveDataWithEmailAndPassword( + expectedEmail, expectedPass) + .then(function(result) { + fireauth.common.testHelper.assertUserCredentialResponse( + expectedResult['user'], + expectedResult['credential'], + expectedResult['additionalUserInfo'], + expectedResult['operationType'], + result); + asyncTestCase.signal(); + }); +} + + +function testAuth_createUserAndRetrieveDataWithEmailAndPassword_error() { + // Tests unsuccessful createUserAndRetrieveDataWithEmailAndPassword. + fireauth.AuthEventManager.ENABLED = true; + // Expected email and password. + var expectedEmail = 'user@example.com'; + var expectedPass = 'password'; + // Expected RPC error. + var expectedError = + new fireauth.AuthError(fireauth.authenum.Error.INTERNAL_ERROR); + // Stub OAuth sign in handler. + fakeOAuthSignInHandler(); + // signInWithIdTokenResponse should not be called due to RPC error. + stubs.replace( + fireauth.Auth.prototype, + 'signInWithIdTokenResponse', + function(tokenResponse) { + fail('signInWithIdTokenResponse should not be called!'); + }); + // createAccount should be called with expected parameters and resolved + // with expected error. + stubs.replace( + fireauth.RpcHandler.prototype, + 'createAccount', + function(email, password) { + assertEquals(expectedEmail, email); + assertEquals(expectedPass, password); + asyncTestCase.signal(); + return goog.Promise.reject(expectedError); + }); + asyncTestCase.waitForSignals(2); + app1 = firebase.initializeApp(config3, appId1); + auth1 = app1.auth(); + auth1.createUserAndRetrieveDataWithEmailAndPassword( + expectedEmail, expectedPass) + .thenCatch(function(error) { + fireauth.common.testHelper.assertErrorEquals(expectedError, error); + asyncTestCase.signal(); + }); +} + + function testAuth_signInWithCredential_success() { // Stub signInAndRetrieveDataWithCredential and confirm same response is used // for signInWithCredential without only the user returned. @@ -4297,6 +4629,207 @@ function testAuth_signInAnonymously_error() { } +function testAuth_signInAnonymouslyAndRetrieveData_success() { + // Tests successful signInAnonymouslyAndRetrieveData. + var expectedIdToken = 'HEAD.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5' + + 'jb20vMTIzNDU2NzgiLCJwcm92aWRlcl9pZCI6ImFub255bW91cyI' + + 'sImF1ZCI6IjEyMzQ1Njc4IiwiYXV0aF90aW1lIjoxNTEwODc0NzQ' + + '5LCJ1c2VyX2lkIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1Iiwic3V' + + 'iIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1IiwiaWF0IjoxNTEwODc' + + '0NzQ5LCJleHAiOjE1MTA4NzgzNDksImZpcmViYXNlIjp7ImlkZW5' + + '0aXRpZXMiOnt9LCJzaWduX2luX3Byb3ZpZGVyIjoiYW5vbnltb3V' + + 'zIn0sImFsZyI6IkhTMjU2In0.SIGNATURE'; + expectedTokenResponse['idToken'] = expectedIdToken; + expectedTokenResponse['kind'] = 'identitytoolkit#SignupNewUserResponse'; + fireauth.AuthEventManager.ENABLED = true; + // Simulate successful RpcHandler signInAnonymously resolving with expected + // token response. + stubs.replace( + fireauth.RpcHandler.prototype, + 'signInAnonymously', + function() { + asyncTestCase.signal(); + return goog.Promise.resolve(expectedTokenResponse); + }); + // Stub OAuth sign in handler. + fakeOAuthSignInHandler(); + // signInWithIdTokenResponse should initialize a user using the expected token + // response generated by RPC response. + stubs.replace( + fireauth.Auth.prototype, + 'signInWithIdTokenResponse', + function(tokenResponse) { + // Token response should match RpcHandler response. + assertObjectEquals(expectedTokenResponse, tokenResponse); + // Simulate user sign in completed and returned. + auth1.setCurrentUser_(user1); + asyncTestCase.signal(); + return goog.Promise.resolve(); + }); + asyncTestCase.waitForSignals(4); + // Initialize expected anonymous user. + var user1 = new fireauth.AuthUser( + config3, expectedTokenResponse, accountInfo); + var expectedResult = { + 'user': user1, + 'credential': null, + 'additionalUserInfo': {'providerId': null, 'isNewUser': true}, + 'operationType': fireauth.constants.OperationType.SIGN_IN + }; + app1 = firebase.initializeApp(config3, appId1); + auth1 = app1.auth(); + currentUserStorageManager = new fireauth.storage.UserManager( + auth1.getStorageKey()); + auth1.signInAnonymouslyAndRetrieveData().then(function(result) { + fireauth.common.testHelper.assertUserCredentialResponse( + expectedResult['user'], + expectedResult['credential'], + expectedResult['additionalUserInfo'], + expectedResult['operationType'], + result); + assertTrue(result['user']['isAnonymous']); + // Confirm anonymous state saved. + currentUserStorageManager.getCurrentUser().then(function(user) { + assertUserEquals(user1, auth1['currentUser']); + assertTrue(user['isAnonymous']); + asyncTestCase.signal(); + }); + asyncTestCase.signal(); + }); +} + + +function testAuth_signInAnonymouslyAndRetrieveData_userAlreadySignedIn() { + // Tests signInAnonymouslyAndRetrieveData when an anonymous user is already + // signed in. + var expectedIdToken = 'HEAD.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5' + + 'jb20vMTIzNDU2NzgiLCJwcm92aWRlcl9pZCI6ImFub255bW91cyI' + + 'sImF1ZCI6IjEyMzQ1Njc4IiwiYXV0aF90aW1lIjoxNTEwODc0NzQ' + + '5LCJ1c2VyX2lkIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1Iiwic3V' + + 'iIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1IiwiaWF0IjoxNTEwODc' + + '0NzQ5LCJleHAiOjE1MTA4NzgzNDksImZpcmViYXNlIjp7ImlkZW5' + + '0aXRpZXMiOnt9LCJzaWduX2luX3Byb3ZpZGVyIjoiYW5vbnltb3V' + + 'zIn0sImFsZyI6IkhTMjU2In0.SIGNATURE'; + expectedTokenResponse['idToken'] = expectedIdToken; + fireauth.AuthEventManager.ENABLED = true; + // Simulate successful RpcHandler signInAnonymously. + stubs.replace( + fireauth.RpcHandler.prototype, + 'signInAnonymously', + function() { + fail('signInAnonymously on RpcHandler should not be called!'); + }); + // Stub OAuth sign in handler. + fakeOAuthSignInHandler(); + // Anonymous user is already signed in so there is no need for this to run. + stubs.replace( + fireauth.Auth.prototype, + 'signInWithIdTokenResponse', + function(tokenResponse) { + fail('signInWithIdTokenResponse should not be called!'); + }); + asyncTestCase.waitForSignals(3); + // Initialize an anonymous user. + var user1 = new fireauth.AuthUser( + config3, expectedTokenResponse, accountInfo); + user1.updateProperty('isAnonymous', true); + var expectedResult = { + 'user': user1, + 'credential': null, + 'additionalUserInfo': {'providerId': null, 'isNewUser': false}, + 'operationType': fireauth.constants.OperationType.SIGN_IN + }; + // Current user reference. + var currentUser = null; + // User state changed counter. + var stateChanged = 0; + // ID token changed counter. + var idTokenChanged = 0; + // Storage key. + currentUserStorageManager = new fireauth.storage.UserManager( + config3['apiKey'] + ':' + appId1); + // Save anonymous user as current in storage. + currentUserStorageManager.setCurrentUser(user1).then(function() { + + app1 = firebase.initializeApp(config3, appId1); + auth1 = app1.auth(); + // All listeners should be called once with the saved anonymous user. + auth1.onAuthStateChanged(function(user) { + stateChanged++; + assertEquals(1, stateChanged); + assertEquals(user1['uid'], user['uid']); + asyncTestCase.signal(); + }); + auth1.onIdTokenChanged(function(user) { + idTokenChanged++; + assertEquals(1, idTokenChanged); + assertEquals(user1['uid'], user['uid']); + asyncTestCase.signal(); + }); + // signInAnonymouslyAndRetrieveData should resolve with the already + // signed in anonymous user without calling RPC handler underneath. + return auth1.signInAnonymouslyAndRetrieveData(); + }).then(function(result) { + assertUserEquals(expectedResult['user'], result['user']); + assertObjectEquals( + expectedResult['additionalUserInfo'], result['additionalUserInfo']); + assertEquals(expectedResult['operationType'], result['operationType']); + assertUserEquals(expectedResult['user'], auth1.currentUser); + assertTrue(result['user']['isAnonymous']); + // Save reference to current user. + currentUser = auth1.currentUser; + // Sign in anonymously again. + return auth1.signInAnonymouslyAndRetrieveData(); + }).then(function(result) { + fireauth.common.testHelper.assertUserCredentialResponse( + currentUser, + expectedResult['credential'], + expectedResult['additionalUserInfo'], + expectedResult['operationType'], + result); + // Exact same reference should be returned. + assertEquals(auth1.currentUser, result['user']); + asyncTestCase.signal(); + }); +} + + +function testAuth_signInAnonymouslyAndRetrieveData_error() { + // Tests unsuccessful signInAnonymouslyAndRetrieveData. + fireauth.AuthEventManager.ENABLED = true; + // Expected RPC error. + var expectedError = new fireauth.AuthError( + fireauth.authenum.Error.INTERNAL_ERROR); + // Simulate unsuccessful RpcHandler signInAnonymously throwing the expected + // error. + stubs.replace( + fireauth.RpcHandler.prototype, + 'signInAnonymously', + function() { + asyncTestCase.signal(); + // Trigger invalid response error. + return goog.Promise.reject(expectedError); + }); + // Stub OAuth sign in handler. + fakeOAuthSignInHandler(); + // signInWithIdTokenResponse should not be called due to RPC error. + stubs.replace( + fireauth.Auth.prototype, + 'signInWithIdTokenResponse', + function(tokenResponse) { + fail('signInWithIdTokenResponse should not be called'); + }); + asyncTestCase.waitForSignals(2); + app1 = firebase.initializeApp(config3, appId1); + auth1 = app1.auth(); + // signInAnonymously should fail with expected error. + auth1.signInAnonymouslyAndRetrieveData().thenCatch(function(error) { + fireauth.common.testHelper.assertErrorEquals(expectedError, error); + asyncTestCase.signal(); + }); +} + + function testAuth_finishPopupAndRedirectSignIn_success() { // Test successful finishPopupAndRedirectSignIn with Auth credential. fireauth.AuthEventManager.ENABLED = true; diff --git a/packages/firebase/externs/firebase-auth-externs.js b/packages/firebase/externs/firebase-auth-externs.js index b70c6a55550..02d84a4d2d4 100644 --- a/packages/firebase/externs/firebase-auth-externs.js +++ b/packages/firebase/externs/firebase-auth-externs.js @@ -1041,10 +1041,68 @@ firebase.auth.Auth.prototype.languageCode; */ firebase.auth.Auth.prototype.useDeviceLanguage = function() {}; +/** + * Creates a new user account associated with the specified email address and + * password and returns any additional user info data or credentials. + * + * This method will be renamed to `createUserWithEmailAndPassword` replacing + * the existing method with the same name in the next major version change. + * + * On successful creation of the user account, this user will also be + * signed in to your application. + * + * User account creation can fail if the account already exists or the password + * is invalid. + * + * Note: The email address acts as a unique identifier for the user and + * enables an email-based password reset. This function will create + * a new user account and set the initial user password. + * + *

Error Codes

+ *
+ *
auth/email-already-in-use
+ *
Thrown if there already exists an account with the given email + * address.
+ *
auth/invalid-email
+ *
Thrown if the email address is not valid.
+ *
auth/operation-not-allowed
+ *
Thrown if email/password accounts are not enabled. Enable email/password + * accounts in the Firebase Console, under the Auth tab.
+ *
auth/weak-password
+ *
Thrown if the password is not strong enough.
+ *
+ * + * @example + * firebase.auth().createUserAndRetrieveDataWithEmailAndPassword(email, password) + * .catch(function(error) { + * // Handle Errors here. + * var errorCode = error.code; + * var errorMessage = error.message; + * if (errorCode == 'auth/weak-password') { + * alert('The password is too weak.'); + * } else { + * alert(errorMessage); + * } + * console.log(error); + * }); + * + * @param {string} email The user's email address. + * @param {string} password The user's chosen password. + * @return {!firebase.Promise} + */ +firebase.auth.Auth.prototype.createUserAndRetrieveDataWithEmailAndPassword = function( + email, + password +) {}; + /** * Creates a new user account associated with the specified email address and * password. * + * This method will be deprecated and will be updated to resolve with a + * `firebase.auth.UserCredential` as is returned in + * {@link firebase.auth.Auth#createUserAndRetrieveDataWithEmailAndPassword}. + * * On successful creation of the user account, this user will also be * signed in to your application. * @@ -1381,9 +1439,54 @@ firebase.auth.Auth.prototype.signInAndRetrieveDataWithCredential = function( credential ) {}; +/** + * Signs in a user asynchronously using a custom token and returns any + * additional user info data or credentials. + * + * This method will be renamed to `signInWithCustomToken` replacing + * the existing method with the same name in the next major version change. + * + * Custom tokens are used to integrate Firebase Auth with existing auth systems, + * and must be generated by the auth backend. + * + * Fails with an error if the token is invalid, expired, or not accepted by the + * Firebase Auth service. + * + *

Error Codes

+ *
+ *
auth/custom-token-mismatch
+ *
Thrown if the custom token is for a different Firebase App.
+ *
auth/invalid-custom-token
+ *
Thrown if the custom token format is incorrect.
+ *
+ * + * @example + * firebase.auth().signInAndRetrieveDataWithCustomToken(token) + * .catch(function(error) { + * // Handle Errors here. + * var errorCode = error.code; + * var errorMessage = error.message; + * if (errorCode === 'auth/invalid-custom-token') { + * alert('The token you provided is not valid.'); + * } else { + * console.error(error); + * } + * }); + * + * @param {string} token The custom token to sign in with. + * @return {!firebase.Promise} + */ +firebase.auth.Auth.prototype.signInAndRetrieveDataWithCustomToken = function( + token +) {}; + /** * Asynchronously signs in using a custom token. * + * This method will be deprecated and will be updated to resolve with a + * `firebase.auth.UserCredential` as is returned in + * {@link firebase.auth.Auth#signInAndRetrieveDataWithCustomToken}. + * * Custom tokens are used to integrate Firebase Auth with existing auth systems, * and must be generated by the auth backend. * @@ -1415,9 +1518,66 @@ firebase.auth.Auth.prototype.signInAndRetrieveDataWithCredential = function( */ firebase.auth.Auth.prototype.signInWithCustomToken = function(token) {}; +/** + * Asynchronously signs in using an email and password and returns any additional + * user info data or credentials. + * + * This method will be renamed to `signInWithEmailAndPassword` replacing + * the existing method with the same name in the next major version change. + * + * Fails with an error if the email address and password do not match. + * + * Note: The user's password is NOT the password used to access the user's email + * account. The email address serves as a unique identifier for the user, and + * the password is used to access the user's account in your Firebase project. + * + * See also: + * {@link firebase.auth.Auth#createUserAndRetrieveDataWithEmailAndPassword}. + * + *

Error Codes

+ *
+ *
auth/invalid-email
+ *
Thrown if the email address is not valid.
+ *
auth/user-disabled
+ *
Thrown if the user corresponding to the given email has been + * disabled.
+ *
auth/user-not-found
+ *
Thrown if there is no user corresponding to the given email.
+ *
auth/wrong-password
+ *
Thrown if the password is invalid for the given email, or the account + * corresponding to the email does not have a password set.
+ *
+ * + * @example + * firebase.auth().signInAndRetrieveDataWithEmailAndPassword(email, password) + * .catch(function(error) { + * // Handle Errors here. + * var errorCode = error.code; + * var errorMessage = error.message; + * if (errorCode === 'auth/wrong-password') { + * alert('Wrong password.'); + * } else { + * alert(errorMessage); + * } + * console.log(error); + * }); + * + * @param {string} email The users email address. + * @param {string} password The users password. + * @return {!firebase.Promise} + */ +firebase.auth.Auth.prototype.signInAndRetrieveDataWithEmailAndPassword = function( + email, + password +) {}; + /** * Asynchronously signs in using an email and password. * + * This method will be deprecated and will be updated to resolve with a + * `firebase.auth.UserCredential` as is returned in + * {@link firebase.auth.Auth#signInAndRetrieveDataWithEmailAndPassword}. + * * Fails with an error if the email address and password do not match. * * Note: The user's password is NOT the password used to access the user's email @@ -1550,9 +1710,48 @@ firebase.auth.ConfirmationResult.prototype.confirm = function( verificationCode ) {}; +/** + * Signs in a user anonymously and returns any additional user info data or + * credentials. + * + * This method will be renamed to `signInAnonymously` replacing the existing + * method with the same name in the next major version change. + * + * If there is already an anonymous user signed in, that user with + * additional date will be returned; otherwise, a new anonymous user + * identity will be created and returned. + * + *

Error Codes

+ *
+ *
auth/operation-not-allowed
+ *
Thrown if anonymous accounts are not enabled. Enable anonymous accounts + * in the Firebase Console, under the Auth tab.
+ *
+ * + * @example + * firebase.auth().signInAnonymouslyAndRetrieveData().catch(function(error) { + * // Handle Errors here. + * var errorCode = error.code; + * var errorMessage = error.message; + * + * if (errorCode === 'auth/operation-not-allowed') { + * alert('You must enable Anonymous auth in the Firebase Console.'); + * } else { + * console.error(error); + * } + * }); + * + * @return {!firebase.Promise} + */ +firebase.auth.Auth.prototype.signInAnonymouslyAndRetrieveData = function() {}; + /** * Asynchronously signs in as an anonymous user. * + * This method will be deprecated and will be updated to resolve with a + * `firebase.auth.UserCredential` as is returned in + * {@link firebase.auth.Auth#signInAnonymouslyAndRetrieveData}. + * * If there is already an anonymous user signed in, that user will be returned; * otherwise, a new anonymous user identity will be created and returned. *