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 流程。
總覽
如要支援伺服器對伺服器的互動,請先在 API Console中為專案建立服務帳戶。如要存取 Google Workspace 帳戶中使用者資料,請將全網域存取權委派給服務帳戶。
接著,應用程式會使用服務帳戶的憑證,向 OAuth 2.0 授權伺服器要求存取權杖,準備進行已授權的 API 呼叫。
最後,應用程式可以使用存取權杖呼叫 Google API。
建立服務帳戶
服務帳戶的憑證包括至少一組公開/私密金鑰組,以及系統產生的專屬電子郵件地址。如果啟用全網域委派功能,用戶端 ID 也會是服務帳戶憑證的一部分。
如果應用程式在 Google App Engine 上執行,系統會在您建立專案時自動設定服務帳戶。
如果應用程式是在 Google Compute Engine 上執行,系統也會在您建立專案時自動設定服務帳戶,但您必須在建立 Google Compute Engine 執行個體時,指定應用程式需要存取的範圍。詳情請參閱準備執行個體以使用服務帳戶。
如果您的應用程式不是在 Google App Engine 或 Google Compute Engine 上執行,您必須在 Google API Console中取得這些憑證。如要產生服務帳戶憑證,或查看已產生的公開憑證,請按照下列步驟操作:
首先,創建一個服務帳戶:
- 打開 Service accounts page。
- If prompted, select a project, or create a new one.
- 單擊 創建服務帳戶。
- 在Service account details下,鍵入服務帳戶的名稱、ID 和描述,然後點擊Create and continue 。
- 可選:在Grant this service account access to project下,選擇要授予服務帳戶的 IAM 角色。
- 單擊繼續。
- 可選:在Grant users access to this service account下,添加允許使用和管理服務帳戶的用戶或組。
- 單擊完成。
接下來,創建一個服務帳戶密鑰:
- 單擊您創建的服務帳戶的電子郵件地址。
- 單擊密鑰選項卡。
- 在添加密鑰下拉列表中,選擇創建新密鑰。
- 單擊創建。
您的新公鑰/私鑰對已生成並下載到您的機器上;它作為私鑰的唯一副本。您有責任安全地存儲它。如果您丟失了這個密鑰對,您將需要生成一個新的。
您可以隨時返回 API Console 查看電子郵件地址、公開金鑰指紋和其他資訊,或產生其他公開/私密金鑰配對。如要進一步瞭解 API Console中的服務帳戶憑證,請參閱 API Console說明檔案中的「服務帳戶」。
記下服務帳戶的電子郵件地址,並將服務帳戶的私密金鑰檔案儲存在應用程式可存取的位置。應用程式需要這些憑證,才能發出授權的 API 呼叫。
將網域層級的權限委派給服務帳戶
機構的 Workspace 管理員可以使用 Google Workspace 帳戶,授權應用程式代表 Google Workspace 網域中的使用者存取 Workspace 使用者資料。舉例來說,透過 Google Calendar API 在 Google Workspace 網域中所有使用者的日曆中加入事件的應用程式,都可以使用服務帳戶來代表這些使用者存取 Google Calendar API。這種授權服務帳戶代表所有網域使用者存取資料的方式,有時稱為「委派全網域授權」給服務帳戶。
如要將全網域權限委派給服務帳戶,Google Workspace 網域的超級管理員必須完成下列步驟:
- 在 Google Workspace 網域的 管理控制台中,依序前往「主選單」 >「安全性」>「存取權與資料控管」>「API 控制項」。
- 在「全網域委派」窗格中,選取「管理全網域委派設定」。
- 點選「新增」。
- 在「用戶端 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。
- 點選「授權」。
您的應用程式現在有權以 Workspace 網域中的使用者身分發出 API 呼叫 (即「模擬」使用者)。準備發出這些委派的 API 呼叫時,您會明確指定要模擬的使用者。
準備發出委派的 API 呼叫
Java
從 API Console取得用戶端電子郵件地址和私密金鑰後,請使用 Java 適用的 Google Auth 程式庫,根據服務帳戶的憑證和應用程式需要存取的範圍,建立 GoogleCredentials
物件。例如:
import com.google.auth.oauth2.GoogleCredentials; import com.google.api.services.sqladmin.SQLAdminScopes; // ... GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream("MyProject-1234.json")) .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN));
如果您在 Google Cloud Platform 上開發應用程式,可以改用應用程式預設憑證,簡化程序。
委派全網域授權
如果您已將全網域存取權委派給服務帳戶,且想模擬使用者帳戶,請使用 GoogleCredentials
物件的 createDelegated
方法指定使用者帳戶的電子郵件地址。例如:
GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream("MyProject-1234.json")) .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN)) .createDelegated("workspace-user@example.com");
上述程式碼使用 GoogleCredentials
物件呼叫其 createDelegated()
方法。createDelegated()
方法的引數必須是屬於您 Workspace 帳戶的使用者。發出要求的程式碼會使用這項憑證,透過服務帳戶呼叫 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')
在應用程式中使用 Credentials 物件呼叫 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
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 標頭
標頭包含三個欄位,分別指出簽署演算法、聲明格式,以及用來簽署 JWT 的 [服務帳戶金鑰的金鑰 ID](https://cloud.google.com/iam/docs/reference/rest/v1/projects.serviceAccounts.keys)。演算法和格式為必填欄位,且每個欄位只能有一個值。隨著更多演算法和格式推出,這個標頭也會隨之變更。金鑰 ID 為選用項目。如果指定的金鑰 ID 有誤,GCP 會嘗試使用與服務帳戶相關聯的所有金鑰驗證權杖,如果找不到有效金鑰,就會拒絕權杖。Google 保留在未來拒絕金鑰 ID 錯誤的權杖。
服務帳戶採用 RSA SHA-256 演算法和 JWT 權杖格式。因此,標頭的 JSON 表示法如下所示:
{"alg":"RS256","typ":"JWT", "kid":"370ab79b4513eb9bad7c9bd16a95cb76b5b2a56a"}
這個值的 Base64url 表示法如下:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsICJraWQiOiIzNzBhYjc5YjQ1MTNlYjliYWQ3YzliZDE2YTk1Y2I3NmI1YjJhNTZhIn0=
建立 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 起算。 |
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 簽名演算法。這項資訊會以 RS256
形式表示在 JWT 標頭的 alg
欄位中。
使用 SHA256withRSA (也稱為 RSASSA-PKCS1-V1_5-SIGN,搭配 SHA-256 雜湊函式) 和從 Google API Console取得的私密金鑰,簽署輸入內容的 UTF-8 表示法。輸出內容會是位元組陣列。
簽章隨後必須採用 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 後,應用程式即可使用該 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
使用 GoogleCredentials
物件呼叫 Google API,請完成下列步驟:
- 使用
GoogleCredentials
物件,為要呼叫的 API 建立服務物件。例如:SQLAdmin sqladmin = new SQLAdmin.Builder(httpTransport, JSON_FACTORY, credentials).build();
- 使用服務物件提供的介面,向 API 服務提出要求。舉例來說,如要列出 exciting-example-123 專案中的 Cloud SQL 資料庫執行個體:
SQLAdmin.Instances.List instances = sqladmin.instances().list("exciting-example-123").execute();
Python
使用授權的 Credentials
物件呼叫 Google API,請完成下列步驟:
- 為要呼叫的 API 建構服務物件。您可以使用 API 的名稱和版本,以及授權的
Credentials
物件呼叫build
函式,藉此建構服務物件。舉例來說,如要呼叫 Cloud SQL Administration API 的 1beta3 版:import googleapiclient.discovery sqladmin = googleapiclient.discovery.build('sqladmin', 'v1beta3', credentials=credentials)
- 使用服務物件提供的介面,向 API 服務提出要求。舉例來說,如要列出 exciting-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 Files 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 帳戶無法授權一或多個要求範圍。 |
如要進一步瞭解管理員如何限制對所有範圍或機密/受限範圍的存取權,直到明確授予 OAuth 用戶端 ID 存取權為止,請參閱 Google Workspace 管理員說明文章「控管哪些第三方應用程式和內部應用程式可存取 Google Workspace 資料」。 |
invalid_client |
(任何值) |
OAuth 用戶端或 JWT 權杖無效或設定有誤。 詳情請參閱錯誤說明。 |
確認 JWT 權杖有效,且包含正確的聲明。 請確認 OAuth 用戶端和服務帳戶設定正確,且您使用的是正確的電子郵件地址。 確認 JWT 權杖正確無誤,且是為要求中的用戶端 ID 核發。 |
deleted_client |
(任何值) |
用來提出要求的 OAuth 用戶端已遭刪除。如果用戶端未使用 ,系統可能會手動或自動刪除。刪除後的 30 天內均可還原用戶端。 瞭解詳情。 |
請使用仍有效的用戶端 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」的服務帳戶,該 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 APIs 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
欄位,請指定 3600 秒後的確切時間,屆時 JWT 將會過期。
使用服務帳戶 JSON 檔案中的私密金鑰,以 RSA-256 簽署 JWT。
例如:
Java
使用 google-auth-library-java 和 java-jwt:
import com.google.auth.oauth2.ServiceAccountCredentials; ... GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream("MyProject-1234.json")); PrivateKey privateKey = ((ServiceAccountCredentials) credentials).getPrivateKey(); String privateKeyId = ((ServiceAccountCredentials) credentials).getPrivateKeyId(); 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
導入跨帳戶防護功能
為保護使用者帳戶,您應採取額外步驟,利用 Google 的跨帳戶保護服務實作跨帳戶保護機制。這項服務可讓您訂閱安全性事件通知,向應用程式提供使用者帳戶重大變更的相關資訊。接著,您就能根據決定如何回應活動,採取適當行動。
Google 跨帳戶保護服務傳送給應用程式的事件類型包括:
-
https://schemas.openid.net/secevent/risc/event-type/sessions-revoked
-
https://schemas.openid.net/secevent/oauth/event-type/token-revoked
-
https://schemas.openid.net/secevent/risc/event-type/account-disabled
如要進一步瞭解如何實作跨帳戶保護機制,以及查看可用事件的完整清單,請參閱「 透過跨帳戶保護機制保護使用者帳戶 」頁面。