適用於行動裝置的 OAuth 2.0 和桌面應用程式

透過集合功能整理內容 你可以依據偏好儲存及分類內容。

本文說明在手機、平板電腦和電腦等裝置上安裝的應用程式如何使用 Google 的 OAuth 2.0 端點來授權存取 Google API。

OAuth 2.0 可讓使用者與應用程式共用特定資料,同時保有使用者名稱、密碼和其他資訊的隱私性。 舉例來說,應用程式可以使用 OAuth 2.0,取得使用者儲存在 Google 雲端硬碟中的檔案的權限。

已安裝的應用程式會發布到個別裝置,並假設這些應用程式無法保存密鑰。當使用者在應用程式或應用程式於背景執行時,他們就能存取 Google API。

這項授權流程與網路伺服器應用程式類似。主要差別在於已安裝的應用程式必須開啟系統瀏覽器並提供本機重新導向 URI,才能處理來自 Google 授權伺服器的回應。

替代方案

如果是行動應用程式,建議您使用 AndroidiOS 適用的 Google 登入功能。Google 登入用戶端程式庫會處理驗證和使用者授權,而且實作方式可能比此處說明的較低層級通訊協定更簡單。

如果應用程式是在不支援系統瀏覽器的裝置上運作,或是輸入功能有限 (例如電視、遊戲主機、攝影機或印表機),請參閱適用於電視和裝置的 OAuth 2.0在電視和有限輸入裝置上登入帳戶

資料庫與示例

建議您參考下列程式庫和範例,協助您實作本文件所述的 OAuth 2.0 流程:

必要條件

為您的專案啟用 API

任何呼叫 Google API 的應用程式都必須在 API Console中啟用這些 API。

如何在專案中啟用 API:

  1. Open the API Library 。 Google API Console
  2. If prompted, select a project, or create a new one.
  3. API Library 會列出所有可用的 API,並按產品系列和熱門程度分組。如果清單中沒有您要啟用的 API,請使用搜尋功能尋找該 API,或在所屬的產品系列中按一下 [查看全部]
  4. 選取要啟用的 API,然後按一下「Enable」按鈕。
  5. If prompted, enable billing.
  6. If prompted, read and accept the API's Terms of Service.

建立授權憑證

任何使用 OAuth 2.0 來存取 Google API 的應用程式,都必須具有授權憑證,能識別 Google 的 OAuth 2.0 伺服器中的應用程式。下列步驟說明如何建立專案的憑證。這樣一來,應用程式就能利用該憑證來存取您為該專案啟用的 API。

  1. Go to the Credentials page.
  2. 按一下 [Create credentials] (建立憑證) > [OAuth client ID] (OAuth 用戶端 ID)
  3. 以下各節將說明 Google 授權伺服器支援的用戶端類型和重新導向方法。為您的應用程式選擇建議的用戶端類型、為 OAuth 用戶端命名,並視情況設定表單中的其他欄位。

自訂 URI 配置 (Android、iOS、UWP)

建議您為 Android 應用程式、iOS 應用程式和通用 Windows 平台 (UWP) 應用程式採用自訂的 URI 配置。

Android
  1. 選取 [Android] 應用程式類型。
  2. 輸入 OAuth 用戶端的名稱。這個名稱會顯示在專案的 Credentials page 中,以便識別用戶端。
  3. 請輸入 Android 應用程式的套件名稱。您可以在應用程式資訊清單檔案的 <manifest> 元素的 package 屬性中定義這個值。
  4. 輸入應用程式發布的 SHA-1 簽署憑證指紋。
    • 如果您的應用程式使用 Google Play 應用程式簽署,請從 Play 管理中心的應用程式簽署頁面複製 SHA-1 指紋。
    • 如果您是自行管理 KeyStore 和簽署金鑰,請使用 Java 隨附的 keytool 公用程式以使用者可理解的格式列印憑證資訊。複製 keytool 輸出中 Certificate fingerprints 區段的 SHA1 值。詳情請參閱 Android 版 Google API 說明文件中的驗證用戶端
  5. 按一下「建立」
