diff --git a/.changeset/tall-bottles-promise.md b/.changeset/tall-bottles-promise.md new file mode 100644 index 00000000000..cb7084916ba --- /dev/null +++ b/.changeset/tall-bottles-promise.md @@ -0,0 +1,5 @@ +--- +'@firebase/auth': patch +--- + +Exposed INVALID_LOGIN_CREDENTIALS as auth/invalid-login-credentials error and updated docs for various auth SDK methods. diff --git a/common/api-review/auth.api.md b/common/api-review/auth.api.md index 0b1e7d0fb76..c34d5793e80 100644 --- a/common/api-review/auth.api.md +++ b/common/api-review/auth.api.md @@ -165,6 +165,7 @@ export const AuthErrorCodes: { readonly INVALID_EMAIL: "auth/invalid-email"; readonly INVALID_EMULATOR_SCHEME: "auth/invalid-emulator-scheme"; readonly INVALID_IDP_RESPONSE: "auth/invalid-credential"; + readonly INVALID_LOGIN_CREDENTIALS: "auth/invalid-login-credentials"; readonly INVALID_MESSAGE_PAYLOAD: "auth/invalid-message-payload"; readonly INVALID_MFA_SESSION: "auth/invalid-multi-factor-session"; readonly INVALID_OAUTH_CLIENT_ID: "auth/invalid-oauth-client-id"; diff --git a/docs-devsite/auth.md b/docs-devsite/auth.md index 684e81eee07..93519c81b87 100644 --- a/docs-devsite/auth.md +++ b/docs-devsite/auth.md @@ -28,7 +28,7 @@ Firebase Authentication | [confirmPasswordReset(auth, oobCode, newPassword)](./auth.md#confirmpasswordreset) | Completes the password reset process, given a confirmation code and new password. | | [connectAuthEmulator(auth, url, options)](./auth.md#connectauthemulator) | Changes the [Auth](./auth.auth.md#auth_interface) instance to communicate with the Firebase Auth Emulator, instead of production Firebase Auth services. | | [createUserWithEmailAndPassword(auth, email, password)](./auth.md#createuserwithemailandpassword) | Creates a new user account associated with the specified email address and password. | -| [fetchSignInMethodsForEmail(auth, email)](./auth.md#fetchsigninmethodsforemail) | Gets the list of possible sign in methods for the given email address. | +| [fetchSignInMethodsForEmail(auth, email)](./auth.md#fetchsigninmethodsforemail) | Gets the list of possible sign in methods for the given email address. This method returns an empty list when \[Email Enumeration Protection\](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection) is enabled, irrespective of the number of authentication methods available for the given email. | | [getMultiFactorResolver(auth, error)](./auth.md#getmultifactorresolver) | Provides a [MultiFactorResolver](./auth.multifactorresolver.md#multifactorresolver_interface) suitable for completion of a multi-factor flow. | | [getRedirectResult(auth, resolver)](./auth.md#getredirectresult) | Returns a [UserCredential](./auth.usercredential.md#usercredential_interface) from the redirect-based sign-in flow. | | [initializeRecaptchaConfig(auth)](./auth.md#initializerecaptchaconfig) | Loads the reCAPTCHA configuration into the Auth instance. | @@ -36,7 +36,7 @@ Firebase Authentication | [onAuthStateChanged(auth, nextOrObserver, error, completed)](./auth.md#onauthstatechanged) | Adds an observer for changes to the user's sign-in state. | | [onIdTokenChanged(auth, nextOrObserver, error, completed)](./auth.md#onidtokenchanged) | Adds an observer for changes to the signed-in user's ID token. | | [revokeAccessToken(auth, token)](./auth.md#revokeaccesstoken) | Revokes the given access token. Currently only supports Apple OAuth access tokens. | -| [sendPasswordResetEmail(auth, email, actionCodeSettings)](./auth.md#sendpasswordresetemail) | Sends a password reset email to the given email address. | +| [sendPasswordResetEmail(auth, email, actionCodeSettings)](./auth.md#sendpasswordresetemail) | Sends a password reset email to the given email address. This method does not throw an error when \[Email Enumeration Protection\](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection) is enabled. | | [sendSignInLinkToEmail(auth, email, actionCodeSettings)](./auth.md#sendsigninlinktoemail) | Sends a sign-in email link to the user with the specified email. | | [setPersistence(auth, persistence)](./auth.md#setpersistence) | Changes the type of persistence on the [Auth](./auth.auth.md#auth_interface) instance for the currently saved Auth session and applies this type of persistence for future sign-in requests, including sign-in with redirect requests. | | [signInAnonymously(auth)](./auth.md#signinanonymously) | Asynchronously signs in as an anonymous user. | @@ -397,7 +397,7 @@ Promise<[UserCredential](./auth.usercredential.md#usercredential_interface).EMAIL\_PASSWORD and [SignInMethod](./auth.md#signinmethod).EMAIL\_LINK. @@ -412,7 +412,7 @@ export declare function fetchSignInMethodsForEmail(auth: Auth, email: string): P | Parameter | Type | Description | | --- | --- | --- | | auth | [Auth](./auth.auth.md#auth_interface) | The [Auth](./auth.auth.md#auth_interface) instance. | -| email | string | The user's email address. | +| email | string | The user's email address.Deprecated Migrating off of this method is recommended as a security best-practice. | Returns: @@ -622,7 +622,7 @@ Promise<void> ## sendPasswordResetEmail() -Sends a password reset email to the given email address. +Sends a password reset email to the given email address. This method does not throw an error when \[Email Enumeration Protection\](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection) is enabled. To complete the password reset, call [confirmPasswordReset()](./auth.md#confirmpasswordreset) with the code supplied in the email sent to the user, along with the new password specified by the user. @@ -825,7 +825,7 @@ Promise<[UserCredential](./auth.usercredential.md#usercredential_interface). @@ -1633,7 +1633,7 @@ export declare function updateEmail(user: User, newEmail: string): Promise | Parameter | Type | Description | | --- | --- | --- | | user | [User](./auth.user.md#user_interface) | The user. | -| newEmail | string | The new email address. | +| newEmail | string | The new email address.Throws "auth/operation-not-allowed" error when \[Email Enumeration Protection\](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection) is enabled. Deprecated - Use [verifyBeforeUpdateEmail()](./auth.md#verifybeforeupdateemail) instead. | Returns: @@ -1851,6 +1851,7 @@ AUTH_ERROR_CODES_MAP_DO_NOT_USE_INTERNALLY: { readonly INVALID_EMAIL: "auth/invalid-email"; readonly INVALID_EMULATOR_SCHEME: "auth/invalid-emulator-scheme"; readonly INVALID_IDP_RESPONSE: "auth/invalid-credential"; + readonly INVALID_LOGIN_CREDENTIALS: "auth/invalid-login-credentials"; readonly INVALID_MESSAGE_PAYLOAD: "auth/invalid-message-payload"; readonly INVALID_MFA_SESSION: "auth/invalid-multi-factor-session"; readonly INVALID_OAUTH_CLIENT_ID: "auth/invalid-oauth-client-id"; diff --git a/packages/auth/demo/src/index.js b/packages/auth/demo/src/index.js index 48aeb07d380..a053a4a9149 100644 --- a/packages/auth/demo/src/index.js +++ b/packages/auth/demo/src/index.js @@ -317,6 +317,11 @@ function onAuthError(error) { if (error.code === 'auth/user-token-expired') { alertError('Token expired, please reauthenticate.'); } + if (error.code === 'auth/invalid-login-credentials') { + alertError( + 'login credentials invalid. It is possible that the email/password combination does not exist.' + ); + } } } diff --git a/packages/auth/src/api/errors.ts b/packages/auth/src/api/errors.ts index d2f07ca6e27..28f877088ae 100644 --- a/packages/auth/src/api/errors.ts +++ b/packages/auth/src/api/errors.ts @@ -44,6 +44,7 @@ export const enum ServerError { INVALID_ID_TOKEN = 'INVALID_ID_TOKEN', INVALID_IDP_RESPONSE = 'INVALID_IDP_RESPONSE', INVALID_IDENTIFIER = 'INVALID_IDENTIFIER', + INVALID_LOGIN_CREDENTIALS = 'INVALID_LOGIN_CREDENTIALS', INVALID_MESSAGE_PAYLOAD = 'INVALID_MESSAGE_PAYLOAD', INVALID_MFA_PENDING_CREDENTIAL = 'INVALID_MFA_PENDING_CREDENTIAL', INVALID_OAUTH_CLIENT_ID = 'INVALID_OAUTH_CLIENT_ID', @@ -144,6 +145,10 @@ export const SERVER_ERROR_MAP: Partial> = { [ServerError.INVALID_PASSWORD]: AuthErrorCode.INVALID_PASSWORD, // This can only happen if the SDK sends a bad request. [ServerError.MISSING_PASSWORD]: AuthErrorCode.MISSING_PASSWORD, + // Thrown if Email Enumeration Protection is enabled in the project and the email or password is + // invalid. + [ServerError.INVALID_LOGIN_CREDENTIALS]: + AuthErrorCode.INVALID_LOGIN_CREDENTIALS, // Sign up with email and password errors. [ServerError.EMAIL_EXISTS]: AuthErrorCode.EMAIL_EXISTS, diff --git a/packages/auth/src/core/errors.ts b/packages/auth/src/core/errors.ts index 586a33d3d34..f2fd27d1624 100644 --- a/packages/auth/src/core/errors.ts +++ b/packages/auth/src/core/errors.ts @@ -61,6 +61,7 @@ export const enum AuthErrorCode { INVALID_EMAIL = 'invalid-email', INVALID_EMULATOR_SCHEME = 'invalid-emulator-scheme', INVALID_IDP_RESPONSE = 'invalid-credential', + INVALID_LOGIN_CREDENTIALS = 'invalid-login-credentials', INVALID_MESSAGE_PAYLOAD = 'invalid-message-payload', INVALID_MFA_SESSION = 'invalid-multi-factor-session', INVALID_OAUTH_CLIENT_ID = 'invalid-oauth-client-id', @@ -219,6 +220,8 @@ function _debugErrorMap(): ErrorMap { 'The SHA-1 certificate hash provided is invalid.', [AuthErrorCode.INVALID_IDP_RESPONSE]: 'The supplied auth credential is malformed or has expired.', + [AuthErrorCode.INVALID_LOGIN_CREDENTIALS]: + 'The supplied login credentials are invalid.', [AuthErrorCode.INVALID_MESSAGE_PAYLOAD]: 'The email template corresponding to this action contains invalid characters in its message. ' + 'Please fix by going to the Auth email templates section in the Firebase Console.', @@ -528,6 +531,7 @@ export const AUTH_ERROR_CODES_MAP_DO_NOT_USE_INTERNALLY = { INVALID_EMAIL: 'auth/invalid-email', INVALID_EMULATOR_SCHEME: 'auth/invalid-emulator-scheme', INVALID_IDP_RESPONSE: 'auth/invalid-credential', + INVALID_LOGIN_CREDENTIALS: 'auth/invalid-login-credentials', INVALID_MESSAGE_PAYLOAD: 'auth/invalid-message-payload', INVALID_MFA_SESSION: 'auth/invalid-multi-factor-session', INVALID_OAUTH_CLIENT_ID: 'auth/invalid-oauth-client-id', diff --git a/packages/auth/src/core/strategies/email.ts b/packages/auth/src/core/strategies/email.ts index 43d3804eace..27c34124f58 100644 --- a/packages/auth/src/core/strategies/email.ts +++ b/packages/auth/src/core/strategies/email.ts @@ -33,7 +33,9 @@ import { _setActionCodeSettingsOnRequest } from './action_code_settings'; import { getModularInstance } from '@firebase/util'; /** - * Gets the list of possible sign in methods for the given email address. + * Gets the list of possible sign in methods for the given email address. This method returns an + * empty list when [Email Enumeration Protection](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection) is enabled, irrespective of the number of + * authentication methods available for the given email. * * @remarks * This is useful to differentiate methods of sign-in for the same provider, eg. @@ -44,6 +46,7 @@ import { getModularInstance } from '@firebase/util'; * @param auth - The {@link Auth} instance. * @param email - The user's email address. * + * Deprecated Migrating off of this method is recommended as a security best-practice. * @public */ export async function fetchSignInMethodsForEmail( diff --git a/packages/auth/src/core/strategies/email_and_password.ts b/packages/auth/src/core/strategies/email_and_password.ts index 0ff21810a49..8e965d32f7e 100644 --- a/packages/auth/src/core/strategies/email_and_password.ts +++ b/packages/auth/src/core/strategies/email_and_password.ts @@ -61,7 +61,8 @@ async function recachePasswordPolicy(auth: Auth): Promise { } /** - * Sends a password reset email to the given email address. + * Sends a password reset email to the given email address. This method does not throw an error when + * [Email Enumeration Protection](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection) is enabled. * * @remarks * To complete the password reset, call {@link confirmPasswordReset} with the code supplied in @@ -303,6 +304,8 @@ export async function createUserWithEmailAndPassword( * * @remarks * Fails with an error if the email address and password do not match. + * When [Email Enumeration Protection](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection) is enabled, + * this method fails with "auth/invalid-credential" in case of an invalid email/password. * * 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 diff --git a/packages/auth/src/core/user/account_info.ts b/packages/auth/src/core/user/account_info.ts index 460ba7d3ed3..3f061630435 100644 --- a/packages/auth/src/core/user/account_info.ts +++ b/packages/auth/src/core/user/account_info.ts @@ -88,6 +88,9 @@ export async function updateProfile( * @param user - The user. * @param newEmail - The new email address. * + * Throws "auth/operation-not-allowed" error when [Email Enumeration Protection](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection) is enabled. + * Deprecated - Use {@link verifyBeforeUpdateEmail} instead. + * * @public */ export function updateEmail(user: User, newEmail: string): Promise {