Skip to content

fix(settings): surface OAuth client-info fetch failures as discrete errors#20457

Open
vpomerleau wants to merge 1 commit intomainfrom
FXA-13618
Open

fix(settings): surface OAuth client-info fetch failures as discrete errors#20457
vpomerleau wants to merge 1 commit intomainfrom
FXA-13618

Conversation

@vpomerleau
Copy link
Copy Markdown
Contributor

@vpomerleau vpomerleau commented Apr 24, 2026

Because

  • A failed /v1/oauth/client/:id fetch silently builds a ghost OAuth integration: scope sanitization strips every scope and the flow throws errno 109, masking the real cause across Sentry events (FXA-CONTENT-1HYP for example)
  • Regression from FXA-12995: the REST replacement for Apollo's useQuery dropped the error signal that useIntegration relied on.

This pull request

  • Adds clientInfoLoadFailed on GenericIntegration, set when client_id was present but clientInfo is undefined.
  • Short-circuits OAuthWebIntegration.getPermissions to throw SERVICE_UNAVAILABLE (errno 998) when the flag is set; existing OAuthDataError handling keeps user-facing behaviour unchanged.
  • Captures the fetch error from useClientInfoState under area: 'useClientInfoState.fetch'.
  • Adds unit coverage for the flag, the early-return, and the Sentry capture.

Issue that this pull request solves

Closes: FXA-13618

Checklist

  • My commit is GPG signed.
  • If applicable, I have modified or added tests which pass locally.
  • I have added necessary documentation (if appropriate).
  • I have verified that my changes render correctly in RTL (if appropriate).
  • I have manually reviewed all AI generated code.

How to review (Optional)

  • Suggested review order:
    1. `packages/fxa-settings/src/models/integrations/integration.ts` — the new `clientInfoLoadFailed` field.
    2. `packages/fxa-settings/src/lib/integrations/integration-factory.ts` — where the flag gets set.
    3. `packages/fxa-settings/src/models/integrations/oauth-web-integration.ts` — the early return in `getPermissions`.
    4. `packages/fxa-settings/src/models/hooks.ts` — Sentry capture in `useClientInfoState`.
    5. The three `*.test.ts` files covering each of the above.
  • Key thing to confirm: the `SERVICE_UNAVAILABLE` throw is caught at `components/App/index.tsx:522-537` and renders `OAuthDataError`, matching the UX path the existing scope-error throw was already taking.
  • Risky parts: none expected. The flag defaults to `false`, so any integration path that doesn't go through the factory (tests, non-OAuth flows) is untouched. The ghost-integration synthesis in `initClientInfo` is preserved as-is for backward compatibility; the flag is additive.

Screenshots (Optional)

N/A — no UI change. The user-visible behaviour when the client-info fetch fails continues to be `OAuthDataError`, just with an honest errno (998 "System unavailable, try again soon") instead of a misleading errno 109.

Other information (Optional)

Supersedes FXA-13172, FXA-13171, FXA-12759 (all linked from the Jira ticket — those should close once Sentry events stop accruing on post-deploy). Related to FXA-13088 which was previously cancelled but is the same ghost-integration pattern reaching a different validator.

Separate follow-ups (not in this PR):

  • If the 67k+ prod events remain after this PR lands, the new `useClientInfoState.fetch` Sentry tag gives us a clean target to investigate further.

@vpomerleau vpomerleau marked this pull request as ready for review April 28, 2026 22:38
@vpomerleau vpomerleau requested a review from a team as a code owner April 28, 2026 22:38
Copilot AI review requested due to automatic review settings April 28, 2026 22:38
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR aims to prevent “ghost” OAuth integrations when the /v1/oauth/client/:id lookup fails by making the failure explicit on the integration model, surfacing a discrete OAuth error (errno 998) instead of falling into misleading scope-validation errors, and logging the underlying fetch failure to Sentry with a dedicated tag.

