Google OAuth 2.0 系統支援伺服器對伺服器的互動,例如網路應用程式與 Google 服務之間的互動。在本情境中,您需要使用服務帳戶,該帳戶屬於您的應用程式,而不是個別使用者。您的應用程式代表服務帳戶呼叫 Google API,因此不會直接涉及使用者。這種情況有時稱為「雙足式 OAuth」或「2LO」。(「三足式 OAuth」一詞是指應用程式代表使用者呼叫 Google API 的情境,有時則是需要使用者同意)。
一般而言,如果應用程式使用 Google API 以自己的資料 (而非使用者資料) 處理應用程式,則應用程式會使用服務帳戶。舉例來說,如果應用程式使用 Google Cloud Datastore 來保存資料,就會使用服務帳戶來驗證對 Google Cloud Datastore API 的呼叫。
Google Workspace 網域管理員也可以授予全網域授權,藉此代表網域中使用者存取使用者資料。
本文件說明如何使用 Google API 用戶端程式庫 (建議選項) 或 HTTP 來完成伺服器對伺服器 OAuth 2.0 流程。
總覽
如要支援伺服器對伺服器的互動,請先在 中為您的專案建立服務帳戶。如要存取 Google Workspace 使用者的使用者資料,請將全網域的存取權委派給服務帳戶。
然後,應用程式準備使用服務帳戶的憑證向 OAuth 2.0 驗證伺服器要求存取權杖,來準備已授權的 API 呼叫。
最後,您的應用程式可以使用存取權杖呼叫 Google API。
建立服務帳戶
服務帳戶的憑證包含產生的唯一電子郵件地址,以及至少一組公開/私密金鑰組。如果啟用了全網域委派,則服務帳戶憑證也屬於服務帳戶憑證的一部分。
如果您的應用程式在 Google App Engine 上執行,則系統會在建立專案時自動設定服務帳戶。
如果您的應用程式是在 Google Compute Engine 上執行,系統也會在建立專案時自動設定服務帳戶,但在建立 Google Compute Engine 執行個體時,您必須指定應用程式需要存取的範圍。詳情請參閱準備執行個體以使用服務帳戶。
如果您的應用程式無法在 Google App Engine 或 Google Compute Engine 上執行,您必須在 中取得這些憑證。如要產生服務帳戶憑證,或查看您已產生的公開憑證,請按照下列指示操作:
First, create a service account:
- Open the Service accounts page.
- If prompted, select a project, or create a new one.
- Click Create service account.
- Under Service account details, type a name, ID, and description for the service account, then click Create and continue.
- Optional: Under Grant this service account access to project, select the IAM roles to grant to the service account.
- Click Continue.
- Optional: Under Grant users access to this service account, add the users or groups that are allowed to use and manage the service account.
- Click Done.
Next, create a service account key:
- Click the email address for the service account you created.
- Click the Keys tab.
- In the Add key drop-down list, select Create new key.
- Click Create.
Your new public/private key pair is generated and downloaded to your machine; it serves as the only copy of the private key. You are responsible for storing it securely. If you lose this key pair, you will need to generate a new one.
您隨時可以返回 API Console 查看電子郵件地址、公開金鑰指紋和其他資訊,或產生額外的公開/私密金鑰組。如要進一步瞭解 API Console中的服務帳戶憑證,請參閱 API Console說明檔案中的服務帳戶。
記下服務帳戶的電子郵件地址,並將服務帳戶的私密金鑰檔案儲存在應用程式可存取的位置。您的應用程式需要這類金鑰,才能進行已授權的 API 呼叫。
將全網域授權委派給服務帳戶
如果您有 Google Workspace 帳戶,機構管理員便可授權應用程式代表 Google Workspace 網域中的使用者存取使用者資料。例如,如果應用程式使用 Google Calendar API,在 Google Workspace 網域中所有使用者的日曆中新增活動,就可以使用服務帳戶來代表使用者存取 Google Calendar API。授權服務帳戶代表網域使用者存取資料,有時也稱為「將全網域授權委派給服務帳戶」。
如要將全網域授權委派給服務帳戶,該 Google Workspace 網域的超級管理員必須完成下列步驟:
- 在 Google Workspace 網域的 管理控制台中,依序前往 [主選單] > [安全性] > [存取權與資料控管] > [API 控制項]。
- 在 [全網域委派] 窗格中,選取 [管理全網域委派設定]。
- 按一下 [Add new] (新增)。
- 在 [用戶端 ID] 欄位中,輸入服務帳戶的用戶端 ID。您可以在 Service accounts page中找到服務帳戶的用戶端 ID。
- 在 [OAuth 範圍 (以半形逗號分隔)] 欄位中,輸入應用程式應獲得存取權的範圍清單。舉例來說,如果您的應用程式需要全網域的完整 Google Drive API 和 Google Calendar API 存取權,請輸入:https://www.googleapis.com/auth/drive, https://www.googleapis.com/auth/calendar。
- 按一下 [授權]。
您的應用程式現在有權以 API 呼叫您網域中的使用者 (即「模擬」使用者)。當您準備發出已授權的 API 呼叫時,您必須指定要模擬的使用者。
準備發出已獲授權的 API 呼叫
Java
從 API Console取得用戶端電子郵件地址和私密金鑰後,請使用 Java 適用的 Google API 用戶端程式庫,透過服務帳戶的憑證和應用程式需要存取的範圍,建立 GoogleCredential
物件。例如:
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; import com.google.api.services.sqladmin.SQLAdminScopes; // ... GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json")) .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN));
如果您是在 Google Cloud Platform 上開發應用程式,可以改用應用程式預設憑證,藉此簡化這項程序。
委派全網域授權
如果您擁有全服務帳戶的服務帳戶存取權,並想模擬使用者帳戶,請使用 GoogleCredential
物件的 createDelegated
方法指定使用者的電子郵件地址。例如:
GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json")) .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN)) .createDelegated("user@example.com");
在應用程式中使用 GoogleCredential
物件呼叫 Google API。
Python
從 API Console取得用戶端電子郵件地址和私密金鑰後,請使用 Python 適用的 Google API 用戶端程式庫來完成下列步驟:
- 從服務帳戶的憑證,以及應用程式需要存取的範圍建立
Credentials
物件。例如:from google.oauth2 import service_account SCOPES = ['https://www.googleapis.com/auth/sqlservice.admin'] SERVICE_ACCOUNT_FILE = '/path/to/service.json' credentials = service_account.Credentials.from_service_account_file( SERVICE_ACCOUNT_FILE, scopes=SCOPES)
如果您是在 Google Cloud Platform 上開發應用程式,可以改用應用程式預設憑證,藉此簡化這項程序。
- 委派全網域授權
如果您擁有全服務帳戶的服務帳戶存取權,並想模擬使用者帳戶,請使用現有
ServiceAccountCredentials
物件的with_subject
方法。例如:delegated_credentials = credentials.with_subject('user@example.org')
使用「憑證」物件,在應用程式中呼叫 Google API。
HTTP/REST
從 API Console取得用戶端 ID 和私密金鑰後,您的應用程式需要完成下列步驟:
- 建立 JSON Web Token (JWT、發音、「jot」),其中包含標頭、版權聲明集和簽名。
- 透過 Google OAuth 2.0 授權伺服器要求存取權杖。
- 處理授權伺服器傳回的 JSON 回應。
以下各節將說明如何完成這些步驟。
如果回應中包含存取權杖,您可以使用存取權杖呼叫 Google API。(如果回應不含存取權杖,您的 JWT 和權杖要求可能未正確設定,或是服務帳戶可能無法存取要求的範圍。
存取憑證到期時,應用程式會產生另一個 JWT 並簽署,然後要求另一組存取權杖。

本節的其餘部分將說明建立 JWT、簽署 JWT、形成存取權杖要求,以及處理回應的具體細節。
建立 JWT
JWT 是由三個部分組成:標頭、版權聲明集和簽名。標頭和版權聲明集是 JSON 物件。這些 JSON 物件會序列化為 UTF-8 位元組,然後使用 Base64url 編碼進行編碼。這種編碼方式能有效因應編碼變更造成的重複變更。標題、版權聲明集和簽名會與一個半形句號 (.
) 字元串連在一起。
JWT 的撰寫方式如下:
{Base64url encoded header}.{Base64url encoded claim set}.{Base64url encoded signature}
簽名的基本字串如下:
{Base64url encoded header}.{Base64url encoded claim set}
建立 JWT 標頭
標頭是由兩個欄位組成,代表簽署演算法和斷言格式。這兩個欄位皆為必填,且每個欄位都只有一個值。隨著其他演算法和格式導入,這個標頭也會隨之改變。
服務帳戶必須採用 RSA SHA-256 演算法和 JWT 憑證格式。因此,標頭的 JSON 表示法如下:
{"alg":"RS256","typ":"JWT"}
其 Base64url 表示法如下:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9
建立 JWT 聲明集
JWT 憑證集包含 JWT 的相關資訊,包括要求的權限 (範圍)、憑證的目標、核發者、核發憑證的時間,以及憑證的生命週期。大部分的欄位皆為必填欄位。與 JWT 標頭一樣,JWT 憑證集是 JSON 物件,用於計算簽名。
必要聲明
要求 JWT 憑證集的必要版權聲明如下所示。因此可能會按照聲明組合中的任何順序顯示。
名稱 | 說明 |
---|---|
iss |
服務帳戶的電子郵件地址。 |
scope |
應用程式要求的權限,並以空格分隔。 |
aud |
斷言目標的描述元。提出存取權杖要求時,這個值一律為 https://oauth2.googleapis.com/token 。 |
exp |
斷言的到期時間,指定為自世界標準時間 1970 年 1 月 1 日 00:00:00 起的秒數。這個值的核發時間上限為 1 小時。 |
iat |
斷言的時間,指定為自 1970 年 1 月 1 日 00:00:00 UTC 起的秒數。 |
以下是 JWT 聲明集中的必填欄位的 JSON 表示法:
{ "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com", "scope": "https://www.googleapis.com/auth/devstorage.read_only", "aud": "https://oauth2.googleapis.com/token", "exp": 1328554385, "iat": 1328550785 }
其他聲明
在部分企業案例中,應用程式可以使用全網域委派功能,代表機構中的特定使用者執行動作。應用程式必須取得這類使用者的授權,才能授予這類模擬權限,且這類權限通常是由超級管理員處理。詳情請參閱使用全網域委派功能控管 API 存取權。
如要取得會授予應用程式委派資源存取權的存取憑證,請在 JWT 聲明中加入使用者的電子郵件地址,並將值設為 sub
欄位的值。
名稱 | 說明 |
---|---|
sub |
應用程式要求委派存取權的使用者電子郵件地址。 |
如果應用程式沒有模擬使用者的權限,則包含 sub
欄位的存取權杖要求回應會是錯誤。
以下是包含 sub
欄位的 JWT 憑證附加資訊範例:
{ "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com", "sub": "some.user@example.com", "scope": "https://www.googleapis.com/auth/prediction", "aud": "https://oauth2.googleapis.com/token", "exp": 1328554385, "iat": 1328550785 }
對 JWT 聲明集進行編碼
與 JWT 標頭一樣,JWT 憑證集應序列化為 UTF-8 和 Base64url 安全編碼。以下是 JWT 憑證集的 JSON 表示法範例:
{ "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com", "scope": "https://www.googleapis.com/auth/prediction", "aud": "https://oauth2.googleapis.com/token", "exp": 1328554385, "iat": 1328550785 }
計算簽名
JSON Web Signature (JWS) 是一種規範,用於為 JWT 產生簽章的機制。簽名的輸入內容是下列內容的位元組陣列:
{Base64url encoded header}.{Base64url encoded claim set}
計算簽名時,必須使用 JWT 標頭中的簽署演算法。Google OAuth 2.0 授權伺服器僅支援 SHA-256 雜湊演算法的 RSA。這在 JWT 標頭的 alg
欄位中會表示為 RS256
。
使用 SHA256withRSA (也稱為 RSASSA-PKCS1-V1_5-SIGN,使用 SHA-256 雜湊函式) 簽署輸入的 UTF-8 表示法,並使用從 Google API Console取得的私密金鑰。輸出結果是位元組陣列。
簽章也必須採用 Base64url 編碼。標題、版權聲明集和簽名會與句號 (.
) 字元串連在一起。結果就是 JWT。範例如下:
{Base64url encoded header}. {Base64url encoded claim set}. {Base64url encoded signature}
以下是採用 Base64url 編碼之前的 JWT 範例:
{"alg":"RS256","typ":"JWT"}. { "iss":"761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com", "scope":"https://www.googleapis.com/auth/prediction", "aud":"https://oauth2.googleapis.com/token", "exp":1328554385, "iat":1328550785 }. [signature bytes]
以下是 已簽署並可準備傳輸的 JWT 範例:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL29hdXRoMi92NC90b2tlbiIsImV4cCI6MTMyODU1NDM4NSwiaWF0IjoxMzI4NTUwNzg1fQ.UFUt59SUM2_AW4cRU8Y0BYVQsNTo4n7AFsNrqOpYiICDu37vVt-tw38UKzjmUKtcRsLLjrR3gFW3dNDMx_pL9DVjgVHDdYirtrCekUHOYoa1CMR66nxep5q5cBQ4y4u2kIgSvChCTc9pmLLNoIem-ruCecAJYgI9Ks7pTnW1gkOKs0x3YpiLpzplVHAkkHztaXiJdtpBcY1OXyo6jTQCa3Lk2Q3va1dPkh_d--GU2M5flgd8xNBPYw4vxyt0mP59XZlHMpztZt0soSgObf7G3GXArreF_6tpbFsS3z2t5zkEiHuWJXpzcYr5zWTRPDEHsejeBSG8EgpLDce2380ROQ
提出存取權杖要求
應用程式產生已簽署的 JWT 後,即可使用該金鑰要求存取權杖。此存取權杖要求是 HTTPS POST
要求,且主體為網址編碼。網址如下所示:
https://oauth2.googleapis.com/token
HTTPS POST
要求中必須使用下列參數:
名稱 | 說明 |
---|---|
grant_type |
使用下列字串,視需要對網址進行編碼:urn:ietf:params:oauth:grant-type:jwt-bearer |
assertion |
JWT,包括簽名。 |
以下是存取權杖要求中使用的 HTTPS POST
要求原始傾印:
POST /token HTTP/1.1 Host: oauth2.googleapis.com Content-Type: application/x-www-form-urlencoded grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU3MzM4MSwiaWF0IjoxMzI4NTY5NzgxfQ.ixOUGehweEVX_UKXv5BbbwVEdcz6AYS-6uQV6fGorGKrHf3LIJnyREw9evE-gs2bmMaQI5_UbabvI4k-mQE4kBqtmSpTzxYBL1TCd7Kv5nTZoUC1CmwmWCFqT9RE6D7XSgPUh_jF1qskLa2w0rxMSjwruNKbysgRNctZPln7cqQ
以下是使用 curl
的同一個要求:
curl -d 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU3MzM4MSwiaWF0IjoxMzI4NTY5NzgxfQ.RZVpzWygMLuL-n3GwjW1_yhQhrqDacyvaXkuf8HcJl8EtXYjGjMaW5oiM5cgAaIorrqgYlp4DPF_GuncFqg9uDZrx7pMmCZ_yHfxhSCXru3gbXrZvAIicNQZMFxrEEn4REVuq7DjkTMyCMGCY1dpMa8aWfTQFt3Eh7smLchaZsU ' https://oauth2.googleapis.com/token
處理回應
如果 JWT 和存取權杖要求的格式正確,且服務帳戶有權執行這項作業,則來自授權伺服器的 JSON 回應會包含存取權杖。以下是回應範例:
{ "access_token": "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M", "scope": "https://www.googleapis.com/auth/prediction" "token_type": "Bearer", "expires_in": 3600 }
在 expires_in
值指定的持續時間內,您可以重複使用存取憑證。
呼叫 Google API
Java
完成下列步驟,使用 GoogleCredential
物件呼叫 Google API:
- 為您要使用
GoogleCredential
物件呼叫的 API 建立服務物件。例如:SQLAdmin sqladmin = new SQLAdmin.Builder(httpTransport, JSON_FACTORY, credential).build();
- 使用服務物件提供的介面向 API 服務發出要求。例如,若要在惡化-example-123
專案中列出 Cloud SQL 資料庫的執行個體:
SQLAdmin.Instances.List instances = sqladmin.instances().list("exciting-example-123").execute();
Python
請完成下列步驟,使用已授權的 Credentials
物件呼叫 Google API:
- 為您要呼叫的 API 建構服務物件。要建立服務物件,您可以呼叫
build
函式,並提供 API 名稱與版本以及授權的Credentials
物件。舉例來說,如要呼叫 Cloud SQL Administration API 第 1beta3 版:import googleapiclient.discovery sqladmin = googleapiclient.discovery.build('sqladmin', 'v1beta3', credentials=credentials)
- 使用服務物件提供的介面向 API 服務發出要求。例如,若要在惡化-example-123
專案中列出 Cloud SQL 資料庫的執行個體:
response = sqladmin.instances().list(project='exciting-example-123').execute()
HTTP/REST
應用程式取得存取權杖後,如果 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
存取憑證過期時
Google OAuth 2.0 授權伺服器核發的存取憑證會在 expires_in
值提供的時間長度到期後失效。存取權杖到期之後,應用程式應產生另一個 JWT 並簽署,然後要求其他存取權杖。
JWT 錯誤代碼
error 欄位 |
error_description 欄位 |
意義 | 解決方式 |
---|---|---|---|
unauthorized_client |
Unauthorized client or scope in request. |
如果您要使用全網域委派,則服務帳戶不會在使用者網域的管理控制台中獲得授權。 |
針對管理控制台中 授權程序通常需時數分鐘,但最多可能要 24 小時才會對 Google 帳戶中的所有使用者生效。 |
unauthorized_client |
Client is unauthorized to retrieve access tokens using this method, or client not
authorized for any of the scopes requested. |
服務帳戶使用用戶端電子郵件地址 (而非管理控制台中的用戶端 ID (數字)) 進行授權。 | 在管理控制台的「全網域委派」頁面中移除用戶端,並使用數字 ID 重新加入該用戶端。 |
access_denied |
(任何值) | 如果您使用的是全網域委派,則一或多個要求的範圍不會在管理控制台中獲得授權。 |
針對管理控制台的 授權程序通常需時數分鐘,但最多可能要 24 小時才會對 Google 帳戶中的所有使用者生效。 |
admin_policy_enforced |
(任何值) | 根據 Google Workspace 管理員的政策,此 Google 帳戶無法授權一或多個要求的範圍。 |
請參閱 Google Workspace 管理員說明文章:控管哪些第三方應用程式和內部應用程式可存取 Google Workspace 資料,進一步瞭解管理員如何限制對所有範圍或機密與受限制範圍的存取權,直到明確獲得 OAuth 用戶端 ID 的存取權為止。 |
invalid_client |
(任何值) |
OAuth 用戶端或 JWT 憑證無效或設定錯誤。 詳情請參閱錯誤說明。 |
確認 JWT 憑證有效且包含正確的聲明。 檢查 OAuth 用戶端和服務帳戶的設定是否正確無誤,而且使用的是正確的電子郵件地址。 檢查 JWT 憑證是否正確,並是否已在要求中針對用戶端 ID 核發。 |
invalid_grant |
Not a valid email. |
使用者不存在。 | 請檢查 sub 聲明 (電子郵件地址) 中的電子郵件地址是否正確。 |
invalid_grant |
|
這通常表示本機系統時間不正確。如果 exp 值未來距離 iat 值超過 65 分鐘,或是 exp 值低於 iat 值,也可能發生這種情況。 |
請確認系統中產生 JWT 的時鐘正確無誤。如有需要,請將您的時間同步到 Google NTP。 |
invalid_grant |
Invalid JWT Signature. |
簽署該 JWT 宣告時,使用的私密金鑰未與用戶端電子郵件識別的服務帳戶相關聯,或者該金鑰使用的金鑰已遭刪除、停用或已過期。 或者,JWT 宣告可能格式不正確,必須採用 Base64 編碼,且不含換行符號或邊框間距等號。 |
將 JWT 聲明集解碼,並驗證簽署宣告的金鑰是否與服務帳戶相關聯。 嘗試使用 Google 提供的 OAuth 程式庫,確認 JWT 已正確產生。 |
invalid_scope |
Invalid OAuth scope or ID token audience provided. |
未要求任何範圍 (範圍空白的清單),或是其中一個要求的範圍不存在 (即無效)。 |
確認已填入 JWT 的 請注意, |
disabled_client |
The OAuth client was disabled. |
用來簽署 JWT 斷言的金鑰已停用。 |
前往 Google API Console,然後在「IAM 與管理」>「服務帳戶」下方啟用服務帳戶,其中包含用於簽署斷言的「金鑰 ID」。 |
org_internal |
This client is restricted to users within its organization. |
要求中的 OAuth 用戶端 ID 屬於某項專案,會限制特定 Google Cloud 機構中存取 Google 帳戶的權限。 |
請使用機構的服務帳戶進行驗證。確認 OAuth 應用程式的使用者類型設定。 |
附加條款:服務帳戶沒有 OAuth 的授權
使用某些 Google API 時,您可以直接使用已簽署的 JWT 做為不記名憑證 (而非 OAuth 2.0 存取憑證),以授權的 API 呼叫。如果可以,那麼您在發出 API 呼叫之前,可以避免向 Google 授權伺服器發出網路要求。
如果您要呼叫的 API 已在 Google API GitHub 存放區中發布服務定義,您可以使用 JWT 提供授權的 API 呼叫,而非存取權杖。方法如下:
- 按照上述說明建立服務帳戶。請務必保留建立帳戶時取得的 JSON 檔案。
- 使用任何標準 JWT 程式庫 (例如 jwt.io 提供的程式庫),建立具有標頭和酬載的 JWT,如下列範例所示:
{ "alg": "RS256", "typ": "JWT", "kid": "abcdef1234567890" } . { "iss": "123456-compute@developer.gserviceaccount.com", "sub": "123456-compute@developer.gserviceaccount.com", "aud": "https://firestore.googleapis.com/", "iat": 1511900000, "exp": 1511903600 }
- 針對標頭中的 [
kid
] 欄位,指定服務帳戶的私密金鑰 ID。您可以在服務帳戶 JSON 檔案的private_key_id
欄位中找到這個值。 - 在 [
iss
] 和 [sub
] 欄位中,指定服務帳戶的電子郵件地址。您可以在服務帳戶 JSON 檔案的client_email
欄位中找到這個值。 - 請在
aud
欄位中指定 API 端點。例如:https://SERVICE.googleapis.com/
。 - 如果是
iat
欄位,請指定目前的 Unix 時間;如果是exp
欄位,請指定確切的 JWT 到期時間的 3600 秒。
使用服務帳戶 JSON 檔案中的私密金鑰,以 RSA-256 簽署 JWT。
例如:
Java
使用 google-api-java-client 和 java-jwt:
GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json")); PrivateKey privateKey = credential.getServiceAccountPrivateKey(); String privateKeyId = credential.getServiceAccountPrivateKeyId(); long now = System.currentTimeMillis(); try { Algorithm algorithm = Algorithm.RSA256(null, privateKey); String signedJwt = JWT.create() .withKeyId(privateKeyId) .withIssuer("123456-compute@developer.gserviceaccount.com") .withSubject("123456-compute@developer.gserviceaccount.com") .withAudience("https://firestore.googleapis.com/") .withIssuedAt(new Date(now)) .withExpiresAt(new Date(now + 3600 * 1000L)) .sign(algorithm); } catch ...
Python
使用 PyJWT:
iat = time.time() exp = iat + 3600 payload = {'iss': '123456-compute@developer.gserviceaccount.com', 'sub': '123456-compute@developer.gserviceaccount.com', 'aud': 'https://firestore.googleapis.com/', 'iat': iat, 'exp': exp} additional_headers = {'kid': PRIVATE_KEY_ID_FROM_JSON} signed_jwt = jwt.encode(payload, PRIVATE_KEY_FROM_JSON, headers=additional_headers, algorithm='RS256')
- 使用已簽署的 JWT 做為不記名憑證,呼叫 API:
GET /v1/projects/abc/databases/123/indexes HTTP/1.1 Authorization: Bearer SIGNED_JWT Host: firestore.googleapis.com