Skip to content

Add core types & error map to auth-exp #2890

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages-exp/auth-exp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@firebase/app-types-exp": "0.x"
},
"dependencies": {
"@firebase/util": "^0.2.44",
"mocha": "^7.1.1",
"tslib": "1.11.1"
},
Expand Down
332 changes: 332 additions & 0 deletions packages-exp/auth-exp/src/core/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,332 @@
/**
* @license
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { ErrorFactory, ErrorMap } from '@firebase/util';
import { AppName } from '../model/auth';
import { User } from '../model/user';

/*
* Developer facing Firebase Auth error codes.
*/
export const enum AuthErrorCode {
ADMIN_ONLY_OPERATION = 'admin-restricted-operation',
ARGUMENT_ERROR = 'argument-error',
APP_NOT_AUTHORIZED = 'app-not-authorized',
APP_NOT_INSTALLED = 'app-not-installed',
CAPTCHA_CHECK_FAILED = 'captcha-check-failed',
CODE_EXPIRED = 'code-expired',
CORDOVA_NOT_READY = 'cordova-not-ready',
CORS_UNSUPPORTED = 'cors-unsupported',
CREDENTIAL_ALREADY_IN_USE = 'credential-already-in-use',
CREDENTIAL_MISMATCH = 'custom-token-mismatch',
CREDENTIAL_TOO_OLD_LOGIN_AGAIN = 'requires-recent-login',
DYNAMIC_LINK_NOT_ACTIVATED = 'dynamic-link-not-activated',
EMAIL_EXISTS = 'email-already-in-use',
EXPIRED_OOB_CODE = 'expired-action-code',
EXPIRED_POPUP_REQUEST = 'cancelled-popup-request',
INTERNAL_ERROR = 'internal-error',
INVALID_API_KEY = 'invalid-api-key',
INVALID_APP_CREDENTIAL = 'invalid-app-credential',
INVALID_APP_ID = 'invalid-app-id',
INVALID_AUTH = 'invalid-user-token',
INVALID_AUTH_EVENT = 'invalid-auth-event',
INVALID_CERT_HASH = 'invalid-cert-hash',
INVALID_CODE = 'invalid-verification-code',
INVALID_CONTINUE_URI = 'invalid-continue-uri',
INVALID_CORDOVA_CONFIGURATION = 'invalid-cordova-configuration',
INVALID_CUSTOM_TOKEN = 'invalid-custom-token',
INVALID_DYNAMIC_LINK_DOMAIN = 'invalid-dynamic-link-domain',
INVALID_EMAIL = 'invalid-email',
INVALID_IDP_RESPONSE = 'invalid-credential',
INVALID_MESSAGE_PAYLOAD = 'invalid-message-payload',
INVALID_OAUTH_CLIENT_ID = 'invalid-oauth-client-id',
INVALID_OAUTH_PROVIDER = 'invalid-oauth-provider',
INVALID_OOB_CODE = 'invalid-action-code',
INVALID_ORIGIN = 'unauthorized-domain',
INVALID_PASSWORD = 'wrong-password',
INVALID_PERSISTENCE = 'invalid-persistence-type',
INVALID_PHONE_NUMBER = 'invalid-phone-number',
INVALID_PROVIDER_ID = 'invalid-provider-id',
INVALID_RECIPIENT_EMAIL = 'invalid-recipient-email',
INVALID_SENDER = 'invalid-sender',
INVALID_SESSION_INFO = 'invalid-verification-id',
INVALID_TENANT_ID = 'invalid-tenant-id',
MISSING_ANDROID_PACKAGE_NAME = 'missing-android-pkg-name',
MISSING_APP_CREDENTIAL = 'missing-app-credential',
MISSING_AUTH_DOMAIN = 'auth-domain-config-required',
MISSING_CODE = 'missing-verification-code',
MISSING_CONTINUE_URI = 'missing-continue-uri',
MISSING_IFRAME_START = 'missing-iframe-start',
MISSING_IOS_BUNDLE_ID = 'missing-ios-bundle-id',
MISSING_OR_INVALID_NONCE = 'missing-or-invalid-nonce',
MISSING_PHONE_NUMBER = 'missing-phone-number',
MISSING_SESSION_INFO = 'missing-verification-id',
MODULE_DESTROYED = 'app-deleted',
MFA_REQUIRED = 'multi-factor-auth-required',
NEED_CONFIRMATION = 'account-exists-with-different-credential',
NETWORK_REQUEST_FAILED = 'network-request-failed',
NULL_USER = 'null-user',
NO_AUTH_EVENT = 'no-auth-event',
NO_SUCH_PROVIDER = 'no-such-provider',
OPERATION_NOT_ALLOWED = 'operation-not-allowed',
OPERATION_NOT_SUPPORTED = 'operation-not-supported-in-this-environment',
POPUP_BLOCKED = 'popup-blocked',
POPUP_CLOSED_BY_USER = 'popup-closed-by-user',
PROVIDER_ALREADY_LINKED = 'provider-already-linked',
QUOTA_EXCEEDED = 'quota-exceeded',
REDIRECT_CANCELLED_BY_USER = 'redirect-cancelled-by-user',
REDIRECT_OPERATION_PENDING = 'redirect-operation-pending',
REJECTED_CREDENTIAL = 'rejected-credential',
TENANT_ID_MISMATCH = 'tenant-id-mismatch',
TIMEOUT = 'timeout',
TOKEN_EXPIRED = 'user-token-expired',
TOO_MANY_ATTEMPTS_TRY_LATER = 'too-many-requests',
UNAUTHORIZED_DOMAIN = 'unauthorized-continue-uri',
UNSUPPORTED_PERSISTENCE = 'unsupported-persistence-type',
UNSUPPORTED_TENANT_OPERATION = 'unsupported-tenant-operation',
USER_CANCELLED = 'user-cancelled',
USER_DELETED = 'user-not-found',
USER_DISABLED = 'user-disabled',
USER_MISMATCH = 'user-mismatch',
USER_SIGNED_OUT = 'user-signed-out',
WEAK_PASSWORD = 'weak-password',
WEB_STORAGE_UNSUPPORTED = 'web-storage-unsupported'
}

