diff --git a/src/core/models/CredentialsManagerError.ts b/src/core/models/CredentialsManagerError.ts index 230152a9..4257ea2a 100644 --- a/src/core/models/CredentialsManagerError.ts +++ b/src/core/models/CredentialsManagerError.ts @@ -1,6 +1,9 @@ import { AuthError } from './AuthError'; -const ERROR_CODE_MAP: Record = { +/** + * Public constants exposing all possible CredentialsManager error codes. + */ +export const CredentialsManagerErrorCodes = { INVALID_CREDENTIALS: 'INVALID_CREDENTIALS', NO_CREDENTIALS: 'NO_CREDENTIALS', NO_REFRESH_TOKEN: 'NO_REFRESH_TOKEN', @@ -12,43 +15,72 @@ const ERROR_CODE_MAP: Record = { BIOMETRICS_FAILED: 'BIOMETRICS_FAILED', NO_NETWORK: 'NO_NETWORK', API_ERROR: 'API_ERROR', + INCOMPATIBLE_DEVICE: 'INCOMPATIBLE_DEVICE', + CRYPTO_EXCEPTION: 'CRYPTO_EXCEPTION', + UNKNOWN_ERROR: 'UNKNOWN_ERROR', +} as const; + +const ERROR_CODE_MAP: Record = { + INVALID_CREDENTIALS: CredentialsManagerErrorCodes.INVALID_CREDENTIALS, + NO_CREDENTIALS: CredentialsManagerErrorCodes.NO_CREDENTIALS, + NO_REFRESH_TOKEN: CredentialsManagerErrorCodes.NO_REFRESH_TOKEN, + RENEW_FAILED: CredentialsManagerErrorCodes.RENEW_FAILED, + STORE_FAILED: CredentialsManagerErrorCodes.STORE_FAILED, + REVOKE_FAILED: CredentialsManagerErrorCodes.REVOKE_FAILED, + LARGE_MIN_TTL: CredentialsManagerErrorCodes.LARGE_MIN_TTL, + CREDENTIAL_MANAGER_ERROR: + CredentialsManagerErrorCodes.CREDENTIAL_MANAGER_ERROR, + BIOMETRICS_FAILED: CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + NO_NETWORK: CredentialsManagerErrorCodes.NO_NETWORK, + API_ERROR: CredentialsManagerErrorCodes.API_ERROR, // --- Web (@auth0/auth0-spa-js) mappings --- - login_required: 'NO_CREDENTIALS', - consent_required: 'RENEW_FAILED', - mfa_required: 'RENEW_FAILED', - invalid_grant: 'RENEW_FAILED', - invalid_refresh_token: 'RENEW_FAILED', - missing_refresh_token: 'NO_REFRESH_TOKEN', + login_required: CredentialsManagerErrorCodes.NO_CREDENTIALS, + consent_required: CredentialsManagerErrorCodes.RENEW_FAILED, + mfa_required: CredentialsManagerErrorCodes.RENEW_FAILED, + invalid_grant: CredentialsManagerErrorCodes.RENEW_FAILED, + invalid_refresh_token: CredentialsManagerErrorCodes.RENEW_FAILED, + missing_refresh_token: CredentialsManagerErrorCodes.NO_REFRESH_TOKEN, // --- Many-to-one mapping for granular Android Biometric errors --- - INCOMPATIBLE_DEVICE: 'INCOMPATIBLE_DEVICE', - CRYPTO_EXCEPTION: 'CRYPTO_EXCEPTION', - BIOMETRIC_NO_ACTIVITY: 'BIOMETRICS_FAILED', - BIOMETRIC_ERROR_STATUS_UNKNOWN: 'BIOMETRICS_FAILED', - BIOMETRIC_ERROR_UNSUPPORTED: 'BIOMETRICS_FAILED', - BIOMETRIC_ERROR_HW_UNAVAILABLE: 'BIOMETRICS_FAILED', - BIOMETRIC_ERROR_NONE_ENROLLED: 'BIOMETRICS_FAILED', - BIOMETRIC_ERROR_NO_HARDWARE: 'BIOMETRICS_FAILED', - BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED: 'BIOMETRICS_FAILED', - BIOMETRIC_AUTHENTICATION_CHECK_FAILED: 'BIOMETRICS_FAILED', - BIOMETRIC_ERROR_DEVICE_CREDENTIAL_NOT_AVAILABLE: 'BIOMETRICS_FAILED', + INCOMPATIBLE_DEVICE: CredentialsManagerErrorCodes.INCOMPATIBLE_DEVICE, + CRYPTO_EXCEPTION: CredentialsManagerErrorCodes.CRYPTO_EXCEPTION, + BIOMETRIC_NO_ACTIVITY: CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_ERROR_STATUS_UNKNOWN: + CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_ERROR_UNSUPPORTED: CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_ERROR_HW_UNAVAILABLE: + CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_ERROR_NONE_ENROLLED: CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_ERROR_NO_HARDWARE: CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED: + CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_AUTHENTICATION_CHECK_FAILED: + CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_ERROR_DEVICE_CREDENTIAL_NOT_AVAILABLE: + CredentialsManagerErrorCodes.BIOMETRICS_FAILED, BIOMETRIC_ERROR_STRONG_AND_DEVICE_CREDENTIAL_NOT_AVAILABLE: - 'BIOMETRICS_FAILED', - BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL: 'BIOMETRICS_FAILED', - BIOMETRIC_ERROR_NEGATIVE_BUTTON: 'BIOMETRICS_FAILED', - BIOMETRIC_ERROR_HW_NOT_PRESENT: 'BIOMETRICS_FAILED', - BIOMETRIC_ERROR_NO_BIOMETRICS: 'BIOMETRICS_FAILED', - BIOMETRIC_ERROR_USER_CANCELED: 'BIOMETRICS_FAILED', - BIOMETRIC_ERROR_LOCKOUT_PERMANENT: 'BIOMETRICS_FAILED', - BIOMETRIC_ERROR_VENDOR: 'BIOMETRICS_FAILED', - BIOMETRIC_ERROR_LOCKOUT: 'BIOMETRICS_FAILED', - BIOMETRIC_ERROR_CANCELED: 'BIOMETRICS_FAILED', - BIOMETRIC_ERROR_NO_SPACE: 'BIOMETRICS_FAILED', - BIOMETRIC_ERROR_TIMEOUT: 'BIOMETRICS_FAILED', - BIOMETRIC_ERROR_UNABLE_TO_PROCESS: 'BIOMETRICS_FAILED', - BIOMETRICS_INVALID_USER: 'BIOMETRICS_FAILED', - BIOMETRIC_AUTHENTICATION_FAILED: 'BIOMETRICS_FAILED', + CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL: + CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_ERROR_NEGATIVE_BUTTON: + CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_ERROR_HW_NOT_PRESENT: + CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_ERROR_NO_BIOMETRICS: CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_ERROR_USER_CANCELED: CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_ERROR_LOCKOUT_PERMANENT: + CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_ERROR_VENDOR: CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_ERROR_LOCKOUT: CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_ERROR_CANCELED: CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_ERROR_NO_SPACE: CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_ERROR_TIMEOUT: CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_ERROR_UNABLE_TO_PROCESS: + CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRICS_INVALID_USER: CredentialsManagerErrorCodes.BIOMETRICS_FAILED, + BIOMETRIC_AUTHENTICATION_FAILED: + CredentialsManagerErrorCodes.BIOMETRICS_FAILED, }; export class CredentialsManagerError extends AuthError { @@ -61,6 +93,8 @@ export class CredentialsManagerError extends AuthError { json: originalError.json, }); - this.type = ERROR_CODE_MAP[originalError.code] || 'UNKNOWN_ERROR'; + this.type = + ERROR_CODE_MAP[originalError.code] || + CredentialsManagerErrorCodes.UNKNOWN_ERROR; } } diff --git a/src/core/models/WebAuthError.ts b/src/core/models/WebAuthError.ts index 494159c2..e7c50a8f 100644 --- a/src/core/models/WebAuthError.ts +++ b/src/core/models/WebAuthError.ts @@ -1,38 +1,63 @@ import { AuthError } from './AuthError'; +/** + * Public constants exposing all possible WebAuth error codes. + */ +export const WebAuthErrorCodes = { + USER_CANCELLED: 'USER_CANCELLED', + ACCESS_DENIED: 'ACCESS_DENIED', + NETWORK_ERROR: 'NETWORK_ERROR', + ID_TOKEN_VALIDATION_FAILED: 'ID_TOKEN_VALIDATION_FAILED', + BIOMETRICS_CONFIGURATION_ERROR: 'BIOMETRICS_CONFIGURATION_ERROR', + BROWSER_NOT_AVAILABLE: 'BROWSER_NOT_AVAILABLE', + FAILED_TO_LOAD_URL: 'FAILED_TO_LOAD_URL', + BROWSER_TERMINATED: 'BROWSER_TERMINATED', + NO_BUNDLE_IDENTIFIER: 'NO_BUNDLE_IDENTIFIER', + TRANSACTION_ACTIVE_ALREADY: 'TRANSACTION_ACTIVE_ALREADY', + NO_AUTHORIZATION_CODE: 'NO_AUTHORIZATION_CODE', + PKCE_NOT_ALLOWED: 'PKCE_NOT_ALLOWED', + INVALID_INVITATION_URL: 'INVALID_INVITATION_URL', + INVALID_STATE: 'INVALID_STATE', + TIMEOUT_ERROR: 'TIMEOUT_ERROR', + CONSENT_REQUIRED: 'CONSENT_REQUIRED', + INVALID_CONFIGURATION: 'INVALID_CONFIGURATION', + UNKNOWN_ERROR: 'UNKNOWN_ERROR', +} as const; + const ERROR_CODE_MAP: Record = { // --- Common Codes --- - 'a0.session.user_cancelled': 'USER_CANCELLED', - 'USER_CANCELLED': 'USER_CANCELLED', - 'access_denied': 'ACCESS_DENIED', - 'a0.network_error': 'NETWORK_ERROR', - 'a0.session.invalid_idtoken': 'ID_TOKEN_VALIDATION_FAILED', - 'ID_TOKEN_VALIDATION_FAILED': 'ID_TOKEN_VALIDATION_FAILED', - 'BIOMETRICS_CONFIGURATION_ERROR': 'BIOMETRICS_CONFIGURATION_ERROR', + 'a0.session.user_cancelled': WebAuthErrorCodes.USER_CANCELLED, + 'USER_CANCELLED': WebAuthErrorCodes.USER_CANCELLED, + 'access_denied': WebAuthErrorCodes.ACCESS_DENIED, + 'a0.network_error': WebAuthErrorCodes.NETWORK_ERROR, + 'a0.session.invalid_idtoken': WebAuthErrorCodes.ID_TOKEN_VALIDATION_FAILED, + 'ID_TOKEN_VALIDATION_FAILED': WebAuthErrorCodes.ID_TOKEN_VALIDATION_FAILED, + 'BIOMETRICS_CONFIGURATION_ERROR': + WebAuthErrorCodes.BIOMETRICS_CONFIGURATION_ERROR, // --- Android-specific mappings --- - 'a0.browser_not_available': 'BROWSER_NOT_AVAILABLE', - 'a0.session.failed_load': 'FAILED_TO_LOAD_URL', - 'a0.session.browser_terminated': 'BROWSER_TERMINATED', + 'a0.browser_not_available': WebAuthErrorCodes.BROWSER_NOT_AVAILABLE, + 'a0.session.failed_load': WebAuthErrorCodes.FAILED_TO_LOAD_URL, + 'a0.session.browser_terminated': WebAuthErrorCodes.BROWSER_TERMINATED, // --- iOS-specific mappings --- - 'NO_BUNDLE_IDENTIFIER': 'NO_BUNDLE_IDENTIFIER', - 'TRANSACTION_ACTIVE_ALREADY': 'TRANSACTION_ACTIVE_ALREADY', - 'NO_AUTHORIZATION_CODE': 'NO_AUTHORIZATION_CODE', - 'PKCE_NOT_ALLOWED': 'PKCE_NOT_ALLOWED', - 'INVALID_INVITATION_URL': 'INVALID_INVITATION_URL', + 'NO_BUNDLE_IDENTIFIER': WebAuthErrorCodes.NO_BUNDLE_IDENTIFIER, + 'TRANSACTION_ACTIVE_ALREADY': WebAuthErrorCodes.TRANSACTION_ACTIVE_ALREADY, + 'NO_AUTHORIZATION_CODE': WebAuthErrorCodes.NO_AUTHORIZATION_CODE, + 'PKCE_NOT_ALLOWED': WebAuthErrorCodes.PKCE_NOT_ALLOWED, + 'INVALID_INVITATION_URL': WebAuthErrorCodes.INVALID_INVITATION_URL, // --- Web (@auth0/auth0-spa-js) mappings --- - 'cancelled': 'USER_CANCELLED', - 'state_mismatch': 'INVALID_STATE', - 'login_required': 'ACCESS_DENIED', - 'timeout': 'TIMEOUT_ERROR', - 'consent_required': 'CONSENT_REQUIRED', + 'cancelled': WebAuthErrorCodes.USER_CANCELLED, + 'state_mismatch': WebAuthErrorCodes.INVALID_STATE, + 'login_required': WebAuthErrorCodes.ACCESS_DENIED, + 'timeout': WebAuthErrorCodes.TIMEOUT_ERROR, + 'consent_required': WebAuthErrorCodes.CONSENT_REQUIRED, // --- Generic Fallbacks --- - 'a0.invalid_configuration': 'INVALID_CONFIGURATION', - 'UNKNOWN': 'UNKNOWN_ERROR', - 'OTHER': 'UNKNOWN_ERROR', + 'a0.invalid_configuration': WebAuthErrorCodes.INVALID_CONFIGURATION, + 'UNKNOWN': WebAuthErrorCodes.UNKNOWN_ERROR, + 'OTHER': WebAuthErrorCodes.UNKNOWN_ERROR, }; export class WebAuthError extends AuthError { @@ -49,9 +74,10 @@ export class WebAuthError extends AuthError { originalError.message.includes('state is invalid') || originalError.code === 'state_mismatch' ) { - this.type = 'INVALID_STATE'; + this.type = WebAuthErrorCodes.INVALID_STATE; } else { - this.type = ERROR_CODE_MAP[originalError.code] || 'UNKNOWN_ERROR'; + this.type = + ERROR_CODE_MAP[originalError.code] || WebAuthErrorCodes.UNKNOWN_ERROR; } } }