Skip to content

feat: ENG-12261 add OAuth 2.0 support and settings UI for Phrase integration#4699

Open
sanyamkamat wants to merge 20 commits into
mainfrom
add_oauth_option
Open

feat: ENG-12261 add OAuth 2.0 support and settings UI for Phrase integration#4699
sanyamkamat wants to merge 20 commits into
mainfrom
add_oauth_option

Conversation

@sanyamkamat

@sanyamkamat sanyamkamat commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Description

Adds OAuth 2.0 support and settings UI for Phrase integration


Note

Medium Risk
Touches authentication and all Phrase translation API calls; OAuth/session edge cases are handled explicitly but depend on server OAuth endpoints behaving correctly.

Overview
Adds SSO / OAuth 2.0 alongside username/password for the Phrase connector, with settings for auth mode, per-org OAuth Client ID, and a Connect / Disconnect UI that runs the popup flow via Builder’s /api/v1/memsource/oauth/* endpoints (tokens stay server-side).

Replaces the direct Phrase client with PhraseApi, which calls the monolith for jobs and apply-translation, checks credentials before translate actions, and retries after oauth/refresh on 401. oauth-client.ts handles prepare/start, origin-checked postMessage, disconnect, and apiKey-scoped session markers so connect/disconnect and org switches don’t show stale connection state.

Plugin settings hide password fields in OAuth mode; translate/apply paths call ensureAuthenticated(). README documents OAuth setup and the flow. Package version bumps to 0.0.17-1; the stub Request an updated translation content action is removed while outdated translation warnings are refactored into checkTranslationFreshness.

Reviewed by Cursor Bugbot for commit b71137f. Bugbot is set up for automated code reviews on this repo. Configure here.

@sanyamkamat sanyamkamat requested review from a team and lihuelg and removed request for a team July 3, 2026 17:54
@changeset-bot

changeset-bot Bot commented Jul 3, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: b71137f

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Comment thread plugins/phrase-conector/src/phrase-api.ts
Comment thread plugins/phrase-conector/src/phrase-api.ts
Comment thread plugins/phrase-conector/src/oauth-client.ts
Comment thread plugins/phrase-conector/src/plugin.tsx
Comment thread plugins/phrase-conector/src/oauth-client.ts
Comment thread plugins/phrase-conector/src/plugin.tsx Outdated
@nx-cloud

nx-cloud Bot commented Jul 3, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit b71137f

Command Status Duration Result
nx test @e2e/nextjs-sdk-next-app ✅ Succeeded 7m 24s View ↗
nx test @e2e/qwik-city ✅ Succeeded 6m 54s View ↗
nx test @e2e/angular-19-ssr ✅ Succeeded 5m 23s View ↗
nx test @e2e/angular-17 ✅ Succeeded 6m 7s View ↗
nx test @e2e/gen1-react ✅ Succeeded 4m 47s View ↗
nx test @e2e/react-sdk-next-pages ✅ Succeeded 4m 50s View ↗
nx test @e2e/angular-17-ssr ✅ Succeeded 5m 21s View ↗
nx test @e2e/hydrogen ✅ Succeeded 5m 17s View ↗
Additional runs (38) ✅ Succeeded ... View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-07-06 13:29:53 UTC

Comment thread plugins/phrase-conector/src/phrase-api.ts
Comment thread plugins/phrase-conector/src/phrase-api.ts
Comment thread plugins/phrase-conector/src/plugin.tsx Outdated
Comment thread plugins/phrase-conector/src/oauth-client.ts
Comment thread plugins/phrase-conector/src/oauth-client.ts
Comment thread plugins/phrase-conector/src/plugin.tsx
Comment thread plugins/phrase-conector/src/plugin.tsx
Comment thread plugins/phrase-conector/src/phrase-api.ts
Comment thread plugins/phrase-conector/src/plugin.tsx Outdated
Comment thread plugins/phrase-conector/src/plugin.tsx Outdated
Comment thread plugins/phrase-conector/src/plugin.tsx
Comment thread plugins/phrase-conector/src/oauth-client.ts
@sanyamkamat sanyamkamat changed the title feat: add OAuth 2.0 support and settings UI for Phrase integration feat: ENG-12261 add OAuth 2.0 support and settings UI for Phrase integration Jul 5, 2026
Comment thread plugins/phrase-conector/src/phrase-api.ts
Comment thread plugins/phrase-conector/src/phrase-api.ts
Comment thread plugins/phrase-conector/src/oauth-client.ts Outdated
Comment thread plugins/phrase-conector/src/phrase-api.ts
Comment thread plugins/phrase-conector/src/phrase-api.ts
Comment thread plugins/phrase-conector/src/plugin.tsx
Comment thread plugins/phrase-conector/src/phrase-api.ts Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b71137f. Configure here.

await this.loaded;
if (readOrgPluginSetting('authMode') !== 'oauth') {
if (!readOrgPluginSetting('userName') || !readOrgPluginSetting('password')) {
throw new Error('Phrase username/password is not configured.');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Auth reads persisted org settings

Medium Severity

ensureAuthenticated and the 401 refresh branch use readOrgPluginSetting for authMode and OAuth metadata, while job calls use the plugin settings object elsewhere. Unsaved Authentication changes can leave persisted org data on password mode, so a successful OAuth connect still fails Translate with username/password errors until settings are saved.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit b71137f. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed. Reworked ensureAuthenticated so the OAuth session marker (set by connectWithOAuth) is the primary signal: it now treats the org as OAuth mode when authMode === 'oauth' OR a live session marker exists. So a successful OAuth connect passes the client check even before the persisted authMode has propagated to the in-memory org model (or before the form is saved), instead of falling into the username/password branch. The server already decides the real mode from persisted Firestore keys, so this just keeps the client pre-check in step.

const oauth = candidates.reduce((a: any, b: any) => (b.expiresAt > a.expiresAt ? b : a));
if (oauth.expiresAt <= Date.now()) {
throw new Error("Phrase OAuth session expired. Please reconnect.");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Missing expiresAt passes auth check

Low Severity

After picking the best OAuth candidate, ensureAuthenticated only tests expiresAt <= Date.now(). It never uses isOAuthValid, so metadata without expiresAt skips both the expiry failure and a proper not-connected error and can proceed to API calls incorrectly.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit b71137f. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed. The chosen candidate now goes through isOAuthValid(oauth) (which rejects both missing expiresAt and expired tokens) instead of a bare expiresAt <= Date.now() comparison, so metadata without an expiresAt no longer slips past as connected — it throws a proper not-connected / reconnect error.

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