Changes:

  • Add clientInfoLoadFailed to GenericIntegration and set it during IntegrationFactory.initClientInfo when client-info was expected but missing.
  • Short-circuit OAuthWebIntegration.getPermissions() to throw SERVICE_UNAVAILABLE when clientInfoLoadFailed is set, avoiding the scope-sanitization/Sentry-path.
  • Capture client-info fetch failures in useClientInfoState to Sentry with tags.area = 'useClientInfoState.fetch' and add unit tests for these behaviors.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
packages/fxa-settings/src/models/integrations/integration.ts Adds clientInfoLoadFailed flag to the base integration model.
packages/fxa-settings/src/lib/integrations/integration-factory.ts Sets clientInfoLoadFailed during integration initialization when clientInfo is missing.
packages/fxa-settings/src/models/integrations/oauth-web-integration.ts Throws SERVICE_UNAVAILABLE early from getPermissions() when client-info fetch failed.
packages/fxa-settings/src/models/hooks.ts Captures /v1/oauth/client/:id fetch errors to Sentry with a dedicated area tag.
packages/fxa-settings/src/models/integrations/oauth-web-integration.test.ts Tests early SERVICE_UNAVAILABLE throw and ensures scope-error isn’t captured to Sentry in that case.
packages/fxa-settings/src/models/hooks.test.ts Adds unit tests for useClientInfoState success + error Sentry capture paths.
packages/fxa-settings/src/lib/integrations/integration-factory.test.ts Adds coverage verifying clientInfoLoadFailed is set/unset as expected.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/fxa-settings/src/lib/integrations/integration-factory.ts Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR makes OAuth client-info fetch failures explicit in fxa-settings integrations, preventing “ghost” clientInfo state from cascading into misleading scope-validation errors and improving Sentry signal for the actual fetch failure.

Changes:

  • Add clientInfoLoadFailed to GenericIntegration and propagate it through useIntegrationIntegrationFactory.
  • Short-circuit OAuthWebIntegration.getPermissions() to throw SERVICE_UNAVAILABLE (errno 998) when client-info lookup failed.
  • Capture /v1/oauth/client/:id fetch failures to Sentry in useClientInfoState with a dedicated area tag, and add unit tests for the new behavior.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/fxa-settings/src/models/integrations/oauth-web-integration.ts Early error throw in getPermissions() when client-info fetch failed to avoid misleading scope sanitization.
packages/fxa-settings/src/models/integrations/oauth-web-integration.test.ts Adds coverage ensuring SERVICE_UNAVAILABLE is thrown and scope-error Sentry capture does not occur.
packages/fxa-settings/src/models/integrations/integration.ts Introduces clientInfoLoadFailed flag on the base integration model.
packages/fxa-settings/src/models/hooks.ts Propagates fetch-failure state into the factory and captures fetch failures to Sentry with area: useClientInfoState.fetch.
packages/fxa-settings/src/models/hooks.test.ts Adds unit tests for useClientInfoState success, network error, non-OK HTTP response, and missing client_id behavior.
packages/fxa-settings/src/lib/integrations/integration-factory.ts Accepts and applies clientInfoLoadFailed onto created integrations during initClientInfo.
packages/fxa-settings/src/lib/integrations/integration-factory.test.ts Adds coverage that the factory flags (and does not incorrectly flag) clientInfoLoadFailed.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…rrors

Because:

* A failed /v1/oauth/client/:id fetch silently builds a ghost OAuth
  integration: scope sanitisation strips every scope and the flow
  throws errno 109, masking the real cause across ~80k Sentry events
  (FXA-CONTENT-1HYP, 1GTG, related).
* Regression from FXA-12995: the REST replacement for Apollo's
  useQuery dropped the error signal that useIntegration relied on.

This commit:

* Adds clientInfoLoadFailed on GenericIntegration, set when client_id
  was present but clientInfo is undefined.
* Short-circuits OAuthWebIntegration.getPermissions to throw
  SERVICE_UNAVAILABLE (errno 998) when the flag is set; existing
  OAuthDataError handling keeps user-facing behaviour unchanged.
* Captures the fetch error from useClientInfoState under
  area: 'useClientInfoState.fetch'.
* Adds unit coverage for the flag, the early-return, and the Sentry
  capture.

Closes #FXA-13618
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants