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

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

取得 OAuth 2.0 憑證

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

要查看給定OAuth 2.0憑據的客戶端ID和客戶端密鑰,請單擊以下文本: 選擇憑據 。在打開的窗口中,選擇您的項目和所需的憑證,然後單擊“ 查看”

或者,從API Console的“ 憑據”頁面中查看您的客戶端ID和客戶端密鑰:

  1. Go to the Credentials page.
  2. 單擊您的憑據名稱或鉛筆( )圖標。您的客戶ID和機密位於頁面頂部。

設定重新導向 URI

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

要創建,查看或編輯給定OAuth 2.0憑據的重定向URI,請執行以下操作:

  1. Go to the Credentials page.
  2. 在頁面的OAuth 2.0客戶端ID部分中,點擊一個憑據。
  3. 查看或編輯重定向URI。

如果“憑據”頁面上沒有OAuth 2.0客戶端ID部分,則您的項目沒有OAuth憑據。要創建一個,點擊創建憑證

自訂使用者同意畫面

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

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

要啟用項目的同意屏幕:

  1. Consent Screen page中打開Google API Console 。
  2. If prompted, select a project, or create a new one.
  3. 填寫表格,然後點擊保存

如果要求中同時包含 OAuth 2.0 和 Google 雲端硬碟範圍,使用者會看到下列同意對話方塊。(這個一般對話方塊是使用 Google OAuth 2.0 Playground 產生,因此不包含在 中設定的品牌資訊。)

同意聲明頁面範例
圖 1. 同意聲明頁面螢幕截圖

存取服務

Google 和第三方提供的程式庫可協助您處理許多驗證使用者及存取 Google API 的實作細節。例如 Google Identity ServicesGoogle 用戶端程式庫,適用於各種平台。

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

驗證使用者

驗證使用者身分時,需要取得並驗證 ID 權杖。ID 憑證OpenID Connect 的標準化功能,專為在網路上分享身分主張而設計。

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

本文說明如何執行伺服器流程來驗證使用者。由於在用戶端處理及使用權杖時存在安全風險,隱含流程的複雜程度大幅增加。如需實作隱含流程,強烈建議使用 Google Identity Services

伺服器流程

請務必中設定應用程式,以便啟用這些通訊協定並驗證使用者。當使用者嘗試透過 Google 登入時,您需要:

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

1. 建立防偽狀態權杖

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

狀態權杖的理想選擇是使用高品質亂數產生器建構的字串,長度約為 30 個字元。另一種是雜湊,方法是使用後端保密的金鑰,簽署部分工作階段狀態變數。

下列程式碼示範如何產生專屬工作階段權杖。

PHP

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

// 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

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

# 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 中繼資料值,從探索文件擷取基準 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 的回覆。這個值必須與您在 Credentials page中設定的 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

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

// 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

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

# 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 Epoch 紀元時間 (整數秒數) 表示。
iat 一律 ID 權杖的核發時間。以 Unix Epoch 紀元時間 (整數秒數) 表示。
iss 一律 回覆核發者的核發者 ID。一律為 Google ID 權杖的 https://accounts.google.comaccounts.google.com
sub 一律 使用者的專屬 ID,必須別於任何其他 Google 帳戶,且不得重複使用。Google 帳戶可在不同時間點使用多個電子郵件地址,但 sub 值一律維持不變。在應用程式中,請使用 sub 做為使用者的唯一識別碼。長度上限為 255 個區分大小寫的 ASCII 字元。
at_hash 存取權杖雜湊值。驗證存取權杖是否與 ID 權杖相關聯。如果 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 (選用,但強烈建議)

通訊協定中來回傳輸的不透明字串。也就是說,在 Basic 流程中,這個字串會以 URI 參數的形式傳回,在 Implicit 流程中,則會以 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 發行的權杖會使用探索文件 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。如果權杖簽章有效,回應會是 JWT 酬載,以解碼的 JSON 物件形式呈現。

tokeninfo 端點適用於偵錯,但為了進行生產,請從金鑰端點擷取 Google 的公開金鑰,並在本機執行驗證。您應使用 jwks_uri 中繼資料值,從探索文件擷取金鑰 URI。對偵錯端點發出的要求可能會受到節流,或發生間歇性錯誤。

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

取得使用者個人資料資訊

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

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

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

    scope=openid%20profile%20email
  2. 將存取權杖新增至授權標頭,並對使用者資訊端點提出 HTTPS GET 要求。您應使用 userinfo_endpoint 中繼資料值,從探索文件擷取使用者資訊端點。如 OpenID Connect Standard Claims 和探索文件 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 要求物件除外)。