From fdc7cd08db3447a66fc4b23d4cd084164b6f5e07 Mon Sep 17 00:00:00 2001 From: sreecharan-desu Date: Fri, 23 Jan 2026 23:28:33 +0530 Subject: [PATCH 1/2] fix(settings): support userContextId in WebChannel status requests for containers --- packages/fxa-settings/src/components/App/index.tsx | 7 +++---- packages/fxa-settings/src/lib/channels/firefox.ts | 5 ++++- .../fxa-settings/src/models/integrations/data/data.ts | 11 ++++++++++- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/packages/fxa-settings/src/components/App/index.tsx b/packages/fxa-settings/src/components/App/index.tsx index 2e27ad7cc38..ea29aa4b06d 100644 --- a/packages/fxa-settings/src/components/App/index.tsx +++ b/packages/fxa-settings/src/components/App/index.tsx @@ -89,9 +89,7 @@ const ResetPasswordConfirmedContainer = lazy( ); const ResetPasswordWithRecoveryKeyVerifiedContainer = lazy( () => - import( - '../../pages/ResetPassword/ResetPasswordWithRecoveryKeyVerified/container' - ) + import('../../pages/ResetPassword/ResetPasswordWithRecoveryKeyVerified/container') ); const CompleteSigninContainer = lazy( () => import('../../pages/Signin/CompleteSignin/container') @@ -228,7 +226,8 @@ export const App = ({ integration.data.context || '', // TODO with React pairing flow, update this if pairing flow false, - integration.data.service || '' + integration.data.service || '', + integration.data.userContextId ); } diff --git a/packages/fxa-settings/src/lib/channels/firefox.ts b/packages/fxa-settings/src/lib/channels/firefox.ts index 904c26b220c..2746fdfe0c6 100644 --- a/packages/fxa-settings/src/lib/channels/firefox.ts +++ b/packages/fxa-settings/src/lib/channels/firefox.ts @@ -63,6 +63,7 @@ type FxAStatusRequest = { service: string; // ex. 'sync' isPairing: boolean; context: string; // ex. 'fx_desktop_v3' + userContextId?: string; }; export type FxAStatusResponse = { @@ -382,7 +383,8 @@ export class Firefox extends EventTarget { async requestSignedInUser( context: string, isPairing: boolean, - service: string + service: string, + userContextId?: string ): Promise { let timeoutId: number; return Promise.race([ @@ -406,6 +408,7 @@ export class Firefox extends EventTarget { context, isPairing, service, + userContextId, }); }); }), diff --git a/packages/fxa-settings/src/models/integrations/data/data.ts b/packages/fxa-settings/src/models/integrations/data/data.ts index 0e28938dc70..4417ff5ba59 100644 --- a/packages/fxa-settings/src/models/integrations/data/data.ts +++ b/packages/fxa-settings/src/models/integrations/data/data.ts @@ -22,7 +22,11 @@ import { KeyTransforms as T, ModelDataProvider, } from '../../../lib/model-data'; -import { IsEmailOrEmpty, IsFxaRedirectToUrl, IsFxaRedirectUri } from '../../../lib/validation'; +import { + IsEmailOrEmpty, + IsFxaRedirectToUrl, + IsFxaRedirectUri, +} from '../../../lib/validation'; /** * Base integration class. Fields in this class represents data commonly accessed across many pages and is useful for various flows. @@ -115,6 +119,11 @@ export class IntegrationData extends ModelDataProvider { @IsString() @bind(T.snakeCase) flowBeginTime: string | undefined; + + @IsOptional() + @IsString() + @bind(T.snakeCase) + userContextId: string | undefined; } /** From 31782fee7e51cd8b1ff92433b681ef6190a10bc3 Mon Sep 17 00:00:00 2001 From: sreecharan-desu Date: Fri, 23 Jan 2026 23:34:19 +0530 Subject: [PATCH 2/2] fix(auth-server): safely access metrics methods in redis to prevent crash if disabled --- packages/fxa-auth-server/lib/redis.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/fxa-auth-server/lib/redis.js b/packages/fxa-auth-server/lib/redis.js index ad068cbbcad..91992d72b64 100644 --- a/packages/fxa-auth-server/lib/redis.js +++ b/packages/fxa-auth-server/lib/redis.js @@ -41,7 +41,7 @@ class FxaRedis extends RedisShared { this.log.error('redis', new Error('invalid ttl on access token')); return; } - this.metrics?.increment('redis.setAccessToken'); + this.metrics?.increment?.('redis.setAccessToken'); const span = tracer.startSpan('redis.setAccessToken'); const value = JSON.stringify(token); const result = await this.redis.setAccessToken( @@ -62,7 +62,7 @@ class FxaRedis extends RedisShared { * @returns {Promise} done */ async removeAccessToken(id) { - this.metrics?.increment('redis.removeAccessToken'); + this.metrics?.increment?.('redis.removeAccessToken'); const span = tracer.startSpan('redis.removeAccessToken'); // This does not remove the id from the user's index // because getAccessTokens cleans up expired/missing tokens @@ -76,7 +76,7 @@ class FxaRedis extends RedisShared { * @param {Buffer | string} uid */ async removeAccessTokensForPublicClients(uid) { - this.metrics?.increment('redis.removeAccessTokensForPublicClients'); + this.metrics?.increment?.('redis.removeAccessTokensForPublicClients'); const span = tracer.startSpan('redis.removeAccessTokensForPublicClients'); const result = await this.redis.removeAccessTokensForPublicClients( hex(uid) @@ -91,7 +91,7 @@ class FxaRedis extends RedisShared { * @param {Buffer | string} clientId */ async removeAccessTokensForUserAndClient(uid, clientId) { - this.metrics?.increment('redis.removeAccessTokensForUserAndClient'); + this.metrics?.increment?.('redis.removeAccessTokensForUserAndClient'); const span = tracer.startSpan('redis.removeAccessTokensForUserAndClient'); const result = await this.redis.removeAccessTokensForUserAndClient( hex(uid), @@ -106,7 +106,7 @@ class FxaRedis extends RedisShared { * @param {Buffer | string} uid */ async removeAccessTokensForUser(uid) { - this.metrics?.increment('redis.removeAccessTokensForUser'); + this.metrics?.increment?.('redis.removeAccessTokensForUser'); const span = tracer.startSpan('redis.removeAccessTokensForUser'); const result = await this.redis.removeAccessTokensForUser(hex(uid)); span.end(); @@ -119,7 +119,7 @@ class FxaRedis extends RedisShared { * @param {RefreshTokenMetadata} token */ async setRefreshToken(uid, tokenId, token) { - this.metrics?.increment('redis.setRefreshToken'); + this.metrics?.increment?.('redis.setRefreshToken'); const span = tracer.startSpan('redis.setRefreshToken'); const p1 = this.redis.setRefreshToken( hex(uid), @@ -140,7 +140,7 @@ class FxaRedis extends RedisShared { * @param {Buffer | string} tokenId */ async removeRefreshToken(uid, tokenId) { - this.metrics?.increment('redis.removeRefreshToken'); + this.metrics?.increment?.('redis.removeRefreshToken'); const span = await tracer.startSpan('redis.removeRefreshToken'); const p1 = this.redis.hdel(hex(uid), hex(tokenId)); const p2 = this.resolveInMs(p1, this.timeoutMs); @@ -154,7 +154,7 @@ class FxaRedis extends RedisShared { * @param {Buffer | string} uid */ async removeRefreshTokensForUser(uid) { - this.metrics?.increment('redis.removeRefreshTokensForUser'); + this.metrics?.increment?.('redis.removeRefreshTokensForUser'); const span = tracer.startSpan('redis.removeRefreshTokensForUser'); const p1 = this.redis.unlink(hex(uid)); const p2 = this.resolveInMs(p1, this.timeoutMs); @@ -164,13 +164,13 @@ class FxaRedis extends RedisShared { } async get(key) { - this.metrics?.increment('redis.get'); + this.metrics?.increment?.('redis.get'); const span = tracer.startSpan('redis.get'); const result = await this.redis.get(key); if (result?.length > 0) { span.setAttribute('redis.get.size', result.length); - this.metrics?.histogram('redis.get.size', result.length); + this.metrics?.histogram?.('redis.get.size', result.length); } span.end(); return result;