OpenID Connect

Google 的 OAuth 2.0 API 可用於驗證和授權作業。本文說明我們實作的 OAuth 2.0 驗證機制,符合 OpenID Connect 規格,且已獲得 OpenID 認證使用 OAuth 2.0 存取 Google API 中的說明文件也適用於這項服務。如要透過互動方式探索這個通訊協定,建議您使用 Google OAuth 2.0 Playground。如需在 Stack Overflow 尋求協助,請在問題中加上「google-oauth」標記。

設定 OAuth 2.0

在應用程式可以使用 Google 的 OAuth 2.0 驗證系統進行使用者登入之前,您必須在 中設定專案,以便取得 OAuth 2.0 憑證、設定重新導向 URI,以及 (選用) 自訂使用者在使用者同意畫面中看到的品牌資訊。您也可以使用 建立服務帳戶、啟用帳單、設定篩選條件,以及執行其他工作。詳情請參閱 說明

取得 OAuth 2.0 憑證

您需要 OAuth 2.0 憑證 (包括用戶端 ID 和用戶端密碼),才能驗證使用者並取得 Google API 存取權。

設定重新導向 URI

您在 中設定的重新導向 URI 會決定 Google 將驗證要求的回應傳送至何處。

自訂使用者同意聲明畫面

對於使用者而言,OAuth 2.0 驗證體驗包含同意畫面,說明使用者要釋出哪些資訊,以及適用的條款。舉例來說,當使用者登入時,系統可能會要求他們授予應用程式存取他們的電子郵件地址和基本帳戶資訊的權限。您可以使用 scope 參數要求存取這項資訊,應用程式會在驗證要求中加入這項參數。您也可以使用範圍要求存取其他 Google API。

使用者同意聲明畫面也會顯示品牌資訊,例如產品名稱、標誌和首頁網址。您可以控管 中的品牌資訊。

以下同意對話方塊顯示,當要求中同時包含 OAuth 2.0 和 Google 雲端硬碟範圍時,使用者會看到什麼內容。(這個通用對話方塊是使用 Google OAuth 2.0 Playground 產生的,因此不包含 中會設定的品牌資訊)。

同意聲明頁面螢幕截圖

存取服務

Google 和第三方提供的程式庫可用於處理許多驗證使用者和取得 Google API 存取權的實作細節。例如 Google 身分識別服務Google 用戶端程式庫,可用於各種平台。

如果您選擇不使用程式庫,請按照本文其餘部分的指示操作,其中說明瞭可用程式庫的 HTTP 要求流程。

驗證使用者

驗證使用者時,您必須取得 ID 權杖並驗證。ID 憑證OpenID Connect 的標準化功能,專門用於在網路上分享身分斷言。

驗證使用者並取得 ID 權杖最常見的方法稱為「伺服器」流程和「隱含」流程。伺服器流程可讓應用程式的後端伺服器驗證使用瀏覽器或行動裝置的使用者身分。當用戶端應用程式 (通常是瀏覽器中執行的 JavaScript 應用程式) 需要直接存取 API,而非透過其後端伺服器存取時,就會使用隱含流程。

本文說明如何執行驗證使用者的伺服器流程。由於在用戶端處理和使用權杖時存在安全風險,因此隱含式流程會變得更加複雜。如果您需要導入隱含的工作流程,強烈建議您使用 Google 身分識別服務

伺服器流程

請務必 中設定應用程式,讓應用程式能夠使用這些通訊協定並驗證使用者。當使用者嘗試透過 Google 帳戶登入時,您必須:

  1. 建立防偽造狀態權杖
  2. 向 Google 傳送驗證要求
  3. 確認防偽造狀態權杖
  4. code 換成存取權杖和 ID 權杖
  5. 從 ID 權杖取得使用者資訊
  6. 驗證使用者

1. 建立防偽造狀態權杖

您必須防範要求偽造攻擊,保護使用者的安全。第一步是建立獨特的工作階段權杖,在應用程式和使用者用戶端之間保留狀態。您稍後會將這組不重複的工作階段權杖,與 Google OAuth 登入服務傳回的驗證回應進行比對,以驗證使用者是否提出要求,而非惡意攻擊者。這些權杖通常稱為跨網站要求偽造 (CSRF) 權杖。

