Spreadsheet Automation Demo / 開發指南
diagram-first v2 · Light
Guides / Authentication / Desktop OAuth
Integration guide

Google Sheets OAuth:從授權到驗證的安全路徑

以完全虛構的桌面應用程式為例,先看資料如何流動、敏感資訊停在哪裡,再依最短路徑完成設定與排錯。

Desktop OAuth clientDrive + Sheets最小權限公開安全範例
Definition of done

成功不是「看到同意畫面」

完成的判準是:應用程式以最小 scopes 取得憑證、安全儲存,重啟後仍能載入,並對一份明確選定的測試試算表完成唯讀 metadata request。瀏覽器 redirect 與 authorization code 都只是短暫中間狀態。

雲端

示範專案已啟用 Google Drive API 與 Google Sheets API,OAuth client 類型為 Desktop app。

本機

程式可短暫監聽 loopback callback,token 使用作業系統憑證庫或權限受限的本機檔案。

Diagram 01

OAuth Authorization Code Sequence

這張圖只回答一個問題:授權碼如何從使用者同意,安全走到本機 token store?

Authorization code flow

從 App 到 Token Store 的完整序列

OAuth Authorization Code SequenceApp 開啟 Browser;Browser 前往 Google Consent;同意後 redirect 到 localhost;App 接收短期 code,交給 Token Endpoint 交換 token,最後寫入 Token Store。AppBrowserGoogleConsentlocalhostredirectAppTokenEndpointTokenStore1 · 開啟授權網址2 · 登入並同意 scopes3 · 302 + code + state4 · listener 驗證 state5 · 一次性 code + verifier6 · access / refresh token7 · 安全落盤只在本機處理state 比對code 用後即棄
圖 1。Browser 只承載同意與 redirect;真正的 code 交換與 token 儲存由本機 App 完成。

結論:localhost redirect 是 Desktop OAuth 的交接點,不是部署失敗;App 必須先啟動 listener,驗證 state,再交換一次性 code。

Diagram 02

Trust Boundary

這張圖只回答一個問題:敏感資訊應停在哪個信任區域,哪些資料才能進入 Sheet?

Data placement

Browser、Google OAuth Server 與 Local Application

OAuth Trust Boundary三個區域分別是 Browser、Google OAuth Server、Local Application。client secret 留在本機;authorization code 短期存在;token 不進 Sheet、Git 或聊天;Sheet 只接收業務資料。BrowserGoogle OAuth ServerLocal Application人機互動區外部授權區受控執行與儲存區Consent UI只顯示 scopes 與同意結果Authorization Code短期存在 · 一次性Client 設定 + Token Storeclient secret 與 token 留本機code 經 loopback 交給 AppGoogle Sheet只接收業務資料禁止流向Token → SheetToken → GitToken → 聊天Client secret → Browser / 文件 / log虛線邊界代表不同信任區;跨界只傳流程必要的最小資料。
圖 2。OAuth 憑證與試算表業務資料是兩條不同資料路徑;不要因為最終使用 Sheets,就把 token 寫進儲存格。

結論:client secret 與 token 只留在 Local Application;authorization code 短期存在、用後即棄;Sheet、Git 與聊天都不是憑證儲存區。

Least privilege

先固定最小 scopes

Drive https://www.googleapis.com/auth/drive.file

只讓應用程式接觸由它建立、或使用者明確選取的檔案。

Sheets https://www.googleapis.com/auth/spreadsheets

需要讀寫內容時使用;若驗證只讀,可評估 https://www.googleapis.com/auth/spreadsheets.readonly

scope 改變後要重新授權舊 token 不會自動取得新增權限。先刪除示範 token,再重新走 consent,不要直接擴大為完整 Drive scope。
Quickstart

7 個可驗證步驟

流程圖已說明資料移動;這裡只保留每一步的操作與完成條件。

1

啟用 Drive 與 Sheets API

成果:API Library 顯示兩個服務均為 Enabled。

在示範 project 啟用兩個 API。建立 OAuth client 不會自動啟用服務。

gcloud · placeholder
gcloud services enable \
  drive.googleapis.com \
  sheets.googleapis.com \
  --project=YOUR_DEMO_PROJECT_ID
預期結果命令成功,且輸出與歷史中沒有任何 OAuth 憑證。
2

設定 Testing audience

成果:受控測試帳號已列入 Test users。

保持 Publishing status 為 Testing。這裡控制「誰能測試」,不是控制 scope。

預期結果測試使用者能開啟同意畫面;公開文件不記錄帳號。
3

建立 Desktop OAuth client

成果:client 設定只存在私密本機環境。