iOS
  1. 選取 [iOS] 應用程式類型。
  2. 輸入 OAuth 用戶端的名稱。這個名稱會顯示在專案的 Credentials page 中,以便識別用戶端。
  3. 輸入應用程式的軟體包 ID。軟體包 ID 是應用程式資訊屬性清單資源檔案 (info.plist) 中 CFBundleIdentifier 鍵的值。這個值最常出現在 Xcode 專案編輯器的一般窗格或「簽署和功能」窗格中。軟體包 ID 也會顯示在 Apple App Store Connect 網站中,「應用程式資訊」頁面的「一般資訊」部分。
  4. (選填)

    如果您的應用程式已在 Apple App Store 發布,請輸入您應用程式的 App Store ID。商店編號是每個 Apple App Store 網址中所包含的數字字串。

    1. 在 iOS 或 iPadOS 裝置上開啟 Apple App Store 應用程式
    2. 搜尋您的應用程式。
    3. 選取 [分享] 按鈕 (正方形和向上箭頭)。
    4. 選取 [複製連結]
    5. 將連結貼到文字編輯器中。App Store ID 是網址的最終部分,

      範例:https://apps.apple.com/app/google/id284815942

  5. (選填)

    輸入您的小組 ID。詳情請參閱 Apple 開發人員帳戶說明文件中的找出您的團隊 ID

  6. 按一下「建立」
UWP
  1. 選取「Universal Windows Platform」應用程式類型。
  2. 輸入 OAuth 用戶端的名稱。這個名稱會顯示在專案的 Credentials page 中,以便識別用戶端。
  3. 輸入應用程式的 12 個字元 Microsoft Store ID。您可以在 Microsoft 合作夥伴中心的「應用程式管理」專區的「應用程式身分」頁面上找到這個值。
  4. 按一下「建立」

對於 UWP 應用程式,自訂 URI 配置不得超過 39 個字元。

回送 IP 位址 (macOS、Linux、Windows 桌面)

如要使用這個網址接收授權碼,您的應用程式必須在本機網路伺服器上監聽。這已在許多平台上 (但不是所有) 都有提供。不過,如果您的平台支援,那麼這是取得授權碼的建議機制。

應用程式收到授權回應時,為求最佳可用性,應顯示 HTML 網頁,指示使用者關閉瀏覽器並返回應用程式。

建議使用方式 macOS、Linux 和 Windows 電腦版應用程式 (而非通用 Windows 平台平台應用程式)
表單值 將應用程式類型設為 [電腦版應用程式]

手動複製/貼上

識別存取權範圍

範圍可讓應用程式僅要求所需資源的存取權,同時讓使用者控制對應用程式授予的存取權數量。因此,要求的範圍數可能會獲得使用者同意的可能性。

開始實作 OAuth 2.0 授權之前,建議您先找出應用程式需要存取權的範圍。

OAuth 2.0 API 範圍文件包含可用於存取 Google API 的完整範圍清單。

取得 OAuth 2.0 存取憑證

下列步驟說明您的應用程式如何與 Google 的 OAuth 2.0 伺服器互動,藉此取得使用者同意,以他們的名義執行 API 要求。您的應用程式必須取得同意聲明,才能執行 Google API 要求,並要求使用者提供授權。

步驟 1:產生程式碼驗證器和驗證方式

Google 支援程式碼交換的金鑰證明 (PKCE) 通訊協定,讓已安裝的應用程式流程更加安全。系統會為每個授權要求建立專屬程式碼驗證器,並將其轉換值 (稱為「code_challenge」) 傳送至授權伺服器,以取得授權碼。

建立程式碼驗證器