狀態符記的一個好選擇,是使用高品質的隨機號碼產生器,建立 30 個字元左右的字串。另一種則是使用在後端保密的金鑰,為部分工作階段狀態變數簽署而產生的雜湊。

以下程式碼示範如何產生不重複的工作階段權杖。

PHP

您必須下載 PHP 適用的 Google API 用戶端程式庫,才能使用這個範例。

// Create a state token to prevent request forgery.
// Store it in the session for later validation.
$state = bin2hex(random_bytes(128/8));
$app['session']->set('state', $state);
// Set the client ID, token state, and application name in the HTML while
// serving it.
return $app['twig']->render('index.html', array(
    'CLIENT_ID' => CLIENT_ID,
    'STATE' => $state,
    'APPLICATION_NAME' => APPLICATION_NAME
));

Java

您必須下載 Java 適用的 Google API 用戶端程式庫,才能使用這個範例。

// Create a state token to prevent request forgery.
// Store it in the session for later validation.
String state = new BigInteger(130, new SecureRandom()).toString(32);
request.session().attribute("state", state);
// Read index.html into memory, and set the client ID,
// token state, and application name in the HTML before serving it.
return new Scanner(new File("index.html"), "UTF-8")
    .useDelimiter("\\A").next()
    .replaceAll("[{]{2}\\s*CLIENT_ID\\s*[}]{2}", CLIENT_ID)
    .replaceAll("[{]{2}\\s*STATE\\s*[}]{2}", state)
    .replaceAll("[{]{2}\\s*APPLICATION_NAME\\s*[}]{2}",
    APPLICATION_NAME);

Python

您必須下載 Python 適用的 Google API 用戶端程式庫,才能使用這個範例。

# Create a state token to prevent request forgery.
# Store it in the session for later validation.
state = hashlib.sha256(os.urandom(1024)).hexdigest()
session['state'] = state
# Set the client ID, token state, and application name in the HTML while
# serving it.
response = make_response(
    render_template('index.html',
                    CLIENT_ID=CLIENT_ID,
                    STATE=state,
                    APPLICATION_NAME=APPLICATION_NAME))

2. 向 Google 傳送驗證要求

接下來,請使用適當的 URI 參數建立 HTTPS GET 要求。請注意,在這個程序的所有步驟中,請使用 HTTPS 而非 HTTP;系統會拒絕 HTTP 連線。您應使用 authorization_endpoint 中繼資料值,從Discovery 文件擷取基礎 URI。以下討論內容假設基礎 URI 為 https://accounts.google.com/o/oauth2/v2/auth

針對基本要求,請指定下列參數:

  • client_id,可從 取得。
  • response_type,在基本授權碼流程要求中應為 code。(詳情請參閱 response_type)。
  • scope,在基本要求中應為 openid email。 (詳情請參閱 scope)。
  • redirect_uri 應為伺服器上的 HTTP 端點,可接收 Google 的回應。這個值必須與您在 中設定的 OAuth 2.0 用戶端的其中一個授權重新導向 URI 完全相符。如果這個值不符合已授權的 URI,要求就會失敗,並傳回 redirect_uri_mismatch 錯誤。
  • state 應包含防竄改專屬工作階段權杖的值,以及使用者返回應用程式時需要復原內容的任何其他資訊,例如起始網址。(詳情請參閱 state)。
  • nonce 是應用程式產生的隨機值,可在存在時啟用重播保護機制。
  • login_hint 可以是使用者的電子郵件地址或 sub 字串,後者等同於使用者的 Google ID。如果您未提供 login_hint,且使用者目前已登入,同意畫面會要求核准將使用者的電子郵件地址發布至應用程式 (詳情請見 login_hint)。
  • 使用 hd 參數,為與 Google Workspace 或 Cloud 機構相關聯的特定網域使用者,改善 OpenID Connect 流程 (詳情請參閱 hd)。

以下是完整 OpenID Connect 驗證 URI 範例,其中包含可供閱讀的換行符號和空格:

https://accounts.google.com/o/oauth2/v2/auth?
 response_type=code&
 client_id=424911365001.apps.googleusercontent.com&
 scope=openid%20email&
 redirect_uri=https%3A//oauth2.example.com/code&
 state=security_token%3D138r5719ru3e1%26url%3Dhttps%3A%2F%2Foauth2-login-demo.example.com%2FmyHome&
 login_hint=jsmith@example.com&
 nonce=0394852-3190485-2490358&
 hd=example.com

如果應用程式要求使用者提供任何新資訊,或是要求存取使用者先前未核准的帳戶,使用者必須同意。

3. 確認防偽造狀態權杖

回應會傳送至您在要求中指定的 redirect_uri。所有回應都會以查詢字串的形式傳回,如下所示:

https://oauth2.example.com/code?state=security_token%3D138r5719ru3e1%26url%3Dhttps%3A%2F%2Foa2cb.example.com%2FmyHome&code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&scope=openid%20email%20https://www.googleapis.com/auth/userinfo.email

您必須在伺服器上確認從 Google 收到的 state 與您在步驟 1 中建立的工作階段權杖相符。這項來回驗證功能有助於確保使用者 (而非惡意指令碼) 提出要求。

以下程式碼示範如何確認您在步驟 1 中建立的工作階段權杖:

PHP

您必須下載 PHP 適用的 Google API 用戶端程式庫,才能使用這個範例。

// Ensure that there is no request forgery going on, and that the user
// sending us this connect request is the user that was supposed to.
if ($request->get('state') != ($app['session']->get('state'))) {
  return new Response('Invalid state parameter', 401);
}

Java

您必須下載 Java 適用的 Google API 用戶端程式庫,才能使用這個範例。

// Ensure that there is no request forgery going on, and that the user
// sending us this connect request is the user that was supposed to.
if (!request.queryParams("state").equals(
    request.session().attribute("state"))) {
  response.status(401);
  return GSON.toJson("Invalid state parameter.");
}

Python

您必須下載 Python 適用的 Google API 用戶端程式庫,才能使用這個範例。

# Ensure that the request is not a forgery and that the user sending
# this connect request is the expected user.
if request.args.get('state', '') != session['state']:
  response = make_response(json.dumps('Invalid state parameter.'), 401)
  response.headers['Content-Type'] = 'application/json'
  return response

4. 將 code 換成存取權杖和 ID 權杖

回應中包含 code 參數,這是一次性授權碼,可讓伺服器換取存取權杖和 ID 權杖。您的伺服器會透過傳送 HTTPS POST 要求進行此交換。POST 要求會傳送至權杖端點,您應使用 token_endpoint 中繼資料值,從探索文件擷取該端點。以下討論假設端點為 https://oauth2.googleapis.com/token。要求必須在 POST 主體中加入下列參數:

欄位
code 初始要求傳回的授權碼。
client_id 您從 取得的用戶端 ID,如取得 OAuth 2.0 憑證所述。
client_secret 您從 取得的用戶端密鑰,如「取得 OAuth 2.0 憑證」一文所述。
redirect_uri 中指定的特定 client_id 的已授權重新導向 URI,如「設定重新導向 URI」一文所述。
grant_type 這個欄位必須包含 authorization_code 的值, 如 OAuth 2.0 規格所定義

實際要求可能如下所示:

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=https%3A//oauth2.example.com/code&
grant_type=authorization_code

成功的回應會在 JSON 陣列中包含下列欄位:

欄位
access_token 可傳送至 Google API 的符記。
expires_in 存取權杖的剩餘生命週期 (以秒為單位)。
id_token 包含使用者身分資訊的 JWT,由 Google 數位簽署。
scope access_token 授予的存取範圍,以空格分隔的字串清單表示,並區分大小寫。
token_type 識別傳回的符記類型。此時,這個欄位一律會包含 Bearer 的值。
refresh_token (選用)

