From dd9c5c97f44981e74a01190125f00e83d243405a Mon Sep 17 00:00:00 2001 From: Tomasz Lesniakiewicz Date: Wed, 10 Dec 2025 12:48:49 +0100 Subject: [PATCH 1/3] add manual auth error tracking --- src/libs/Authentication.ts | 24 +++++++++- .../telemetry/trackAuthenticationError.ts | 44 +++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 src/libs/telemetry/trackAuthenticationError.ts diff --git a/src/libs/Authentication.ts b/src/libs/Authentication.ts index 77f19dd6b3ef..51dcf99b42cd 100644 --- a/src/libs/Authentication.ts +++ b/src/libs/Authentication.ts @@ -15,6 +15,7 @@ import {post} from './Network'; import {getCredentials, hasReadRequiredDataFromStorage, setAuthToken, setIsAuthenticating} from './Network/NetworkStore'; import requireParameters from './requireParameters'; import {checkIfShouldUseNewPartnerName} from './SessionUtils'; +import trackAuthenticationError from './telemetry/trackAuthenticationError'; type Parameters = { useExpensifyLogin?: boolean; @@ -62,6 +63,12 @@ function Authenticate(parameters: Parameters): Promise { requireParameters(['partnerName', 'partnerPassword', 'partnerUserID', 'partnerUserSecret'], parameters, commandName); } catch (error) { const errorMessage = (error as Error).message; + trackAuthenticationError(error as Error, { + errorType: 'missing_params', + functionName: 'Authenticate', + commandName, + providedParameters: Object.keys(parameters), + }); Log.hmmm('Redirecting to Sign In because we failed to reauthenticate', { error: errorMessage, }); @@ -147,12 +154,27 @@ function reauthenticate(command = ''): Promise { if (response.jsonCode === CONST.JSON_CODE.UNABLE_TO_RETRY) { // When a fetch() fails due to a network issue and an error is thrown we won't log the user out. Most likely they // have a spotty connection and will need to retry reauthenticate when they come back online. Error so it can be handled by the retry mechanism. - throw new Error('Unable to retry Authenticate request'); + const error = new Error('Unable to retry Authenticate request'); + trackAuthenticationError(error, { + errorType: 'network_retry', + functionName: 'reauthenticate', + jsonCode: response.jsonCode, + command, + }); + throw error; } // If authentication fails and we are online then log the user out if (response.jsonCode !== 200) { const errorMessage = getAuthenticateErrorMessage(response); + + trackAuthenticationError(new Error('Authentication failed'), { + errorType: 'auth_failure', + functionName: 'reauthenticate', + jsonCode: response.jsonCode, + command, + errorMessage, + }); setIsAuthenticating(false); Log.hmmm('Redirecting to Sign In because we failed to reauthenticate', { command, diff --git a/src/libs/telemetry/trackAuthenticationError.ts b/src/libs/telemetry/trackAuthenticationError.ts new file mode 100644 index 000000000000..963d1f2e0ecc --- /dev/null +++ b/src/libs/telemetry/trackAuthenticationError.ts @@ -0,0 +1,44 @@ +import * as Sentry from '@sentry/react-native'; + +type AuthenticationFunction = 'Authenticate' | 'reauthenticate'; +type AuthenticationErrorType = 'missing_params' | 'network_retry' | 'auth_failure'; + +type AuthenticationErrorContext = { + errorType: AuthenticationErrorType; + functionName: AuthenticationFunction; + jsonCode?: number | string; + command?: string; + commandName?: string; + errorMessage?: string; + providedParameters?: string[]; +}; + +/** + * Track authentication errors in Sentry with consistent tagging and context. + * + * @param error - The error object to capture + * @param context - Additional context about the authentication error + */ +function trackAuthenticationError(error: Error, context: AuthenticationErrorContext): void { + const {errorType, functionName, jsonCode, command, commandName, errorMessage, providedParameters} = context; + + const tags: Record = { + 'authentication.function': functionName, + 'authentication.error_type': errorType, + }; + + if (jsonCode !== undefined) { + tags['authentication.json_code'] = String(jsonCode); + } + + const extra: Record = { + ...(command && {command}), + ...(commandName && {commandName}), + ...(errorMessage && {errorMessage}), + ...(providedParameters && {providedParameters}), + }; + + Sentry.captureException(error, {tags, extra}); +} + +export default trackAuthenticationError; From 20d3ff0010fcbc1ad57e4fe598f9edb77f0e746c Mon Sep 17 00:00:00 2001 From: Tomasz Lesniakiewicz Date: Wed, 10 Dec 2025 13:55:26 +0100 Subject: [PATCH 2/3] fix tag variable naming --- src/CONST/index.ts | 3 +++ src/libs/telemetry/trackAuthenticationError.ts | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index baacb45eb0bd..b48bb9ab73b5 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -1674,6 +1674,9 @@ const CONST = { CONTEXT_POLICIES: 'Policies', TAG_ACTIVE_POLICY: 'active_policy_id', TAG_NUDGE_MIGRATION_COHORT: 'nudge_migration_cohort', + TAG_AUTHENTICATION_FUNCTION: 'authentication_function', + TAG_AUTHENTICATION_ERROR_TYPE: 'authentication_error_type', + TAG_AUTHENTICATION_JSON_CODE: 'authentication_json_code', // Span names SPAN_OPEN_REPORT: 'ManualOpenReport', SPAN_APP_STARTUP: 'ManualAppStartup', diff --git a/src/libs/telemetry/trackAuthenticationError.ts b/src/libs/telemetry/trackAuthenticationError.ts index 963d1f2e0ecc..20aaded9fb12 100644 --- a/src/libs/telemetry/trackAuthenticationError.ts +++ b/src/libs/telemetry/trackAuthenticationError.ts @@ -1,4 +1,5 @@ import * as Sentry from '@sentry/react-native'; +import CONST from '@src/CONST'; type AuthenticationFunction = 'Authenticate' | 'reauthenticate'; type AuthenticationErrorType = 'missing_params' | 'network_retry' | 'auth_failure'; @@ -23,12 +24,12 @@ function trackAuthenticationError(error: Error, context: AuthenticationErrorCont const {errorType, functionName, jsonCode, command, commandName, errorMessage, providedParameters} = context; const tags: Record = { - 'authentication.function': functionName, - 'authentication.error_type': errorType, + [CONST.TELEMETRY.TAG_AUTHENTICATION_FUNCTION]: functionName, + [CONST.TELEMETRY.TAG_AUTHENTICATION_ERROR_TYPE]: errorType, }; if (jsonCode !== undefined) { - tags['authentication.json_code'] = String(jsonCode); + tags[CONST.TELEMETRY.TAG_AUTHENTICATION_JSON_CODE] = String(jsonCode); } const extra: Record = { From 36124f2116837722fb1c1c0ace3c08e68c98fcc6 Mon Sep 17 00:00:00 2001 From: Tomasz Lesniakiewicz Date: Thu, 11 Dec 2025 19:06:58 +0100 Subject: [PATCH 3/3] chore: adjust comments --- src/libs/telemetry/trackAuthenticationError.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/telemetry/trackAuthenticationError.ts b/src/libs/telemetry/trackAuthenticationError.ts index 20aaded9fb12..08438b776e94 100644 --- a/src/libs/telemetry/trackAuthenticationError.ts +++ b/src/libs/telemetry/trackAuthenticationError.ts @@ -15,7 +15,7 @@ type AuthenticationErrorContext = { }; /** - * Track authentication errors in Sentry with consistent tagging and context. + * Track authentication errors in Sentry with extra context. * * @param error - The error object to capture * @param context - Additional context about the authentication error