const ERRORS: ErrorMap<AuthErrorCode> = {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll start the discussion here - is there a way we can make this optional? All these strings will be a large part of the compiled binary

Copy link
Contributor

@sam-gc sam-gc Apr 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed offline, it might be good to have separate error maps for "dev" and "prod", that way the user could choose which gets included. That would require the AUTH_ERROR_FACTORY to not be a constant.

I think we can mull this for a while, but to make that change more straightforward in the future, maybe this module should export a function instead of a constant?

export function getErrorFactory() { return AUTH_ERROR_FACTORY }

Copy link
Contributor Author

@avolkovi avolkovi Apr 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interested in what others think about this... @bojeil-google ?

Copy link
Member

@Feiyang1 Feiyang1 Apr 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just as a FYI, Firestore implemented something similar recently, but in a different way. They split their asserts into hardAsserts and debugAsserts, and debugAsserts are removed in the prod build.

#2859
#2814

I like your idea here that user could choose what errors to show.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assert model is cool, but doesn't work great in auth since most of our error messages are translations for server side errors

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this list also includes client side errors that do not map to server side errors.
So you are suggesting to make error mapping functionality modular? So if the developer does not import it, then what happens?
Expecting the developer to know what errors to include puts a lot of burden on the developer. They would need to understand each error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think for production builds we could just have a short code that can be mapped in our documentation, something like Error: auth/email-exists, with the full description & troubleshooting tips available online

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this would be a breaking API change though, and we would need the page up on the documentation before we could launch this, but it would be cool and could potentially make the final binary that much smaller

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I misunderstood your suggestion. You are suggesting modularization of the error messages population component and not the entire client side errors (and how they are mapped from server to client). That may not be terrible but a breaking change, alas.

I agree we should optimize this but I would suggest we think about it more (this also seems like a general problem and not specific to Auth). JsCore should try to find a unified solution for it. I would recommend implementing the current spec in its current form for now and then experimenting with the generated binary and revisiting this to see how we can avoid bundling these messages.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree on punting this to JS core for now, lets proceed as is, we can measure the possible effect of the strings during alpha and maybe implement this during beta

[AuthErrorCode.ADMIN_ONLY_OPERATION]:
'This operation is restricted to administrators only.',
[AuthErrorCode.ARGUMENT_ERROR]: '',
[AuthErrorCode.APP_NOT_AUTHORIZED]:
"This app]: identified by the domain where it's hosted]: is not " +
'authorized to use Firebase Authentication with the provided API key. ' +
'Review your key configuration in the Google API console.',
[AuthErrorCode.APP_NOT_INSTALLED]:
'The requested mobile application corresponding to the identifier (' +
'Android package name or iOS bundle ID) provided is not installed on ' +
'this device.',
[AuthErrorCode.CAPTCHA_CHECK_FAILED]:
'The reCAPTCHA response token provided is either invalid]: expired]: ' +
'already used or the domain associated with it does not match the list ' +
'of whitelisted domains.',
[AuthErrorCode.CODE_EXPIRED]:
'The SMS code has expired. Please re-send the verification code to try ' +
'again.',
[AuthErrorCode.CORDOVA_NOT_READY]: 'Cordova framework is not ready.',
[AuthErrorCode.CORS_UNSUPPORTED]: 'This browser is not supported.',
[AuthErrorCode.CREDENTIAL_ALREADY_IN_USE]:
'This credential is already associated with a different user account.',
[AuthErrorCode.CREDENTIAL_MISMATCH]:
'The custom token corresponds to a different audience.',
[AuthErrorCode.CREDENTIAL_TOO_OLD_LOGIN_AGAIN]:
'This operation is sensitive and requires recent authentication. Log in ' +
'again before retrying this request.',
[AuthErrorCode.DYNAMIC_LINK_NOT_ACTIVATED]:
'Please activate ' +
'Dynamic Links in the Firebase Console and agree to the terms and ' +
'conditions.',
[AuthErrorCode.EMAIL_EXISTS]:
'The email address is already in use by another account.',
[AuthErrorCode.EXPIRED_OOB_CODE]: 'The action code has expired. ',
[AuthErrorCode.EXPIRED_POPUP_REQUEST]:
'This operation has been cancelled due to another conflicting popup ' +
'being opened.',
[AuthErrorCode.INTERNAL_ERROR]: 'An internal AuthError has occurred.',
[AuthErrorCode.INVALID_APP_CREDENTIAL]:
'The phone verification request contains an invalid application verifier.' +
' The reCAPTCHA token response is either invalid or expired.',
[AuthErrorCode.INVALID_APP_ID]:
'The mobile app identifier is not registed for the current project.',
[AuthErrorCode.INVALID_AUTH]:
"This user's credential isn't valid for this project. This can happen " +
"if the user's token has been tampered with]: or if the user isn't for " +
'the project associated with this API key.',
[AuthErrorCode.INVALID_AUTH_EVENT]: 'An internal AuthError has occurred.',
[AuthErrorCode.INVALID_CODE]:
'The SMS verification code used to create the phone auth credential is ' +
'invalid. Please resend the verification code sms and be sure use the ' +
'verification code provided by the user.',
[AuthErrorCode.INVALID_CONTINUE_URI]:
'The continue URL provided in the request is invalid.',
[AuthErrorCode.INVALID_CORDOVA_CONFIGURATION]:
'The following' +
' Cordova plugins must be installed to enable OAuth sign-in= ' +
'cordova-plugin-buildinfo]: cordova-universal-links-plugin]: ' +
'cordova-plugin-browsertab]: cordova-plugin-inappbrowser and ' +
'cordova-plugin-customurlscheme.',
[AuthErrorCode.INVALID_CUSTOM_TOKEN]:
'The custom token format is incorrect. Please check the documentation.',
[AuthErrorCode.INVALID_DYNAMIC_LINK_DOMAIN]:
'The provided ' +
'dynamic link domain is not configured or authorized for the current ' +
'project.',
[AuthErrorCode.INVALID_EMAIL]: 'The email address is badly formatted.',
[AuthErrorCode.INVALID_API_KEY]:
'Your API key is invalid]: please check you have copied it correctly.',
[AuthErrorCode.INVALID_CERT_HASH]:
'The SHA-1 certificate hash provided is invalid.',
[AuthErrorCode.INVALID_IDP_RESPONSE]:
'The supplied auth credential is malformed or has expired.',
[AuthErrorCode.INVALID_MESSAGE_PAYLOAD]:
'The email template corresponding to this action contains invalid charac' +
'ters in its message. Please fix by going to the Auth email templates se' +
'ction in the Firebase Console.',
[AuthErrorCode.INVALID_OAUTH_PROVIDER]:
'EmailAuthProvider is not supported for this operation. This operation ' +
'only supports OAuth providers.',
[AuthErrorCode.INVALID_OAUTH_CLIENT_ID]:
'The OAuth client ID provided is either invalid or does not match the ' +
'specified API key.',
[AuthErrorCode.INVALID_ORIGIN]:
'This domain is not authorized for OAuth operations for your Firebase ' +
'project. Edit the list of authorized domains from the Firebase console.',
[AuthErrorCode.INVALID_OOB_CODE]:
'The action code is invalid. This can happen if the code is malformed]: ' +
'expired]: or has already been used.',
[AuthErrorCode.INVALID_PASSWORD]:
'The password is invalid or the user does not have a password.',
[AuthErrorCode.INVALID_PERSISTENCE]:
'The specified persistence type is invalid. It can only be local]: ' +
'session or none.',
[AuthErrorCode.INVALID_PHONE_NUMBER]:
'The format of the phone number provided is incorrect. Please enter the ' +
'phone number in a format that can be parsed into E.164 format. E.164 ' +
'phone numbers are written in the format [+,[country code,[subscriber ' +
'number including area code,.',
[AuthErrorCode.INVALID_PROVIDER_ID]: 'The specified provider ID is invalid.',
[AuthErrorCode.INVALID_RECIPIENT_EMAIL]:
'The email corresponding to this action failed to send as the provided ' +
'recipient email address is invalid.',
[AuthErrorCode.INVALID_SENDER]:
'The email template corresponding to this action contains an invalid sen' +
'der email or name. Please fix by going to the Auth email templates sect' +
'ion in the Firebase Console.',
[AuthErrorCode.INVALID_SESSION_INFO]:
'The verification ID used to create the phone auth credential is invalid.',
[AuthErrorCode.INVALID_TENANT_ID]:
"The Auth instance's tenant ID is invalid.",
[AuthErrorCode.MISSING_ANDROID_PACKAGE_NAME]:
'An Android ' +
'Package Name must be provided if the Android App is required to be ' +
'installed.',
[AuthErrorCode.MISSING_AUTH_DOMAIN]:
'Be sure to include authDomain when calling firebase.initializeApp()]: ' +
'by following the instructions in the Firebase console.',
[AuthErrorCode.MISSING_APP_CREDENTIAL]:
'The phone verification request is missing an application verifier ' +
'assertion. A reCAPTCHA response token needs to be provided.',
[AuthErrorCode.MISSING_CODE]:
'The phone auth credential was created with an empty SMS verification ' +
'code.',
[AuthErrorCode.MISSING_CONTINUE_URI]:
'A continue URL must be provided in the request.',
[AuthErrorCode.MISSING_IFRAME_START]: 'An internal AuthError has occurred.',
[AuthErrorCode.MISSING_IOS_BUNDLE_ID]:
'An iOS Bundle ID must be provided if an App Store ID is provided.',
[AuthErrorCode.MISSING_OR_INVALID_NONCE]:
'The request does not contain a valid nonce. This can occur if the ' +
'SHA-256 hash of the provided raw nonce does not match the hashed nonce ' +
'in the ID token payload.',
[AuthErrorCode.MISSING_PHONE_NUMBER]:
'To send verification codes]: provide a phone number for the recipient.',
[AuthErrorCode.MISSING_SESSION_INFO]:
'The phone auth credential was created with an empty verification ID.',
[AuthErrorCode.MODULE_DESTROYED]:
'This instance of FirebaseApp has been deleted.',
[AuthErrorCode.MFA_REQUIRED]:
'Proof of ownership of a second factor is required to complete sign-in.',
[AuthErrorCode.NEED_CONFIRMATION]:
'An account already exists with the same email address but different ' +
'sign-in credentials. Sign in using a provider associated with this ' +
'email address.',
[AuthErrorCode.NETWORK_REQUEST_FAILED]:
'A network AuthError (such as timeout]: interrupted connection or ' +
'unreachable host) has occurred.',
[AuthErrorCode.NO_AUTH_EVENT]: 'An internal AuthError has occurred.',
[AuthErrorCode.NO_SUCH_PROVIDER]:
'User was not linked to an account with the given provider.',
[AuthErrorCode.NULL_USER]:
'A null user object was provided as the argument for an operation which ' +
'requires a non-null user object.',
[AuthErrorCode.OPERATION_NOT_ALLOWED]:
'The given sign-in provider is disabled for this Firebase project. ' +
'Enable it in the Firebase console]: under the sign-in method tab of the ' +
'Auth section.',
[AuthErrorCode.OPERATION_NOT_SUPPORTED]:
'This operation is not supported in the environment this application is ' +
'running on. "location.protocol" must be http]: https or chrome-extension' +
' and web storage must be enabled.',
[AuthErrorCode.POPUP_BLOCKED]:
'Unable to establish a connection with the popup. It may have been ' +
'blocked by the browser.',
[AuthErrorCode.POPUP_CLOSED_BY_USER]:
'The popup has been closed by the user before finalizing the operation.',
[AuthErrorCode.PROVIDER_ALREADY_LINKED]:
'User can only be linked to one identity for the given provider.',
[AuthErrorCode.QUOTA_EXCEEDED]:
"The project's quota for this operation has been exceeded.",
[AuthErrorCode.REDIRECT_CANCELLED_BY_USER]:
'The redirect operation has been cancelled by the user before finalizing.',
[AuthErrorCode.REDIRECT_OPERATION_PENDING]:
'A redirect sign-in operation is already pending.',
[AuthErrorCode.REJECTED_CREDENTIAL]:
'The request contains malformed or mismatching credentials.',
[AuthErrorCode.TENANT_ID_MISMATCH]:
"The provided tenant ID does not match the Auth instance's tenant ID",
[AuthErrorCode.TIMEOUT]: 'The operation has timed out.',
[AuthErrorCode.TOKEN_EXPIRED]:
"The user's credential is no longer valid. The user must sign in again.",
[AuthErrorCode.TOO_MANY_ATTEMPTS_TRY_LATER]:
'We have blocked all requests from this device due to unusual activity. ' +
'Try again later.',
[AuthErrorCode.UNAUTHORIZED_DOMAIN]:
'The domain of the continue URL is not whitelisted. Please whitelist ' +
'the domain in the Firebase console.',
[AuthErrorCode.UNSUPPORTED_PERSISTENCE]:
'The current environment does not support the specified persistence type.',
[AuthErrorCode.UNSUPPORTED_TENANT_OPERATION]:
'This operation is not supported in a multi-tenant context.',
[AuthErrorCode.USER_CANCELLED]:
'The user did not grant your application the permissions it requested.',
[AuthErrorCode.USER_DELETED]:
'There is no user record corresponding to this identifier. The user may ' +
'have been deleted.',
[AuthErrorCode.USER_DISABLED]:
'The user account has been disabled by an administrator.',
[AuthErrorCode.USER_MISMATCH]:
'The supplied credentials do not correspond to the previously signed in ' +
'user.',
[AuthErrorCode.USER_SIGNED_OUT]: '',
[AuthErrorCode.WEAK_PASSWORD]:
'The password must be 6 characters long or more.',
[AuthErrorCode.WEB_STORAGE_UNSUPPORTED]:
'This browser is not supported or 3rd party cookies and data may be ' +
'disabled.'
};

type AuthErrorParams = {
[key in AuthErrorCode]: {
appName: AppName;
serverResponse?: object;
user?: User;
};
};

export const AUTH_ERROR_FACTORY = new ErrorFactory<
AuthErrorCode,
AuthErrorParams
>('auth', 'Firebase', ERRORS);
31 changes: 31 additions & 0 deletions packages-exp/auth-exp/src/core/providers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* Supported providers
*/
export enum ProviderId {
ANONYMOUS = 'anonymous',
CUSTOM = 'custom',
FACEBOOK = 'facebook.com',
FIREBASE = 'firebase',
GITHUB = 'github.com',
GOOGLE = 'google.com',
PASSWORD = 'password',
PHONE = 'phone',
TWITTER = 'twitter.com'
}
Loading