只有在驗證要求中將 access_type 參數設為 offline 時,這個欄位才會顯示。詳情請參閱「更新權杖」。

5. 從 ID 權杖取得使用者資訊

ID 權杖是 JWT (JSON Web Token),也就是經過加密簽署的 Base64 編碼 JSON 物件。通常,您必須先驗證 ID 權杖才能使用,但由於您是透過無中介 HTTPS 管道直接與 Google 通訊,並使用用戶端密鑰向 Google 驗證身分,因此您可以放心,您收到的權杖確實來自 Google 且有效。如果伺服器將 ID 權杖傳遞至應用程式的其他元件,其他元件必須先驗證權杖,才能使用權杖。

由於大多數的 API 程式庫會將驗證作業與解碼 base64url 編碼值和剖析其中的 JSON 作業結合,因此您在存取 ID 權杖中的宣告時,可能還是會驗證權杖。

ID 權杖的酬載

ID 權杖是包含一組名稱/值配對的 JSON 物件。以下是經過格式調整的範例,方便您閱讀:

{
  "iss": "https://accounts.google.com",
  "azp": "1234987819200.apps.googleusercontent.com",
  "aud": "1234987819200.apps.googleusercontent.com",
  "sub": "10769150350006150715113082367",
  "at_hash": "HK6E_P6Dh8Y93mRNtsDB1Q",
  "hd": "example.com",
  "email": "jsmith@example.com",
  "email_verified": "true",
  "iat": 1353601026,
  "exp": 1353604926,
  "nonce": "0394852-3190485-2490358"
}

Google ID 權杖可能含有下列欄位 (稱為憑證附加資訊):

版權聲明 自行提供 說明
aud 一律 此 ID 權杖的目標對象。此屬性必須是應用程式的 OAuth 2.0 用戶端 ID。
exp 一律 到期時間,ID 權杖必須在該時間或之後過期。以 Unix 時間 (整數秒數) 表示。
iat 一律 ID 權杖的核發時間。以 Unix 時間 (整數秒數) 表示。
iss 一律 回應核發者的核發者 ID。一律從 https://accounts.google.comaccounts.google.com 取得 Google ID 權杖。
sub 一律 使用者的專屬 ID,必須別於任何其他 Google 帳戶,且不得重複使用。Google 帳戶可在不同時間點使用多個電子郵件地址,但 sub 值一律維持不變。在應用程式中,請使用 sub 做為使用者的專屬識別碼。長度上限為 255 個大小寫敏感的 ASCII 字元。
at_hash 存取權杖雜湊值。提供驗證,確認存取權杖與身分權杖相連。如果 ID 權杖是在伺服器流程中以 access_token 值核發,則系統一律會納入這項權杖。這個權利要求可用於替代機制,以防範跨網站要求偽造攻擊,但如果您按照步驟 1步驟 3 操作,則不必驗證存取權權杖。
azp 授權表示器的 client_id。只有當 ID 權杖的要求者與 ID 權杖的目標對象不同時,才需要使用這項憑證附加資訊。如果在 Google 中使用混合型應用程式,若網頁應用程式和 Android 應用程式的 OAuth 2.0 client_id 不同,但共用同一項 Google API 專案,則可能會發生這種情況。
email 使用者的電子郵件地址。只有在您在要求中加入 email 範圍時才會提供。這項聲明的值可能不是此帳戶的專屬值,且可能會隨時間變更,因此您不應將這項值用作連結使用者記錄的主要 ID。您也無法依賴 email 要求的網域來識別 Google Workspace 或 Cloud 機構的使用者;請改用 hd 要求。
email_verified 如果使用者的電子郵件地址已完成驗證,則為 true;否則傳回 false。
family_name 使用者的姓氏。name 聲明存在時,可能會提供此屬性。
given_name 使用者的名字或姓氏。name 聲明存在時,可能會提供此屬性。
hd 與使用者 Google Workspace 或 Cloud 機構相關聯的網域。 只有在使用者屬於 Google Cloud 機構時才提供。如要將資源存取權限制為特定網域的成員,您必須勾選這個版權聲明。如果沒有這個憑證,表示帳戶不屬於 Google 代管的網域。
locale 使用者的語言代碼,以 BCP 47 語言標記表示。name 聲明存在時,可能會提供此屬性。
name 以可顯示格式呈現的使用者全名。可能在下列情況下提供:
  • 要求範圍包含字串「profile」
  • ID 權杖會透過權杖重新整理作業傳回