.gitignore
# OAuth 設定與 token 永不進版控
client_secret*.json
.google/
.app/google_token.json
預期結果Application type 明確為 Desktop app,設定檔未加入 Git。
4

產生授權網址並啟動 listener

成果:Browser 顯示預期 scopes,redirect 指向 loopback。

每次建立新的 state 與 PKCE verifier;先啟動 listener,再開啟 authorization URL。

環境變數 · 不含真值
export OAUTH_CLIENT_ID='YOUR_CLIENT_ID'
export OAUTH_REDIRECT_URI='http://127.0.0.1:YOUR_PORT/callback'
export OAUTH_SCOPES='https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/spreadsheets'
預期結果URL 不含 client secret;callback state 與 session state 完全一致。
5

交換一次性 code

成果:Token Endpoint 成功回應,log 只記錄狀態。

由 OAuth library 在記憶體中送出 code、同一 redirect URI 與 PKCE verifier。code 不落盤、不重送。

Token Endpoint
POST https://oauth2.googleapis.com/token
Content-Type: application/x-www-form-urlencoded

client_id=YOUR_CLIENT_ID&code=ONE_TIME_CODE&
code_verifier=YOUR_PKCE_VERIFIER&
redirect_uri=http%3A%2F%2F127.0.0.1%3AYOUR_PORT%2Fcallback&
grant_type=authorization_code
預期結果交換成功;憑證值不出現在 log、文件、聊天或 shell history。
6

安全儲存 token

成果:只有目前使用者可讀取 token store。

優先使用作業系統憑證庫。若示範必須使用檔案,目錄設為 700、檔案設為 600,並採原子寫入。

shell · 只建立容器
install -d -m 700 ~/.app
install -m 600 /dev/null ~/.app/google_token.json
# 由應用程式原子寫入,不在命令列輸入 token
預期結果儲存位置未被版控、備份或公開截圖收錄。
7

重啟並驗證最小 request

成果:新 process 載入憑證並讀取指定試算表 metadata。

以 OAuth library 載入或 refresh credential,再讀取明確選定的測試 spreadsheet。公開輸出仍使用 placeholder。

request shape
GET https://sheets.googleapis.com/v4/spreadsheets/YOUR_TEST_SPREADSHEET_ID?fields=spreadsheetId%2Cproperties.title
Authorization: Bearer [ACCESS_CREDENTIAL_PLACEHOLDER]
預期結果回傳指定 spreadsheet 的 ID 與 title,且沒有要求更廣的 Drive 權限。
Diagram 03

Troubleshooting Decision Tree

這張圖只回答一個問題:看到授權或 API 錯誤時,第一個正確修復動作是什麼?

First corrective action

依症狀選擇最短修復路徑

OAuth Troubleshooting Decision Tree403 access_denied 檢查 Test User;API not enabled 啟用 Drive 與 Sheets;insufficient_scope 重新授權;localhost 無法連線時視為預期 redirect,複製完整 URL 給仍在執行的 App。授權或 API 呼叫失敗先保留錯誤文字,不貼任何 token錯誤屬於哪一類?依畫面或 response code 分流403 access_deniedAPI not enabledinsufficient_scopelocalhost無法連線同意前即被拒絕服務未在 project 啟用舊 token 缺少 scoperedirect 已到 loopback檢查 Test User保持 Testing,加入受控帳號啟用 Drive API與 Sheets API確認 OAuth client 屬同一 project重新授權清除舊 token,再跑 consent預期行為複製完整 URL交給仍在執行的 App重新執行最小驗證 request仍失敗才檢查 redirect、state、PKCE 與資源權限
圖 3。每個分支只給第一個可驗證動作;不要以擴大 scope、切換 Production 或停用安全檢查作為捷徑。

結論:先把錯誤分類,再做最小修正。localhost 無法顯示頁面不必然代表授權失敗;保留完整 URL,讓仍在執行的 App 接手。

Acceptance checks

完成前逐項驗證

  • OAuth client 類型是 Desktop app;consent screen 維持 Testing。
  • authorization URL 只有最小 scopes,state 與 PKCE 每次重新產生。
  • localhost listener 綁定 loopback、驗證 state,接受一次後關閉。
  • authorization code 不落盤、不重用,也不進 log。
  • client 設定與 token 僅留在本機安全儲存;不進 Sheet、Git 或聊天。
  • 重啟 process 後仍可載入或 refresh credential。
  • 最小 request 只讀取明確選定的測試 spreadsheet metadata。
  • 公開內容只使用 placeholder,沒有帳號、真實 credential、token 或內部資訊。
憑證外洩時立即撤銷 token、輪替受影響 credential、清除 artifacts 並檢查存取紀錄;只刪除貼文或 commit 不足以解除風險。