From 0c1660858b0bc80de92ac91f84a7a2c8b080baae Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 5 Mar 2026 20:35:23 -0500 Subject: [PATCH] docs: update vimdoc for unified Google auth Problem: `doc/pending.txt` still documented per-backend `:Pending gtasks auth` / `:Pending gcal auth` commands and separate token files, which no longer exist after the auth unification. Solution: add `:Pending auth` entry to COMMANDS and a new `*pending-google-auth*` section covering the shared PKCE flow, combined scopes, and `google_tokens.json`. Remove `auth` from gcal/gtasks action tables and update all cross-references to use `:Pending auth`. --- doc/pending.txt | 81 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 58 insertions(+), 23 deletions(-) diff --git a/doc/pending.txt b/doc/pending.txt index 2465ba3..994afc6 100644 --- a/doc/pending.txt +++ b/doc/pending.txt @@ -65,8 +65,9 @@ CONTENTS *pending-contents* 17. Sync Backends ................................... |pending-sync-backend| 18. Google Calendar .......................................... |pending-gcal| 19. Google Tasks ............................................ |pending-gtasks| - 20. Data Format .............................................. |pending-data| - 21. Health Check ........................................... |pending-health| + 20. Google Authentication ......................... |pending-google-auth| + 21. Data Format .............................................. |pending-data| + 22. Health Check ........................................... |pending-health| ============================================================================== REQUIREMENTS *pending-requirements* @@ -148,6 +149,15 @@ COMMANDS *pending-commands* Populate the quickfix list with all tasks that are overdue or due today. Open the list with |:copen| to navigate to each task's category. + *:Pending-auth* +:Pending auth + Authorize pending.nvim to access Google services (Tasks and Calendar). + Prompts with |vim.ui.select| to choose gtasks, gcal, or both — all + options run the same combined OAuth flow and produce a single shared + token file. If no credentials are configured, the setup wizard runs + first to collect a client ID and secret. + See |pending-google-auth| for full details. + *:Pending-gtasks* :Pending gtasks {action} Run a Google Tasks action. An explicit action is required. @@ -156,13 +166,11 @@ COMMANDS *pending-commands* `sync` Push local changes then pull remote changes. `push` Push local changes to Google Tasks only. `pull` Pull remote changes from Google Tasks only. - `auth` Run the OAuth authorization flow. Examples: >vim :Pending gtasks sync " push then pull :Pending gtasks push " push local → Google Tasks :Pending gtasks pull " pull Google Tasks → local - :Pending gtasks auth " authorize < Tab completion after `:Pending gtasks ` lists available actions. @@ -174,11 +182,9 @@ COMMANDS *pending-commands* Actions: ~ `push` Push tasks with due dates to Google Calendar. - `auth` Run the OAuth authorization flow. Examples: >vim :Pending gcal push " push to Google Calendar - :Pending gcal auth " authorize < Tab completion after `:Pending gcal ` lists available actions. @@ -920,7 +926,6 @@ Each module returns a table conforming to the backend interface: >lua ---@class pending.SyncBackend ---@field name string - ---@field auth fun(): nil ---@field push? fun(): nil ---@field pull? fun(): nil ---@field sync? fun(): nil @@ -929,15 +934,17 @@ Each module returns a table conforming to the backend interface: >lua Required fields: ~ {name} Backend identifier (matches the filename). - {sync} Main sync action. Called by `:Pending `. - {auth} Authorization flow. Called by `:Pending auth`. Optional fields: ~ {push} Push-only action. Called by `:Pending push`. {pull} Pull-only action. Called by `:Pending pull`. + {sync} Main sync action. Called by `:Pending sync`. {health} Called by `:checkhealth pending` to report backend-specific diagnostics (e.g. checking for external tools). +Note: authorization is not a per-backend action. Use `:Pending auth` to +authenticate all Google backends at once. See |pending-google-auth|. + Backend-specific configuration goes under `sync.` in |pending-config|. ============================================================================== @@ -957,7 +964,7 @@ Configuration: >lua < No configuration is required to get started — bundled OAuth credentials are -used by default. Run `:Pending gcal auth` and the browser opens immediately. +used by default. Run `:Pending auth` and the browser opens immediately. *pending.GcalConfig* Fields: ~ @@ -983,15 +990,8 @@ Credentials are resolved in order: 3. Bundled credentials shipped with the plugin (always available). OAuth flow: ~ -On the first `:Pending gcal` call the plugin detects that no refresh token -exists and opens the Google authorization URL in the browser using -|vim.ui.open()|. A temporary local HTTP server listens on port 18392 for the -OAuth redirect. The PKCE (Proof Key for Code Exchange) flow is used. After -the user grants consent, the -authorization code is exchanged for tokens and the refresh token is stored at -`stdpath('data')/pending/gcal_tokens.json` with mode `600`. Subsequent syncs -use the stored refresh token and refresh the access token automatically when -it is about to expire. +See |pending-google-auth|. Tokens are shared with the gtasks backend and +stored at `stdpath('data')/pending/google_tokens.json`. `:Pending gcal push` behavior: ~ For each task in the store: @@ -1020,7 +1020,7 @@ Configuration: >lua < No configuration is required to get started — bundled OAuth credentials are -used by default. Run `:Pending gtasks auth` and the browser opens immediately. +used by default. Run `:Pending auth` and the browser opens immediately. *pending.GtasksConfig* Fields: ~ @@ -1043,9 +1043,8 @@ Credential resolution: ~ Same three-tier resolution as the gcal backend (see |pending-gcal|). OAuth flow: ~ -Same PKCE flow as the gcal backend; listens on port 18393. Tokens are stored -at `stdpath('data')/pending/gtasks_tokens.json`. Run `:Pending gtasks auth` -to authorize; subsequent syncs refresh the token automatically. +See |pending-google-auth|. Tokens are shared with the gcal backend and +stored at `stdpath('data')/pending/google_tokens.json`. `:Pending gtasks` actions: ~ @@ -1077,6 +1076,42 @@ the remainder is ignored. Recurrence (`rec:`) is stored in notes for round-tripping but is not expanded by Google Tasks (GTasks has no recurrence API). +============================================================================== +GOOGLE AUTHENTICATION *pending-google-auth* + +Both the gcal and gtasks backends share a single OAuth client with combined +scopes (`tasks` + `calendar`). One authorization flow covers both services +and produces one token file. + +:Pending auth ~ +Prompts with |vim.ui.select| offering three options: `gtasks`, `gcal`, and +`both`. All three options run the identical combined OAuth flow — the choice +is informational only. If no real credentials are configured (i.e. bundled +placeholders are in use), the setup wizard runs first to collect a client ID +and client secret before opening the browser. + +OAuth flow: ~ +A PKCE (Proof Key for Code Exchange) flow is used: +1. A random 64-character `code_verifier` is generated. +2. Its SHA-256 hash is base64url-encoded as the `code_challenge`. +3. The Google authorization URL is opened in the browser via |vim.ui.open()|. +4. A temporary TCP server on port 18392 waits up to 120 seconds for the + OAuth redirect. +5. The authorization code is exchanged for tokens via `curl`. +6. The refresh token is written to + `stdpath('data')/pending/google_tokens.json` with mode `600`. +7. Subsequent syncs refresh the access token automatically when it is about + to expire (within 60 seconds of the `expires_in` window). + +Credential resolution: ~ +Credentials are resolved in order for the `google` config key: +1. `client_id` + `client_secret` under `sync.google` (highest priority). +2. JSON file at `sync.google.credentials_path` or the default path + `stdpath('data')/pending/google_credentials.json`. +3. Bundled placeholder credentials (always available; trigger setup wizard). + +The `installed` wrapper format from the Google Cloud Console is accepted. + ============================================================================== DATA FORMAT *pending-data*