name 權利要求出現時,您可以使用這些權利要求更新應用程式的使用者記錄。請注意,系統不保證一定會顯示這項聲明。

nonce 您的應用程式在驗證要求中提供的 nonce 值。您必須確保該 Nonce 值只會出現一次,加強防範重送攻擊。
picture 使用者個人資料相片的網址。可能在下列情況下提供:
  • 要求範圍包含字串「profile」
  • ID 權杖會透過權杖重新整理作業傳回

picture 權利要求出現時,您可以使用這些權利要求更新應用程式的使用者記錄。請注意,系統不保證一定會顯示這項聲明。

profile 使用者個人資料頁面的網址。可能在下列情況下提供:
  • 要求範圍包含字串「profile」
  • ID 權杖會透過權杖重新整理作業傳回

profile 權利要求出現時,您可以使用這些權利要求更新應用程式的使用者記錄。請注意,系統不保證一定會顯示這項聲明。

6. 驗證使用者

從 ID 權杖取得使用者資訊後,您應查詢應用程式的使用者資料庫。如果使用者已存在資料庫中,且 Google API 回應符合所有登入要求,您就應為該使用者啟動應用程式工作階段。

如果使用者不存在於使用者資料庫中,您應將使用者重新導向至新使用者註冊流程。您可以根據從 Google 收到的資訊,自動為使用者註冊,或至少預先填入註冊表單中許多必要欄位。除了 ID 權杖中的資訊之外,您還可以在我們的使用者個人資料端點取得其他使用者個人資料資訊

進階主題

下列各節將詳細說明 Google OAuth 2.0 API。本文資訊適用於有驗證和授權進階需求的開發人員。

存取其他 Google API

使用 OAuth 2.0 進行驗證的好處之一,是應用程式可以在驗證使用者身分時,取得代表使用者使用其他 Google API (例如 YouTube、Google 雲端硬碟、日曆或聯絡人) 的權限。如要這樣做,請在傳送給 Google 的驗證要求中加入所需的其他範圍。舉例來說,如要將使用者的年齡層加入驗證要求,請傳遞 openid email https://www.googleapis.com/auth/profile.agerange.read 的範圍參數。系統會在同意畫面中適當提示使用者。您從 Google 收到的存取權憑證,可讓您存取與您要求並獲得的存取範圍相關的所有 API。

重新整理權杖

在 API 存取要求中,您可以要求在 code 交換程序中傳回重新整理權杖。更新權杖可讓應用程式在使用者不在應用程式中時,持續存取 Google API。如要要求重新整理權杖,請在驗證要求中將 access_type 參數設為 offline

注意事項:

  • 請務必安全且永久地儲存重新整理權杖,因為您只能在首次執行程式碼交換流程時取得重新整理權杖。
  • 系統會針對核發的重新整理權杖數量設下限制:每個用戶端/使用者組合一個限制,以及每個使用者在所有用戶端的另一個限制。如果應用程式要求的重新整理權杖過多,可能會觸及這些限制,導致較舊的重新整理權杖停止運作。

詳情請參閱「重新整理存取權權杖 (離線存取)」。

您可以在驗證要求中,將 prompt 參數設為 consent,即可提示使用者重新授權給應用程式。包含 prompt=consent 時,每當應用程式要求存取權範圍授權,就會顯示同意畫面,即使先前已將所有範圍授予 Google API 專案也一樣。因此,請僅在必要時才納入 prompt=consent

如要進一步瞭解 prompt 參數,請參閱「驗證 URI 參數」表格中的 prompt

驗證 URI 參數

下表將更完整地說明 Google OAuth 2.0 驗證 API 接受的參數。

