Skip to content

feat(google-docs): managed OAuth-redirect Picker (no API key, no BYOK)#620

Merged
Gagancreates merged 2 commits into
drivefrom
drive-oauth-picker-managed
Jun 22, 2026
Merged

feat(google-docs): managed OAuth-redirect Picker (no API key, no BYOK)#620
Gagancreates merged 2 commits into
drivefrom
drive-oauth-picker-managed

Conversation

@Gagancreates

@Gagancreates Gagancreates commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Replaces the experimental Google Docs pickers with the managed (rowboat-mode) OAuth-redirect Picker (trigger_onepick) — no Picker API key, no appId, no BYOK credentials on the desktop. Verified end-to-end on staging ✅. Pairs with backend rowboatlabs/rowboatx-backend#7 (merged to develop/staging).

Flow

  1. Add Google Doc → Choose → desktop opens ${webappUrl}/oauth/google/picker/start.
  2. Backend runs a standalone drive.file OAuth (company client) with trigger_onepick — Google shows the Picker in the consent screen and returns picked_file_ids.
  3. Backend parks the file ids + a fresh drive.file token and deep-links rowboat://oauth/google/picker/done?session=….
  4. Desktop claims { fileIds, tokens } via POST /v1/google-oauth/claim-picked and downloads the doc with that token — imports as an editable .docx and opens it.

Adds (managed picker)

  • core: importGoogleDocWithToken (download with an explicit token; fetch/metadata helpers take an optional Drive client, sharing writeDocxAndLink) + claimPickedFilesViaBackend.
  • main: google-picker-managed.ts (opens start URL, resolves on the picker deep link) + completion routing in deeplink.ts.
  • ipc: google-docs:pickViaManaged.
  • renderer: the picker dialog gates on Rowboat sign-in — the picker grants drive.file per-file, so no pre-existing Google connection or scope is required.

Removes (the now-dead picker experiments)

The managed dialog is the only picker consumer, so the prior experiments are removed:

  • API-key / system-browser picker: google-docs:openPicker handler + schema, renderer lib/google-picker.ts (Picker JS SDK), google-docs:getAccessToken + core getGoogleAccessToken.
  • BYOK / ngrok trigger_onepick: google-picker-oauth.ts, pickViaOAuth + schema, google-picker.ts redirect-URL helpers.
  • Kept GoogleClientIdModal / google-credentials-store — still used by the general BYOK Google connect (onboarding, connectors, settings).

Notes

  • tsc clean (main + renderer), lint clean on changed files (one pre-existing EmailBlockSchema unused-import in shared/ipc.ts is unrelated).
  • Managed connect doesn't carry drive.file, so the picker mints its own token — existing managed users aren't forced to reconnect.

