電視和限縮裝置應用程式專用的 OAuth 2.0

本文說明如何實作 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:

  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. 選取 [電視和受限輸入裝置] 應用程式類型。
  4. 為您的 OAuth 2.0 用戶端命名,然後按一下 [Create] (建立)

識別存取權範圍

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

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

請參閱允許範圍清單,瞭解已安裝的應用程式或裝置。

取得 OAuth 2.0 存取憑證

即使應用程式在執行輸入功能受限的裝置上執行,使用者還是必須能存取具備較高輸入功能的裝置,以便完成此授權流程。流程如下:

  1. 應用程式會將要求傳送至 Google 的授權伺服器,該伺服器會識別應用程式要求存取的範圍。
  2. 伺服器會在回應中使用後續步驟資訊,例如裝置代碼和使用者代碼回應。
  3. 您要在其他裝置上輸入資訊,以供使用者在其他應用程式中授權。
  4. 您的應用程式會開始輪詢 Google 的授權伺服器,以判斷使用者是否授權您的應用程式。
  5. 使用者切換至輸入功能更豐富的裝置、啟動網路瀏覽器、瀏覽至步驟 3 中顯示的網址,然後輸入步驟 3 中顯示的代碼。接著,使用者就能授予或拒絕應用程式的存取權。
  6. 輪詢回應的下一個回應,包含應用程式代表使用者授權要求所需的符記。(如果使用者拒絕存取您的應用程式,回應則不會包含憑證)。

下圖說明這項程序:

使用者在其他裝置上登入瀏覽器

以下各節詳細說明瞭這些步驟。考量到裝置可能具備的功能範圍和執行階段環境,本文中的範例使用 curl 指令列公用程式。這些範例應可輕易移往各種語言和執行階段。

步驟 1:要求裝置和使用者代碼

在這個步驟中,您的裝置會將 HTTP POST 要求傳送至 https://oauth2.googleapis.com/device/code 的授權伺服器,此伺服器用於識別您的應用程式,以及應用程式想要代表使用者存取的存取權範圍。您應該使用 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=

此範例顯示傳送相同要求的 curl 指令:

curl -d "client_id=client_id&scope=" \
     https://oauth2.googleapis.com/device/code

步驟 2:處理授權伺服器回應

授權伺服器會傳回下列其中一項回應:

成功回應

如果要求有效,您的回應將會是包含以下屬性的 JSON 物件:

屬性
device_code 這個唯一值是由 Google 指派,用於識別執行授權要求的裝置。使用者將授權其他裝置,以享有更豐富的輸入功能。舉例來說,使用者可能會使用筆記型電腦或手機,來授權電視上執行的應用程式。在此情況下,device_code 可識別電視。

這個程式碼可讓執行應用程式的裝置安全地判斷使用者是否授予或拒絕存取權。

expires_in device_codeuser_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_urluser_code。這兩個值可包含 US-ASCII 字元集中的任何可列印字元。您向使用者顯示的內容應引導使用者在其他裝置上前往 verification_url,然後輸入 user_code

設計使用者介面 (UI) 時,請將下列規則納入考量:

  • user_code
    • user_code 必須顯示在能夠處理 15 個「W」大小字元的欄位。換句話說,如果您能夠正確顯示程式碼 WWWWWWWWWWWWWWW,您的 UI 就有效,我們建議您在測試 user_code 在使用者介面中的顯示方式時,使用該字串值。
    • user_code 須區分大小寫,而且不應以任何方式修改,例如變更大小寫或插入其他格式設定字元。
  • verification_url
    • 顯示 verification_url 的寬度必須夠寬,以處理長度為 40 個字元的網址字串。
    • 您不得以任何方式修改 verification_url,但可以選擇性地移除顯示配置。如果您計劃出於顯示原因而打算刪除網址中的配置 (例如 https://),請確保您的應用程式可以處理 httphttps 的變體。

步驟 4:輪詢 Google 授權伺服器

由於使用者會使用其他裝置前往 verification_url 並授予 (或拒絕) 存取權,因此當使用者回應存取要求時,系統不會自動通知要求的裝置。因此,要求裝置必須輪詢 Google 授權伺服器,以判斷使用者回應要求的時間。

請求裝置應持續傳送輪詢要求,直到收到回應為止,指出使用者已回應存取要求,或是直到 步驟 2 中取得的 device_codeuser_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 授權伺服器傳回的device_code (步驟 2)。
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 Workspace 管理員的政策,此 Google 帳戶無法授權一或多個要求的範圍。請參閱 Google Workspace 管理員說明文章,控管哪些第三方應用程式和內部應用程式可存取 Google Workspace 資料,進一步瞭解管理員如何限制存取權,直到明確授予您的 OAuth 用戶端 ID 存取權為止。
invalid_client 401

找不到 OAuth 用戶端。舉例來說,如果 client_id 參數值無效,就會發生這個錯誤。

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 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取得的用戶端密鑰。
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 ConnectGoogle 登入

  • 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