參數 必填 說明
client_id (必填) 從 取得的用戶端 ID 字串,如取得 OAuth 2.0 憑證所述。
nonce (必填) 應用程式產生的隨機值,可啟用重播保護機制。
response_type (必填) 如果值為 code,系統會啟動基本授權碼流程,要求您向權杖端點發出 POST,才能取得權杖。如果值為 token id_tokenid_token token,系統會啟動隱含流程,需要在重新導向 URI 中使用 JavaScript,才能從 URI #fragment ID 擷取符記。
redirect_uri (必填) 決定回應傳送的位置。這個參數的值必須與您在 中設定的授權重新導向值完全相符(包括 HTTP 或 HTTPS 通訊協定、大小寫和結尾的「/」)。
scope (必填)

範圍參數的開頭必須是 openid 值,然後包含 profile 值或 email 值,或兩者皆包含。

如果提供 profile 範圍值,ID 權杖可能會 (但不保證) 包含使用者的預設 profile 權杖。

如果存在 email 範圍值,ID 權杖就會包含 emailemail_verified 宣告。

除了這些 OpenID 專屬範圍外,範圍引數還可包含其他範圍值。所有範圍值都必須以空格分隔。舉例來說,如果您想取得使用者 Google 雲端硬碟的個別檔案存取權,範圍參數可能會是 openid profile email https://www.googleapis.com/auth/drive.file

如需可用範圍的相關資訊,請參閱「Google API 適用的 OAuth 2.0 範圍」或您要使用的 Google API 說明文件。

state (選用,但強烈建議使用)

在通訊協定中進行來回傳送的不透明字串,也就是在基本流程中以 URI 參數的形式傳回,以及在隱含流程中的 URI #fragment ID 中傳回。

state 可用於連結要求和回應。由於 redirect_uri 可以被猜測,因此使用 state 值可提高您對傳入連線的信心,確保該連線是應用程式啟動的驗證要求結果。如果您產生隨機字串,或在這個 state 變數中對某些用戶端狀態 (例如 Cookie) 的雜湊編碼,您就可以驗證回應,進一步確保要求和回應來自同一個瀏覽器。這可防範跨網站要求偽造等攻擊。

access_type (選填) 允許的值為 offlineonline離線存取中記錄了這項效果;如果要求存取權憑證,除非指定 offline 的值,否則用戶端不會收到更新憑證。
display (選填) 這是 ASCII 字串值,可用於指定授權伺服器如何顯示驗證和同意使用者介面頁面。以下值已指定並由 Google 伺服器接受,但不會影響其行為:pagepopuptouchwap
hd (選填)

簡化 Google Cloud 機構擁有的帳戶登入程序。您可以加入 Google Cloud 機構網域 (例如 mycollege.edu),指出帳戶選取 UI 應針對該網域中的帳戶進行最佳化。如要針對 Google Cloud 機構帳戶進行一般最佳化,而非只針對單一 Google Cloud 機構網域進行最佳化,請將值設為星號 (*):hd=*

請勿依賴這個 UI 最佳化功能來控制誰可以存取您的應用程式,因為用戶端要求可以修改。請務必驗證傳回的 ID 權杖是否包含與您預期相符的 hd 宣告值 (例如 mycolledge.edu)。與要求參數不同,ID 權杖 hd 宣告包含在 Google 的安全性權杖中,因此可以信任該值。

include_granted_scopes (選填) 如果此參數提供的值為 true,且授權要求已核准,則授權會包含先前針對此使用者/應用程式組合授予其他範圍的所有授權;請參閱「逐步授權」。

請注意,您無法透過已安裝應用程式流程進行漸進式授權。