code_verifier 是一個高密碼密碼編譯字串,使用未保留的字元 [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / ~~",長度下限為 43 個字元,長度上限為 128 個字元。

程式碼驗證工具應具備充足的熵,無法猜測這個值。

建立程式碼挑戰

系統支援建立程式碼挑戰的兩種方法。

程式碼挑戰產生方法
S256 (建議選項) 程式碼驗證是程式碼驗證器的 Base64URL (不含邊框間距) 編碼 SHA256 雜湊。
code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
程式碼驗證的值與上述產生的程式碼驗證工具相同。
code_challenge = code_verifier

步驟 2:傳送要求至 Google 的 OAuth 2.0 伺服器

如要取得使用者授權,請前往 https://accounts.google.com/o/oauth2/v2/auth 向 Google 的授權伺服器傳送要求。此端點會處理主動的工作階段查詢、驗證使用者以及取得使用者同意。此端點只能透過安全資料傳輸層 (SSL) 存取,並拒絕 HTTP (非 SSL) 連線。

授權伺服器支援已安裝應用程式的下列查詢字串參數:

參數
client_id 必要

應用程式的用戶端 ID。您可以在 API Console Credentials page中找到這個值。

redirect_uri 必要

決定 Google 的授權伺服器傳送回應給應用程式的方式。安裝版應用程式有多種重新導向選項,您可以設定特定重新導向方法的授權憑證

這個值必須與您在用戶端的 API Console Credentials page中設定的 OAuth 2.0 用戶端授權重新導向 URI 完全相符。如果這個值與已獲授權的 URI 不符,您會收到 redirect_uri_mismatch 錯誤。

下表列出每個方法的適當 redirect_uri 參數值:

redirect_uri
自訂 URI 配置 com.example.app:redirect_uri_path

com.googleusercontent.apps.123:redirect_uri_path
  • com.example.app 是由您控制的網域中反向 DNS 標記法。自訂配置必須包含一個時段。
  • com.googleusercontent.apps.123 是用戶端 ID 的反向 DNS 標記法。
  • redirect_uri_path 是選用的路徑元件,例如 /oauth2redirect。請注意,路徑的開頭必須是單一斜線,與一般的 HTTP 網址不同。
回送 IP 位址 http://127.0.0.1:porthttp://[::1]:port

請查詢您的平台,取得相關的回送 IP 位址,並在隨機可用的通訊埠上啟動 HTTP 事件監聽器。將 port 替換為應用程式實際監聽的通訊埠編號。

請注意,行動應用程式上的回送 IP 位址重新導向選項支援 已不適用

response_type 必要

決定 Google OAuth 2.0 端點是否傳回授權碼。

將已安裝應用程式的參數值設為 code

scope 必要

以空格分隔的範圍清單,可用來識別應用程式可代表使用者能存取的資源。這些值會告知 Google 向使用者顯示的同意畫面。

範圍可讓應用程式僅要求所需資源的存取權,同時讓使用者控制對應用程式授予的存取權數量。因此,要求的範圍數以及取得使用者同意聲明的可能性之間存在反向關係。

code_challenge 建議使用

指定編碼的 code_verifier,在授權程式碼交換期間將用來當做伺服器端驗證。詳情請參閱上方的建立程式碼驗證一節。

code_challenge_method 建議使用

指定用來對 code_verifier 進行授權交換過程中所用的 code_verifier 編碼的方法。這個參數必須與上述的 code_challenge 參數搭配使用。如果要求中包含 code_challenge,則 code_challenge_method 的值預設為 plain。這個參數僅支援 S256plain 值。

state 建議使用

指定應用程式用來維持授權要求與授權伺服器回應之間狀態的任何字串值。在使用者同意或拒絕應用程式存取要求之後,伺服器會傳回您在 redirect_uri 網址片段 ID (#) 中,以 name=value 組合形式傳送的確切值。

您可以將這個參數用於多種用途,例如將使用者導向應用程式中的正確資源、傳送 Nonce 及減少跨網站偽造要求。由於您可以猜測 redirect_uri,因此使用 state 值可能會提高傳入要求是驗證要求產生的結果。如果您產生隨機字串或對 Cookie 的雜湊或其他擷取用戶端狀態的值,您可以驗證回應,進一步確保要求和回應來自同一個瀏覽器,以提供防範跨網站要求偽造的攻擊。如需如何建立及確認 state 權杖的範例,請參閱 OpenID Connect 說明文件。

login_hint 選填

如果您的應用程式知道要驗證哪些使用者,便能使用這個參數向 Google 驗證伺服器提供提示。伺服器會使用提示表單中的電子郵件欄位預先填入,或選取適當的多重登入工作階段,藉此簡化登入流程。

將參數值設為電子郵件地址或 sub ID,相當於使用者的 Google ID。

授權網址範例

下方分頁標籤中列出不同重新導向 URI 選項的授權網址範例。

除了 redirect_uri 參數的值之外,網址完全相同。網址也包含必要的 response_typeclient_id 參數,以及選用的 state 參數。每個網址都包含換行符號,並方便閱讀。

自訂 URI 配置

https://accounts.google.com/o/oauth2/v2/auth?
 scope=email%20profile&
 response_type=code&
 state=security_token%3D138r5719ru3e1%26url%3Dhttps%3A%2F%2Foauth2.example.com%2Ftoken&
 redirect_uri=com.example.app%3A/oauth2redirect&
 client_id=client_id

回送 IP 位址

https://accounts.google.com/o/oauth2/v2/auth?
 scope=email%20profile&
 response_type=code&
 state=security_token%3D138r5719ru3e1%26url%3Dhttps%3A%2F%2Foauth2.example.com%2Ftoken&
 redirect_uri=http%3A//127.0.0.1%3A9004&
 client_id=client_id

步驟 3:Google 提示使用者提供同意聲明

在這個步驟中,使用者可以決定是否要授予應用程式要求的存取權。在這個階段,Google 會顯示同意視窗,其中會顯示您的應用程式名稱,以及應用程式要求取得使用者授權憑證存取權的 Google API 服務,以及要求授予的權限範圍摘要。這樣一來,使用者便可同意授予應用程式所要求一或多個範圍的存取權,或拒絕該要求。

在此階段,應用程式會等待 Google 的 OAuth 2.0 伺服器回應指出是否已授予任何存取權限,因此不需要在這個階段採取任何行動。我們將在下文中說明該回應。

錯誤

向 Google 的 OAuth 2.0 授權端點發出的要求可能會顯示向使用者顯示的錯誤訊息,而不是預期的驗證和授權流程。以下列出常見的錯誤代碼和建議解決方案。

admin_policy_enforced

根據 Google Workspace 管理員的政策,Google 帳戶無法授權一或多個要求的範圍。請參閱 Google Workspace 管理員說明文章, 控管哪些第三方應用程式和內部應用程式可存取 Google Workspace 資料,進一步瞭解管理員如何限制所有範圍或機密與受限制範圍的存取權,直到明確獲得 OAuth 用戶端 ID 的存取權為止。

disallowed_useragent

授權端點會顯示在 Google 的 OAuth 2.0 政策不允許的嵌入式使用者代理程式中。

Android

Android 開發人員在 android.webkit.WebView 中開啟授權要求時,可能會收到這則錯誤訊息。開發人員應改用 Android 程式庫,例如 Google 登入 Android 版或 OpenID 基金會的 AppAuth for Android

當 Android 應用程式在嵌入的使用者代理程式中開啟一般網頁連結,而使用者從您的網站前往 Google 的 OAuth 2.0 授權端點時,網頁開發人員可能會遇到這個錯誤。開發人員應允許在一般預設連結處理常式 (包括 Android 應用程式連結處理常式或預設瀏覽器應用程式) 中開啟一般連結。此外,您也可以使用 Android 自訂分頁資料庫。

iOS

iOS 和 macOS 開發人員在 WKWebView 中開啟授權要求時,可能會遇到這個錯誤。開發人員應改用 iOS 程式庫,例如 iOS 適用的 Google 登入或 OpenID Foundation 的 iOS 專用 AppAuth

當 iOS 或 macOS 應用程式在嵌入的使用者代理程式中開啟一般網頁連結,而使用者前往您網站的 Google 的 OAuth 2.0 授權端點時,網頁開發人員可能會遇到這個錯誤。開發人員應允許在作業系統的預設連結處理常式 (包括通用連結 處理常式或預設瀏覽器應用程式) 中開啟一般連結。 SFSafariViewController 同時也支援程式庫。

org_internal

要求中的 OAuth 用戶端 ID 屬於某項專案,會限制特定 Google Cloud 機構中存取 Google 帳戶的權限。如要進一步瞭解這個設定選項,請參閱「設定 OAuth 同意畫面」說明文章中的使用者類型一節。

invalid_grant

如果您使用的是程式碼驗證器和驗證方式code_callenge 參數無效或遺失。請確認 code_challenge 參數設定正確。

重新整理存取憑證時,憑證可能已過期或失效。 重新驗證使用者,並要求使用者同意取得新權杖。如果繼續看到這則錯誤訊息,請確認您的應用程式已正確設定,且您在要求中使用了正確的憑證和參數。否則,該使用者帳戶可能已遭刪除或停用。

redirect_uri_mismatch

授權要求中傳遞的 redirect_uri 與 OAuth 用戶端 ID 的授權重新導向 URI 不符。查看 Google API Console Credentials page中獲得授權的重新導向 URI。

傳送的 redirect_uri 可能不適用於用戶端類型。

redirect_uri 參數可能是指已不適用且不再支援的 OAuth 頻外 (OOB) 流程。請參閱遷移指南來更新整合作業。

步驟 4:處理 OAuth 2.0 伺服器回應

應用程式接收授權回應的方式取決於使用的重新導向 URI 配置。無論配置為何,回應都會包含授權碼 (code) 或錯誤 (error)。舉例來說,error=access_denied 表示使用者拒絕要求。

如果使用者授予應用程式的存取權,您就可以將授權碼轉換為存取權杖和更新權杖,如下一節所述。

步驟 5:交換更新憑證和存取權杖的授權碼

如要交換存取權杖的授權碼,請呼叫 https://oauth2.googleapis.com/token 端點並設定下列參數:

欄位
client_id 從 API Console Credentials page取得的用戶端 ID。
client_secret 從 API Console Credentials page取得的用戶端密鑰。
code 初始要求傳回的授權碼。
code_verifier 您在步驟 1 中建立的程式碼驗證器。
grant_type OAuth 2.0 規格所定義,這個欄位的值必須設為 authorization_code
redirect_uri 針對您的專案, API Console Credentials page client_id

下列程式碼片段顯示要求範例:

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=your_client_id&
client_secret=your_client_secret&
redirect_uri=http://127.0.0.1:9004&
grant_type=authorization_code

Google 回應此要求後,會傳回含有短期存取權杖和更新權杖的 JSON 物件。

回應中包含以下欄位:

欄位
access_token 應用程式傳送憑證以授權 Google API 要求。
expires_in 存取憑證的剩餘生命週期 (單位為秒)。
id_token 注意:只有在您的要求包含身分範圍 (例如 openidprofileemail) 時,系統才會傳回這個屬性。這個值是 JSON Web Token (JWT),其中包含使用者的數位簽章識別資訊。
refresh_token 可用來取得新的存取權杖的權杖。重新整理權杖的效力將直到使用者撤銷存取權為止。請注意,系統一律會為已安裝的應用程式傳回重新整理權杖。
scope access_token 授予的存取權範圍,以空格分隔且區分大小寫的字串清單表示。
token_type 傳回的權杖類型。目前,這個欄位的值一律會設為 Bearer

下列程式碼片段顯示回應範例:

{
  "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in": 3920,
  "token_type": "Bearer",
  "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
  "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}

呼叫 Google API

應用程式取得存取權杖後,如果 API 要求存取權範圍,您就可使用該權杖代表指定使用者帳戶呼叫 Google API。方法是在向 API 發出的要求中加入存取權杖,方法是加入 access_token 查詢參數或 Authorization HTTP 標頭 Bearer 的值。請盡可能使用 HTTP 標頭,因為查詢字串經常出現在伺服器記錄中。在多數情況下,您可以使用用戶端程式庫來設定對 Google API 的呼叫 (例如在呼叫 Drive API API 時)。

您可以前往 OAuth 2.0 Playground 試用所有 Google API 並查看其範圍。

HTTP GET 範例

使用 Authorization: Bearer HTTP 標頭呼叫 drive.files 端點 (Drive Files API) 可能如下所示。請注意,您必須指定自己的存取憑證:

GET /drive/v2/files HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer access_token

下面是針對已驗證的使用者,使用 access_token 查詢字串參數呼叫同一個 API:

GET https://www.googleapis.com/drive/v2/files?access_token=access_token

curl 範例

您可以使用 curl 指令列應用程式來測試這些指令。以下是使用 HTTP 標頭選項 (建議) 的範例:

curl -H "Authorization: Bearer access_token" https://www.googleapis.com/drive/v2/files

或者,您也可以選用查詢字串參數選項:

curl https://www.googleapis.com/drive/v2/files?access_token=access_token

重新整理存取憑證

存取憑證經常失效,且會成為相關 API 要求的無效憑證。如果您要求取得與憑證相關的範圍的離線存取權,可以不先提示使用者授予權限 (包括使用者不存在時)。

如要重新整理存取憑證,您的應用程式會將 HTTPS POST 要求傳送至 Google 的授權伺服器 (https://oauth2.googleapis.com/token),其中包含下列參數:

欄位
client_id API Console取得的用戶端 ID。
client_secret API Console取得的用戶端密鑰。(client_secret 不適用於註冊為 Android、iOS 或 Chrome 應用程式的用戶端要求)。
grant_type OAuth 2.0 規格定義,這個欄位的值必須設為 refresh_token
refresh_token 從授權碼交換所傳回的更新憑證。

下列程式碼片段顯示要求範例:

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

client_id=your_client_id&
client_secret=your_client_secret&
refresh_token=refresh_token&
grant_type=refresh_token

只要使用者尚未撤銷已授予應用程式的存取權,權杖伺服器會傳回含有新存取憑證的 JSON 物件。下列程式碼片段顯示回應範例:

{
  "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in": 3920,
  "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
  "token_type": "Bearer"
}

請注意,要核發的更新憑證有數量限制;每個用戶端/使用者組合各有一項限制,且所有用戶端對每位使用者都各有一項限制。請將更新憑證儲存在長期儲存空間中,只要憑證依然有效,就能繼續使用。如果您的應用程式要求過多的更新憑證,可能會達到這些限制,在這種情況下,舊有的更新憑證將會停止運作。

撤銷憑證

在某些情況下,使用者可能會想撤銷先前授予應用程式的存取權。使用者可以前往 帳戶設定撤銷存取權。詳情請參閱「具有帳戶存取權的第三方網站和應用程式」一文中的「移除網站或應用程式存取權」一節。

此外,應用程式也可以以程式輔助的方式撤銷對應用程式的存取權。如果使用者取消訂閱、移除應用程式或應用程式所需的 API 資源有大幅變動的情況,程式輔助撤銷就相當重要。換句話說,移除程序的一部分可能包含 API 要求,以確保先前授予應用程式的權限已移除。

如要透過程式撤銷憑證,應用程式會向 https://oauth2.googleapis.com/revoke 發出要求,並將憑證做為參數:

curl -d -X -POST --header "Content-type:application/x-www-form-urlencoded" \
        https://oauth2.googleapis.com/revoke?token={token}

這個權杖可以是存取權杖或更新權杖。如果符記是存取權杖,且具有對應的重新整理權杖,則系統會一併撤銷更新權杖。

如果撤銷作業成功,則回應的 HTTP 狀態碼為 200。如果是錯誤條件,系統會傳回 HTTP 狀態碼 400 以及錯誤代碼。

其他資訊

IETF Best Current Practice OAuth 2.0 for native Apps (適用於原生應用程式的 OAuth 2.0) 建立了本文所述的許多最佳做法。