To ship to prod

  1. Backend develop → main + deploy (api.x / app.x).
  2. Register https://app.x.rowboatlabs.com/oauth/google/picker/callback on the prod company OAuth client.
  3. Merge this → drive (Drive #583) → dev, then cut a new desktop app release. (Backend must reach prod before the desktop release.)

Adds the managed (rowboat-mode) Google Docs picker via Google's trigger_onepick
flow. The Rowboat backend runs a standalone drive.file OAuth with the company
client, renders the Picker inside the browser consent screen, and deep-links the
selection back; the desktop downloads the picked doc with the fresh drive.file
token the backend returns. No Picker API key, appId, or BYOK credentials on the
desktop.

- core: importGoogleDocWithToken downloads a picked doc with an explicit token;
  fetch/metadata helpers take an optional Drive client and share writeDocxAndLink.
  claimPickedFilesViaBackend claims the parked file ids + token from the api.
- main: google-picker-managed.ts opens the backend start URL and resolves on the
  rowboat://oauth/google/picker/done deep link; deeplink.ts routes that completion.
- ipc: google-docs:pickViaManaged.
- renderer: the picker dialog gates on Rowboat sign-in (the picker grants
  drive.file per-file, so no pre-existing connection or scope is required).

Backend contract: rowboatlabs/rowboatx-backend#7
(GET /oauth/google/picker/{start,callback}, POST /v1/google-oauth/claim-picked).
@Gagancreates Gagancreates force-pushed the drive-oauth-picker-managed branch from 813e5ad to 581a071 Compare June 22, 2026 19:29
@Gagancreates Gagancreates changed the title Google Docs Picker without a Picker API key (trigger_onepick) feat(google-docs): managed OAuth-redirect Picker (no API key, no BYOK) Jun 22, 2026
The managed picker replaced the only consumer (the picker dialog), so the
experimental API-key Picker is now unused. Removes:
- main: google-docs:openPicker handler (system-browser loopback Picker)
- shared: google-docs:openPicker + google-docs:getAccessToken IPC schemas
- core: getGoogleAccessToken (token plumbing for the client-side Picker)
- renderer: lib/google-picker.ts (Picker JS SDK loader)

Kept GoogleClientIdModal / google-credentials-store — still used by the
general BYOK Google connect in onboarding, connectors, and settings.
@Gagancreates Gagancreates merged commit 67b5214 into drive Jun 22, 2026
2 checks passed
Gagancreates added a commit that referenced this pull request Jun 22, 2026
* add drive sync up and down

* add drive button

* google doc icon

* icon changes

* show error state with retry in google doc picker

* feat(google-docs): import and sync down as Markdown, record remote revision

* feat(google-docs): structure-preserving sync up with remote-conflict guard

* feat(google-docs): overwrite-confirm on sync conflict and last-synced indicator

* feat(google-docs): store linked docs as .docx, edit in docx editor, sync via Drive

* feat(google-docs): offer BYOK connect in picker so signed-in users can grant Drive/Docs scopes

* fix(google-docs): request full drive scope so .docx sync-up can write back

* fix(google-docs): search all drives in doc picker, log result count

* feat(google-docs): import native Docs AND uploaded .docx files from Drive

* chore(google-docs): drop dev-only test file

* feat(google-docs): use Google Picker + drive.file scope instead of full-drive listing

* fix(google-oauth): request offline access so BYOK tokens refresh

BYOK never requested access_type=offline/prompt=consent so no refresh token was issued and tokens died after ~1h; also stop handing back expired tokens and extend the connect timeout to 10m.

* feat(google-docs): pick docs via system-browser Google Picker

Runs the Picker in the user's real browser (it 403s inside Electron), sets appId so the drive.file grant attaches to the picked file, and downloads + opens the selected doc.

* feat(google-docs): managed OAuth-redirect Picker (no API key, no BYOK) (#620)

* feat(google-docs): managed OAuth-redirect Picker (no API key, no BYOK)

Adds the managed (rowboat-mode) Google Docs picker via Google's trigger_onepick
flow. The Rowboat backend runs a standalone drive.file OAuth with the company
client, renders the Picker inside the browser consent screen, and deep-links the
selection back; the desktop downloads the picked doc with the fresh drive.file
token the backend returns. No Picker API key, appId, or BYOK credentials on the
desktop.

- core: importGoogleDocWithToken downloads a picked doc with an explicit token;
  fetch/metadata helpers take an optional Drive client and share writeDocxAndLink.
  claimPickedFilesViaBackend claims the parked file ids + token from the api.
- main: google-picker-managed.ts opens the backend start URL and resolves on the
  rowboat://oauth/google/picker/done deep link; deeplink.ts routes that completion.
- ipc: google-docs:pickViaManaged.
- renderer: the picker dialog gates on Rowboat sign-in (the picker grants
  drive.file per-file, so no pre-existing connection or scope is required).

Backend contract: rowboatlabs/rowboatx-backend#7
(GET /oauth/google/picker/{start,callback}, POST /v1/google-oauth/claim-picked).

* chore(google-docs): remove the dead API-key/system-browser Picker

The managed picker replaced the only consumer (the picker dialog), so the
experimental API-key Picker is now unused. Removes:
- main: google-docs:openPicker handler (system-browser loopback Picker)
- shared: google-docs:openPicker + google-docs:getAccessToken IPC schemas
- core: getGoogleAccessToken (token plumbing for the client-side Picker)
- renderer: lib/google-picker.ts (Picker JS SDK loader)

Kept GoogleClientIdModal / google-credentials-store — still used by the
general BYOK Google connect in onboarding, connectors, and settings.

---------

Co-authored-by: Gagancreates <gaganp000999@gmail.com>
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.

1 participant