login_hint (選填) 當應用程式知道要驗證哪位使用者時,可以將這個參數提供給驗證伺服器做為提示。傳遞這個提示可抑制帳戶選擇器,並在登入表單中預先填入電子郵件方塊,或選取適當的工作階段 (如果使用者使用多重登入),這有助於避免應用程式登入錯誤的使用者帳戶。這個值可以是電子郵件地址或 sub 字串,後者等同於使用者的 Google ID。
prompt (選填) 以空格分隔的字串值清單,用於指定授權伺服器是否會提示使用者重新驗證及同意。可能的值如下:
  • none

    授權伺服器不會顯示任何驗證或使用者同意畫面;如果使用者尚未通過驗證,且尚未預先設定所要求範圍的同意聲明,系統會傳回錯誤。您可以使用 none 檢查現有的驗證和/或同意聲明。

  • consent

    授權伺服器會在將資訊傳回用戶端前,提示使用者提供同意聲明。

  • select_account

    授權伺服器會提示使用者選取使用者帳戶。這可讓在授權伺服器中擁有多個帳戶的使用者,從多個帳戶中選取目前可能有工作階段的帳戶。

如果未指定任何值,且使用者先前未授權存取權,系統會向使用者顯示同意聲明畫面。

驗證 ID 權杖

除非您知道 ID 權杖是直接來自 Google,否則必須在伺服器上驗證所有 ID 權杖。舉例來說,您的伺服器必須驗證從用戶端應用程式收到的任何 ID 權杖是否為真。

以下是您可能會將 ID 權杖傳送至伺服器的常見情況:

  • 透過需要驗證的請求傳送 ID 權杖。ID 權杖會告知您提出要求的特定使用者,以及 ID 權杖授予哪個用戶端。

ID 權杖屬於敏感資訊,如果遭到攔截,可能會遭到濫用。您必須確保這些符記以安全無虞的方式處理,也就是只能透過 HTTPS 傳輸,且只能透過 POST 資料或要求標頭傳輸。如果您將 ID 權杖儲存在伺服器上,也必須以安全的方式儲存。

ID 權杖之所以實用,是因為您可以將其傳遞至應用程式的不同元件。這些元件可使用 ID 權杖做為輕量驗證機制,驗證應用程式和使用者。不過,您必須先驗證 ID 權杖中的資訊,才能使用該資訊,或將其做為使用者已完成驗證的斷言。

驗證 ID 權杖需要執行幾個步驟:

  1. 確認 ID 權杖是否由發出者正確簽署。Google 核發的權杖會使用 Discovery 文件jwks_uri 中繼資料值指定的 URI 所找到的其中一個憑證進行簽署。
  2. 確認 ID 權杖中的 iss 要求值等於 https://accounts.google.comaccounts.google.com
  3. 確認 ID 權杖中的 aud 要求值與應用程式的用戶端 ID 相等。
  4. 確認 ID 權杖的到期時間 (exp 要求) 尚未過期。
  5. 如果您在要求中指定了 hd 參數值,請確認 ID 權杖包含 hd 要求,且與與 Google Cloud 機構相關聯的已接受網域相符。

步驟 2 到 5 只涉及字串和日期比較,這類操作相當簡單,因此我們不會在此詳述。

第一步較為複雜,涉及加密編譯簽名檢查。如要進行偵錯,您可以使用 Google 的 tokeninfo 端點,與在伺服器或裝置上執行的本機處理作業進行比較。假設 ID 權杖的值為 XYZ123。接著,您會解除 URI https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123 的參照。如果權杖簽名有效,回應會是已解碼 JSON 物件形式的 JWT 酬載。

tokeninfo 端點可用於偵錯,但如果是用於實際工作環境,請從金鑰端點擷取 Google 的公開金鑰,並在本機執行驗證。您應使用 jwks_uri 中繼資料值,從Discovery 文件擷取鍵 URI。對偵錯端點的要求可能會受到節流限制,或會發生間歇性錯誤。

由於 Google 很少變更公開金鑰,因此您可以使用 HTTP 回應的快取指令將其快取,在大多數情況下,執行本機驗證的效率會比使用 tokeninfo 端點高出許多。這項驗證作業需要擷取及剖析憑證,並進行適當的加密編譯呼叫,以便檢查簽章。幸好,有許多經過良好偵錯的程式庫可用多種語言完成此工作 (請參閱 jwt.io)。

取得使用者個人資料資訊

