本文說明如何實作 OAuth 2.0 授權,透過在電視、遊戲主機和印表機等裝置上執行的應用程式存取 Google API。具體來說,這個流程適用於無法存取瀏覽器或輸入功能有限的裝置。
OAuth 2.0 可讓使用者與應用程式共用特定資料,同時保有使用者名稱、密碼和其他資訊的私密性。 舉例來說,電視應用程式可使用 OAuth 2.0 取得權限,以選取儲存在 Google 雲端硬碟中的檔案。
由於使用這個流程的應用程式是發布至個別裝置,因此系統會假設應用程式無法保存密鑰。當使用者位於應用程式期間,或在背景執行時,他們還是可以存取 Google API。
替代方案
如果您要為具有瀏覽器和完整輸入功能的平台 (例如 Android、iOS、macOS、Linux 或 Windows (包括通用 Windows 平台)) 編寫應用程式,請使用行動裝置和電腦應用程式適用的 OAuth 2.0 流程。(即使應用程式是沒有圖形介面的指令列工具,仍建議您採用該流程)。
如果您只想透過 Google 帳戶登入使用者,並使用 JWT ID 權杖取得基本使用者個人資料,請參閱在電視和有限輸入裝置中登入相關說明。
必要條件
為專案啟用 API
呼叫 Google API 的所有應用程式都必須在 API Console中啟用這些 API。
如要在專案中啟用 API,請按照下列步驟操作:
- Open the API Library (位於 Google API Console中)。
- If prompted, select a project, or create a new one.
- API Library 會列出所有可用的 API,並按照產品系列及熱門程度分組。如果清單中未顯示您想啟用的 API,請使用搜尋功能找到該 API,或在所屬產品系列中按一下「查看全部」。
- 選取要啟用的 API,然後按一下「Enable」按鈕。
- If prompted, enable billing.
- If prompted, read and accept the API's Terms of Service.
建立授權憑證
凡是使用 OAuth 2.0 存取 Google API 的應用程式,都必須具備授權憑證,用來向 Google 的 OAuth 2.0 伺服器識別應用程式。下列步驟說明如何為專案建立憑證。接著,您的應用程式就能使用憑證存取您為該專案啟用的 API。
- Go to the Credentials page.
- 按一下 [Create credentials] (建立憑證) > [OAuth client ID] (OAuth 用戶端 ID)。
- 選取「電視和受限的輸入裝置」應用程式類型。
- 為 OAuth 2.0 用戶端命名,然後按一下「建立」。
識別存取權範圍
範圍可讓應用程式僅要求存取所需的資源,也能讓使用者控管自己授予應用程式的存取權量。因此,要求的範圍數量與取得使用者同意聲明的可能性之間存在反向關係。
開始實作 OAuth 2.0 授權之前,建議您先找出應用程式需要權限存取的範圍。
如要查看已安裝的應用程式或裝置,請參閱允許的範圍清單。
取得 OAuth 2.0 存取權杖
即使應用程式在輸入功能受限的裝置上運作,使用者仍須擁有輸入功能更豐富的裝置獨立存取權,才能完成這項授權流程。流程包含下列步驟:
- 應用程式傳送要求至 Google 的授權伺服器,以識別應用程式要求存取的權限範圍。
- 伺服器會以後續步驟使用多項資訊回應,例如裝置代碼和使用者代碼。
- 您會顯示使用者可在獨立裝置上輸入的資訊,為應用程式進行授權。
- 您的應用程式會開始輪詢 Google 授權伺服器,判斷使用者是否授權您的應用程式。
- 使用者切換至擁有更豐富的輸入功能的裝置、啟動網路瀏覽器並前往步驟 3 顯示的網址,並輸入步驟 3 中顯示的代碼。接著,使用者就可以授予 (或拒絕) 存取您的應用程式。
- 輪詢要求的下一個回應包含應用程式代表使用者授權要求所需的權杖。(如果使用者拒絕授予應用程式的存取權,回應中就不會包含權杖)。
下圖說明這項程序:
下列各節將詳細說明這些步驟。考量到裝置可能具備的功能和執行階段環境,本文件中的範例使用 curl
指令列公用程式。這些範例應該要能輕鬆移植到各種語言和執行階段。
步驟 1:索取裝置和使用者驗證碼
在這個步驟中,您的裝置會在 https://oauth2.googleapis.com/device/code
向 Google 的授權伺服器傳送 HTTP POST 要求,以識別您的應用程式及應用程式要代表使用者存取的存取權範圍。請使用 device_authorization_endpoint
中繼資料值,從探索文件擷取這個網址。請加入下列 HTTP 要求參數:
參數 | |
---|---|
client_id |
必填
應用程式的用戶端 ID。您可以在 API Console Credentials page中找到這個值。 |
scope |
必填
以空格分隔的範圍清單,用來識別應用程式可以代表使用者存取的資源。這些值會告知 Google 向使用者顯示的同意畫面。如要查看已安裝的應用程式或裝置,請參閱允許的範圍清單。 範圍可讓應用程式僅要求存取所需的資源,也能讓使用者控管自己授予應用程式的存取權量。因此,要求的範圍數量與取得使用者同意聲明的可能性之間存在反向關係。 |
示例
以下程式碼片段為要求範例:
POST /device/code HTTP/1.1 Host: oauth2.googleapis.com Content-Type: application/x-www-form-urlencoded client_id=client_id&scope=email%20profile
本例顯示 curl
指令來傳送相同的要求:
curl -d "client_id=client_id&scope=email%20profile" \ https://oauth2.googleapis.com/device/code
步驟 2:處理授權伺服器回應
授權伺服器會傳回下列其中一個回應:
成功回應
如果要求有效,回應就會是包含下列屬性的 JSON 物件:
屬性 | |
---|---|
device_code |
Google 專門指派的值,用於識別執行應用程式要求授權的裝置。使用者會透過其他具備更豐富的輸入功能的裝置授權該裝置。舉例來說,使用者可能會使用筆記型電腦或手機,授權在電視上執行的應用程式。在這種情況下,device_code 可用來識別電視。
這個程式碼可讓執行應用程式的裝置安全地判斷使用者是否授予或拒絕存取要求。 |
expires_in |
device_code 和 user_code 有效的時間長度 (以秒為單位)。屆時,如果使用者未完成授權流程,裝置也不再輪詢以擷取使用者決定的相關資訊,您可能需要從步驟 1 重新開始這項程序。 |
interval |
裝置每次發出輪詢要求的時間 (以秒為單位)。例如,如果值為 5 ,則裝置應每五秒鐘傳送輪詢要求至 Google 的授權伺服器。詳情請參閱步驟 3。 |
user_code |
這個值區分大小寫,用來向 Google 識別應用程式要求存取的範圍。使用者介面會指示使用者在具備更豐富的輸入功能的獨立裝置上輸入這個值。然後,Google 會在提示使用者授予應用程式存取權時,使用該值顯示正確的範圍組合。 |
verification_url |
使用者必須使用獨立裝置前往的網址,才能輸入 user_code 並授予或拒絕應用程式的存取權。您的使用者介面也會顯示這個值。 |
以下程式碼片段為回應範例:
{ "device_code": "4/4-GMMhmHCXhWEzkobqIHGG_EnNYYsAkukHspeYUk9E8", "user_code": "GQVQ-JKEC", "verification_url": "https://www.google.com/device", "expires_in": 1800, "interval": 5 }
超過配額的回應
如果裝置代碼要求超過與用戶端 ID 相關聯的配額,您會收到 403 回應,其中包含下列錯誤:
{ "error_code": "rate_limit_exceeded" }
在這種情況下,請使用輪詢策略來降低要求的比率。
步驟 3:顯示使用者程式碼
向使用者顯示步驟 2 中取得的 verification_url
和 user_code
。這兩個值可包含 US-ASCII 字元集的任何可列印字元。向使用者顯示的內容應指示使用者在另一部裝置上前往 verification_url
並輸入 user_code
。
設計使用者介面 (UI) 時,請注意下列規則:
user_code
user_code
必須顯示在可處理 15 個「W」大小字元的欄位。也就是說,如果您可以正確顯示程式碼WWWWWWWWWWWWWWW
,表示使用者介面有效;因此,建議您在測試user_code
在 UI 中的顯示方式時,使用該字串值。user_code
會區分大小寫,且不得經過任何修改,例如變更大小寫或插入其他格式設定字元。
verification_url
- 顯示
verification_url
的空間必須夠寬,才能處理長度為 40 個字元的網址字串。 - 除非是選擇性移除顯示配置,否則請勿以任何方式修改
verification_url
。如果您基於顯示原因,打算移除網址中的配置 (例如https://
),請確保應用程式可以同時處理http
和https
變化版本。
- 顯示
步驟 4:輪詢 Google 的授權伺服器
由於使用者會使用另一部裝置前往 verification_url
,並授予 (或拒絕) 存取權,因此當使用者回應存取要求時,系統不會自動通知提出要求的裝置。因此,要求的裝置必須輪詢 Google 的授權伺服器,判斷使用者何時回應要求。
提出要求的裝置應繼續傳送輪詢要求,直到收到回應指出使用者已回應存取要求,或直到你在
步驟 2 中取得的 device_code
和 user_code
過期為止。步驟 2 中傳回的 interval
指定兩次要求之間等待的時間 (以秒為單位)。
要輪詢的端點網址為 https://oauth2.googleapis.com/token
。輪詢要求包含下列參數:
參數 | |
---|---|
client_id |
應用程式的用戶端 ID。您可以在 API Console Credentials page中找到這個值。 |
client_secret |
所提供 client_id 的用戶端密鑰。您可以在 API Console
Credentials page中找到這個值。 |
device_code |
授權伺服器在步驟 2 中傳回的 device_code 。 |
grant_type |
將這個值設為 urn:ietf:params:oauth:grant-type:device_code 。 |
示例
以下程式碼片段為要求範例:
POST /token HTTP/1.1 Host: oauth2.googleapis.com Content-Type: application/x-www-form-urlencoded client_id=client_id& client_secret=client_secret& device_code=device_code& grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code
本例顯示 curl
指令來傳送相同的要求:
curl -d "client_id=client_id&client_secret=client_secret& \ device_code=device_code& \ grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code" \ -H "Content-Type: application/x-www-form-urlencoded" \ https://oauth2.googleapis.com/token
步驟 5:使用者回應存取要求
下圖顯示使用者前往步驟 3 顯示的 verification_url
時看到的網頁:
進入 user_code
後,如果尚未登入 Google,使用者會看到同意畫面,如下所示:
步驟 6:處理輪詢要求的回應
Google 的授權伺服器會使用下列其中一個回應回應每個輪詢要求:
已獲得存取權
如果使用者已授予裝置存取權 (在同意畫面中按一下 Allow
),回應就會包含存取權杖和更新權杖。權杖可讓裝置代表使用者存取 Google API。(回應中的 scope
屬性會決定裝置可以存取的 API)。
在這種情況下,API 回應包含下列欄位:
欄位 | |
---|---|
access_token |
應用程式傳送的憑證以授權 Google API 要求。 |
expires_in |
存取權杖的剩餘生命週期 (以秒為單位)。 |
refresh_token |
可用來取得新存取權杖的權杖。重新整理權杖的效力直到使用者撤銷存取權為止。請注意,系統一律會為裝置傳回更新權杖。 |
scope |
access_token 授予的存取權範圍,以以空格分隔且區分大小寫的字串清單表示。 |
token_type |
傳回的權杖類型。目前,這個欄位的值一律會設為 Bearer 。 |
以下程式碼片段為回應範例:
{ "access_token": "1/fFAGRNJru1FTz70BzhT3Zg", "expires_in": 3920, "scope": "openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email", "token_type": "Bearer", "refresh_token": "1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI" }
存取權杖的生命週期有限。如果應用程式需要長時間存取 API,即可使用更新權杖來取得新的存取權杖。如果您的應用程式需要這種存取權,則應儲存更新權杖供日後使用。
存取遭拒
如果使用者拒絕授予裝置存取權,伺服器回應就會提供 403
HTTP 回應狀態碼 (Forbidden
)。回應會包含下列錯誤:
{ "error": "access_denied", "error_description": "Forbidden" }
待授權
如果使用者尚未完成授權流程,伺服器會傳回 428
HTTP 回應狀態碼 (Precondition Required
)。回應會包含下列錯誤:
{ "error": "authorization_pending", "error_description": "Precondition Required" }
輪詢頻率過高
如果裝置太常傳送輪詢要求,伺服器會傳回 403
HTTP 回應狀態碼 (Forbidden
)。回應會包含下列錯誤:
{ "error": "slow_down", "error_description": "Forbidden" }
其他錯誤
如果輪詢要求缺少任何必要參數或參數值不正確,授權伺服器也會傳回錯誤。這些要求通常包含 400
(Bad Request
) 或 401
(Unauthorized
) HTTP 回應狀態碼。這類錯誤包括:
錯誤 | HTTP 狀態碼 | 說明 |
---|---|---|
admin_policy_enforced |
400 |
Google 帳戶無法依據 Google Workspace 管理員的政策,授權給一或多個要求的範圍。請參閱 Google Workspace 管理員說明文章「控管哪些第三方應用程式和內部應用程式可存取 Google Workspace 資料」,進一步瞭解管理員在未明確授予 OAuth 用戶端 ID 存取權前可能會如何限制範圍的存取權。 |
invalid_client |
401 |
找不到 OAuth 用戶端。舉例來說,如果 OAuth 用戶端類型不正確。確認用戶端 ID 的應用程式類型已設為「電視和有限輸入裝置」。 |
invalid_grant |
400 |
code 參數值無效、已聲明擁有權或無法剖析。 |
unsupported_grant_type |
400 |
grant_type 參數值無效。 |
org_internal |
403 |
要求中的 OAuth 用戶端 ID 屬於某項專案的一部分,其作用是限制特定 Google Cloud 機構的 Google 帳戶存取權。確認 OAuth 應用程式的使用者類型設定。 |
呼叫 Google API
應用程式取得存取權杖後,如果 API 所需的存取權範圍已獲準,您可以使用權杖,代表指定使用者帳戶呼叫 Google API。方法是在傳送至 API 的要求中加入存取權杖,方法是加入 access_token
查詢參數或 Authorization
HTTP 標頭 Bearer
值。建議您盡可能使用 HTTP 標頭,因為查詢字串通常會顯示在伺服器記錄檔中。在多數情況下,您可以使用用戶端程式庫來設定對 Google API 的呼叫 (例如呼叫 Drive Files API 時)。
您可以試用所有 Google API,並前往 OAuth 2.0 Playground 查看其範圍。
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取得的用戶端密鑰。 |
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
,以及錯誤代碼。
允許的範圍
裝置的 OAuth 2.0 流程僅支援下列範圍:
OpenID Connect、 Google 登入
email
openid
profile
Drive API
https://www.googleapis.com/auth/drive.appdata
https://www.googleapis.com/auth/drive.file
YouTube API
https://www.googleapis.com/auth/youtube
https://www.googleapis.com/auth/youtube.readonly