如要取得使用者的其他個人資料資訊,您可以使用存取權存取權 (應用程式在驗證流程期間收到的憑證) 和 OpenID Connect 標準:

  1. 如要符合 OpenID 規範,您必須在驗證要求中加入 openid profile 範圍值。

    如果您想納入使用者的電子郵件地址,可以指定額外的範圍值 email。如要同時指定 profileemail,您可以在驗證要求 URI 中加入下列參數:

    scope=openid%20profile%20email
  2. 將存取權權杖新增至授權標頭,並對 userinfo 端點提出 HTTPS GET 要求。您應使用 userinfo_endpoint 中繼資料值,從 Discovery 文件擷取 userinfo 端點。如 OpenID Connect Standard Claims 和 Discovery 文件的 claims_supported 中繼資料值所述,userinfo 回應會包含使用者相關資訊。使用者或其機構可能會選擇提供或隱藏特定欄位,因此您可能無法取得授權存取範圍內的每個欄位資訊。

探索文件

OpenID Connect 通訊協定要求使用多個端點來驗證使用者,以及要求憑證、使用者資訊和公開金鑰等資源。

為了簡化實作並提高彈性,OpenID Connect 允許使用「探索文件」,這是位於已知位置的 JSON 文件,其中包含鍵/值組合,可提供 OpenID Connect 提供者的設定詳細資料,包括授權、權杖、撤銷、使用者資訊和公開金鑰端點的 URI。您可以從下列位置擷取 Google OpenID Connect 服務的探索文件:

https://accounts.google.com/.well-known/openid-configuration

如要使用 Google 的 OpenID Connect 服務,您必須將探索文件 URI (https://accounts.google.com/.well-known/openid-configuration) 硬式編碼至應用程式。應用程式會擷取文件、在回應中套用快取規則,然後視需要從中擷取端點 URI。舉例來說,如要驗證使用者,您的程式碼會擷取 authorization_endpoint 中繼資料值 (在下方範例中為 https://accounts.google.com/o/oauth2/v2/auth),做為傳送至 Google 的驗證要求的基準 URI。

以下是這類文件的範例,欄位名稱是 OpenID Connect Discovery 1.0 中指定的名稱 (請參閱該文件瞭解其含義)。這些值僅供說明,可能會變更,但已從實際 Google Discovery 文件的最新版本複製:

{
  "issuer": "https://accounts.google.com",
  "authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
  "device_authorization_endpoint": "https://oauth2.googleapis.com/device/code",
  "token_endpoint": "https://oauth2.googleapis.com/token",
  "userinfo_endpoint": "https://openidconnect.googleapis.com/v1/userinfo",
  "revocation_endpoint": "https://oauth2.googleapis.com/revoke",
  "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
  "response_types_supported": [
    "code",
    "token",
    "id_token",
    "code token",
    "code id_token",
    "token id_token",
    "code token id_token",
    "none"
  ],
  "subject_types_supported": [
    "public"
  ],
  "id_token_signing_alg_values_supported": [
    "RS256"
  ],
  "scopes_supported": [
    "openid",
    "email",
    "profile"
  ],
  "token_endpoint_auth_methods_supported": [
    "client_secret_post",
    "client_secret_basic"
  ],
  "claims_supported": [
    "aud",
    "email",
    "email_verified",
    "exp",
    "family_name",
    "given_name",
    "iat",
    "iss",
    "locale",
    "name",
    "picture",
    "sub"
  ],
  "code_challenge_methods_supported": [
    "plain",
    "S256"
  ]
}

您可以快取探索文件中的值,避免進行 HTTP 往返傳輸。系統會使用標準 HTTP 快取標頭,並應遵循這些標頭。

用戶端程式庫

下列用戶端程式庫可與熱門架構整合,讓您更輕鬆地實作 OAuth 2.0:

OpenID Connect 法規遵循

Google 的 OAuth 2.0 驗證系統支援 OpenID Connect Core 規格的必要功能。任何用於 OpenID Connect 的用戶端都應與這項服務互通 (OpenID 要求物件除外)。