Google 致力於促進黑人社區的種族平等。 怎麼看。

將 OAuth 2.0 用於 Web 服務器應用程序

本文檔解釋了 Web 服務器應用程序如何使用 Google API 客戶端庫或 Google OAuth 2.0 端點來實現 OAuth 2.0 授權以訪問 Google API。

OAuth 2.0 允許用戶與應用程序共享特定數據,同時將他們的用戶名、密碼和其他信息保密。例如,應用程序可以使用 OAuth 2.0 獲得用戶的許可,以便將文件存儲在其 Google 雲端硬盤中。

此 OAuth 2.0 流程專門用於用戶授權。它專為可以存儲機密信息和維護狀態的應用程序而設計。在用戶與應用程序交互時或在用戶離開應用程序之後,正確授權的 Web 服務器應用程序可以訪問 API。

Web服務器應用程序也經常使用服務帳戶授權API請求,調用雲API來訪問的基於項目的數據,而不是用戶特定數據時尤為如此。 Web 服務器應用程序可以將服務帳戶與用戶授權結合使用。

客戶端庫

在這個頁面中使用的語言,具體的例子谷歌API客戶端庫來實現的OAuth 2.0授權。要運行代碼示例,您必須首先為您的語言安裝客戶端庫。

當您使用 Google API 客戶端庫來處理應用程序的 OAuth 2.0 流時,客戶端庫會執行應用程序原本需要自行處理的許多操作。例如,它確定應用程序何時可以使用或刷新存儲的訪問令牌以及應用程序何時必須重新獲得同意。客戶端庫還生成正確的重定向 URL,並幫助實現為訪問令牌交換授權代碼的重定向處理程序。

客戶端庫可用於以下語言:

先決條件

為您的項目啟用 API

調用谷歌API的應用程序需要能夠在這些API API Console。

要為您的項目啟用 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不在列表中可見,用搜索找到它,或者點擊查看全部的產品系列屬於。
  4. 選擇您要啟用的API,然後點擊啟用按鈕。
  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. 單擊創建證書> OAuth用戶端ID。
  3. 選擇Web應用程序的應用程序類型。
  4. 填寫表格,然後點擊創建。應用程序使用的語言和框架,如PHP,Java和Python和Ruby和.NET必須指定授權的重定向URI。重定向 URI 是 OAuth 2.0 服務器可以向其發送響應的端點。這些端點都必須遵守谷歌的驗證規則

    為了進行測試,您可以指定參考本地機器的URI,如http://localhost:8080 。考慮到這一點,請注意,所有的在這個文件的例子使用http://localhost:8080作為重定向URI。

    我們建議您設計您的應用程序的身份驗證的端點,使您的應用程序沒有在網頁上公開授權碼到其他資源。

創建憑據後,請從該client_secret.json文件 API Console。將文件安全地存儲在只有您的應用程序可以訪問的位置。

確定訪問範圍

範圍使您的應用程序能夠僅請求訪問它需要的資源,同時還使用戶能夠控制他們授予您的應用程序的訪問權限。因此,請求的範圍數量與獲得用戶同意的可能性之間可能存在反比關係。

在開始實施 OAuth 2.0 授權之前,我們建議您確定您的應用需要訪問權限的範圍。

我們還建議到授權應用程序的請求訪問通過一個作用域增量授權過程中,您的應用程序請求用戶數據的情況下訪問。此最佳實踐可幫助用戶更輕鬆地了解您的應用程序為何需要其請求的訪問權限。

的OAuth 2.0 API範圍文檔包含範圍,您可以使用訪問谷歌的API的完整列表。

特定語言要求

要運行本文檔中的任何代碼示例,您需要一個 Google 帳戶、互聯網訪問權限和 Web 瀏覽器。如果您使用 API 客戶端庫之一,另請參閱下面的特定語言要求。

PHP

要運行本文檔中的 PHP 代碼示例,您需要:

  • PHP 5.4 或更高版本,安裝了命令行界面 (CLI) 和 JSON 擴展。
  • 作曲家依賴管理工具。
  • PHP 的 Google API 客戶端庫:

    php composer.phar require google/apiclient:^2.0

Python

要運行本文檔中的 Python 代碼示例,您需要:

  • Python 2.6 或更高版本
  • PIP包管理工具。
  • 該谷歌API客戶端庫的Python:
    pip install --upgrade google-api-python-client
  • google-authgoogle-auth-oauthlib ,和google-auth-httplib2用戶授權。
    pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2
  • Flask Python Web 應用程序框架。
    pip install --upgrade flask
  • requests的HTTP庫。
    pip install --upgrade requests

紅寶石

要運行本文檔中的 Ruby 代碼示例,您需要:

  • Ruby 2.2.2 或更高版本
  • Ruby 的 Google API 客戶端庫:

    gem install google-api-client
  • Sinatra Ruby Web 應用程序框架。

    gem install sinatra

HTTP/REST

您無需安裝任何庫即可直接調用 OAuth 2.0 端點。

獲取 OAuth 2.0 訪問令牌

以下步驟展示了您的應用程序如何與 Google 的 OAuth 2.0 服務器交互以獲取用戶的同意以代表用戶執行 API 請求。您的應用程序必須先獲得該同意,然後才能執行需要用戶授權的 Google API 請求。

下面的列表快速總結了這些步驟:

  1. 您的應用程序確定它需要的權限。
  2. 您的應用程序將用戶連同請求的權限列表一起重定向到 Google。
  3. 用戶決定是否向您的應用程序授予權限。
  4. 您的應用程序會找出用戶的決定。
  5. 如果用戶授予了請求的權限,您的應用程序將檢索代表用戶發出 API 請求所需的令牌。

第一步:設置授權參數

您的第一步是創建授權請求。該請求設置了標識您的應用程序的參數,並定義了用戶將被要求授予您的應用程序的權限。

  • 如果您使用 Google 客戶端庫進行 OAuth 2.0 身份驗證和授權,則需要創建和配置定義這些參數的對象。
  • 如果您直接調用 Google OAuth 2.0 端點,您將生成一個 URL 並在該 URL 上設置參數。

下面的選項卡定義了 Web 服務器應用程序支持的授權參數。特定於語言的示例還展示瞭如何使用客戶端庫或授權庫來配置設置這些參數的對象。

PHP

下面的代碼段創建Google_Client()對象,其定義在所述授權請求的參數。

client_secret.json文件對象使用情況的信息,以確定您的應用程序。 (請參閱創建授權證書更多有關文件。)對象還標識範圍您的應用程序請求訪問和URL到應用程序的身份驗證的端點,這將處理來自谷歌的OAuth 2.0服務器的響應。最後,代碼設置可選access_typeinclude_granted_scopes參數。

例如,此代碼請求對用戶的 Google Drive 進行只讀、離線訪問:

$client = new Google_Client();
$client->setAuthConfig('client_secret.json');
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');
// offline access will give you both an access and refresh token so that
// your app can refresh the access token without user interaction.
$client->setAccessType('offline');
// Using "consent" ensures that your application always receives a refresh token.
// If you are not using offline access, you can omit this.
$client->setApprovalPrompt("consent");
$client->setIncludeGrantedScopes(true);   // incremental auth

該請求指定了以下信息:

參數
client_id必需的

您的應用程序的客戶端 ID。你可以找到在這個值 API ConsoleCredentials page

在PHP中,調用setAuthConfig函數從client_secret.json文件加載授權證書。

$client = new Google_Client();
$client->setAuthConfig('client_secret.json');
redirect_uri必需的

確定用戶完成授權流程後 API 服務器將用戶重定向到何處。該值必須完全匹配授權的重定向的URI的OAuth 2.0用戶端,您可以在您的客戶機的配置的一個 API ConsoleCredentials page。如果此值不為所提供的匹配授權的重新導向URI client_id你會得到一個redirect_uri_mismatch錯誤。

注意, httphttps方案,案例,和斜線(' / ')必須全部匹配。

要設置在PHP這個值,調用setRedirectUri功能。請注意,您必須指定提供有效的重定向URI client_id

$client->setRedirectUri('https://oauth2.example.com/code');
scope必需的

一個以空格分隔的範圍列表,用於標識您的應用程序可以代表用戶訪問的資源。這些值通知 Google 向用戶顯示的同意屏幕。

範圍使您的應用程序能夠僅請求訪問它需要的資源,同時還使用戶能夠控制他們授予您的應用程序的訪問權限。因此,請求的範圍數量與獲得用戶同意的可能性之間存在反比關係。

要設置在PHP這個值,調用addScope功能:

$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);

我們建議您的應用程序盡可能請求訪問上下文中的授權範圍。通過請求訪問用戶數據的情況下,通過增量授權,你幫助用戶更容易理解為什麼您的應用程序需要被請求的訪問。

access_type受到推崇的

指示當用戶不在瀏覽器時您的應用程序是否可以刷新訪問令牌。有效的參數值是online ,這是默認值,而offline

將該值設置為offline ,如果你的應用需要刷新訪問令牌,當用戶不存在於瀏覽器。這是本文檔後面描述的刷新訪問令牌的方法。該值指示谷歌授權服務器返回令牌的刷新令牌首次訪問您的應用程序交流的令牌的授權碼。

要設置在PHP這個值,調用setAccessType功能:

$client->setAccessType('offline');
state受到推崇的

指定您的應用程序用於維護授權請求和授權服務器響應之間的狀態的任何字符串值。服務器返回您發送的精確值name=value的URL查詢組件對( ?對的) redirect_uri用戶同意後,或拒絕您的應用程序的訪問請求。

您可以將此參數用於多種用途,例如將用戶定向到應用程序中的正確資源、發送隨機數以及減少跨站點請求偽造。由於您的redirect_uri可以猜到,使用state值可以增加你保證傳入連接的認證請求的結果。如果您生成隨機字符串或對 cookie 的哈希值或捕獲客戶端狀態的其他值進行編碼,則可以驗證響應以額外確保請求和響應源自同一瀏覽器,從而防止跨站點等攻擊請求偽造。見ID連接文檔中如何創建並確認一個例子state令牌。

要設置在PHP這個值,調用setState函數:

$client->setState($sample_passthrough_value);
include_granted_scopes可選的

使應用程序能夠使用增量授權來請求訪問上下文中的其他範圍。如果這個參數的值設置為true和授權請求被批准,那麼新的訪問令牌也將覆蓋該用戶以前授予的應用程序訪問的任何範圍。見增量授權的示例部分。

要設置在PHP這個值,調用setIncludeGrantedScopes功能:

$client->setIncludeGrantedScopes(true);
login_hint可選的

如果您的應用程序知道哪個用戶正在嘗試進行身份驗證,它可以使用此參數向 Google 身份驗證服務器提供提示。服務器通過在登錄表單中預填電子郵件字段或選擇適當的多登錄會話,使用提示來簡化登錄流程。

設置參數值到電子郵件地址或sub標識符,這相當於用戶的谷歌ID。

要設置在PHP這個值,調用setLoginHint功能:

$client->setLoginHint('None');
prompt可選的

以空格分隔、區分大小寫的提示列表,以呈現給用戶。如果您不指定此參數,則僅在您的項目第一次請求訪問時才會提示用戶。見提示重新同意,以獲取更多信息。

要設置在PHP這個值,調用setApprovalPrompt功能:

$client->setApprovalPrompt('consent');

可能的值為:

none不顯示任何身份驗證或同意屏幕。不得與其他值一起指定。
consent提示用戶同意。
select_account提示用戶選擇一個帳戶。

Python

下面的代碼段使用google-auth-oauthlib.flow模塊來構建所述授權請求。

代碼構造一個Flow對象,它標識從client_secret.json文件應用程序中使用的信息,你下載後創建的授權憑證。該對像還標識您的應用程序請求訪問權限的範圍以及您應用程序的 auth 端點的 URL,它將處理來自 Google 的 OAuth 2.0 服務器的響應。最後,代碼設置可選access_typeinclude_granted_scopes參數。

例如,此代碼請求對用戶的 Google Drive 進行只讀、離線訪問:

import google.oauth2.credentials
import google_auth_oauthlib.flow

# Use the client_secret.json file to identify the application requesting
# authorization. The client ID (from that file) and access scopes are required.
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'])

# Indicate where the API server will redirect the user after the user completes
# the authorization flow. The redirect URI is required. The value must exactly
# match one of the authorized redirect URIs for the OAuth 2.0 client, which you
# configured in the API Console. If this value doesn't match an authorized URI,
# you will get a 'redirect_uri_mismatch' error.
flow.redirect_uri = 'https://www.example.com/oauth2callback'

# Generate URL for request to Google's OAuth 2.0 server.
# Use kwargs to set optional request parameters.
authorization_url, state = flow.authorization_url(
    # Enable offline access so that you can refresh an access token without
    # re-prompting the user for permission. Recommended for web server apps.
    access_type='offline',
    # Enable incremental authorization. Recommended as a best practice.
    include_granted_scopes='true')

該請求指定了以下信息:

參數
client_id必需的

您的應用程序的客戶端 ID。你可以找到在這個值 API ConsoleCredentials page

在Python,調用from_client_secrets_file方法從client_secret.json文件中檢索的客戶機ID。 (您也可以使用from_client_config方法,它通過客戶端配置,因為它最初出現在客戶端機密文件,但不訪問文件本身。)

flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'])
redirect_uri必需的

確定用戶完成授權流程後 API 服務器將用戶重定向到何處。該值必須完全匹配授權的重定向的URI的OAuth 2.0用戶端,您可以在您的客戶機的配置的一個 API ConsoleCredentials page。如果此值不為所提供的匹配授權的重新導向URI client_id你會得到一個redirect_uri_mismatch錯誤。

注意, httphttps方案,案例,和斜線(' / ')必須全部匹配。

要設置在Python這個值,設置flow對象的redirect_uri屬性:

flow.redirect_uri = 'https://oauth2.example.com/code'
scope必需的

標識您的應用程序可以代表用戶訪問的資源的範圍列表。這些值通知 Google 向用戶顯示的同意屏幕。

範圍使您的應用程序能夠僅請求訪問它需要的資源,同時還使用戶能夠控制他們授予您的應用程序的訪問權限。因此,請求的範圍數量與獲得用戶同意的可能性之間存在反比關係。

在Python中,使用您用來設置同樣的方法client_id指定的範圍列表。

flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'])

我們建議您的應用程序盡可能請求訪問上下文中的授權範圍。通過請求訪問用戶數據的情況下,通過增量授權,你幫助用戶更容易理解為什麼您的應用程序需要被請求的訪問。

access_type受到推崇的

指示當用戶不在瀏覽器時您的應用程序是否可以刷新訪問令牌。有效的參數值是online ,這是默認值,而offline

將該值設置為offline ,如果你的應用需要刷新訪問令牌,當用戶不存在於瀏覽器。這是本文檔後面描述的刷新訪問令牌的方法。該值指示谷歌授權服務器返回令牌的刷新令牌首次訪問您的應用程序交流的令牌的授權碼。

在Python,設置access_type通過指定參數access_type調用時作為關鍵字參數flow.authorization_url方法:

authorization_url, state = flow.authorization_url(
    access_type='offline',
    include_granted_scopes='true')
state受到推崇的

指定您的應用程序用於維護授權請求和授權服務器響應之間的狀態的任何字符串值。服務器返回您發送的精確值name=value的URL查詢組件對( ?對的) redirect_uri用戶同意後,或拒絕您的應用程序的訪問請求。

您可以將此參數用於多種用途,例如將用戶定向到應用程序中的正確資源、發送隨機數以及減少跨站點請求偽造。由於您的redirect_uri可以猜到,使用state值可以增加你保證傳入連接的認證請求的結果。如果您生成隨機字符串或對 cookie 的哈希值或捕獲客戶端狀態的其他值進行編碼,則可以驗證響應以額外確保請求和響應源自同一瀏覽器,從而防止跨站點等攻擊請求偽造。見ID連接文檔中如何創建並確認一個例子state令牌。

在Python,設定state通過指定參數state調用時作為關鍵字參數flow.authorization_url方法:

authorization_url, state = flow.authorization_url(
    access_type='offline',
    state=sample_passthrough_value,
    include_granted_scopes='true')
include_granted_scopes可選的

使應用程序能夠使用增量授權來請求訪問上下文中的其他範圍。如果這個參數的值設置為true和授權請求被批准,那麼新的訪問令牌也將覆蓋該用戶以前授予的應用程序訪問的任何範圍。見增量授權的示例部分。

在Python,設置include_granted_scopes參數通過指定include_granted_scopes調用時作為關鍵字參數flow.authorization_url方法:

authorization_url, state = flow.authorization_url(
    access_type='offline',
    include_granted_scopes='true')
login_hint可選的

如果您的應用程序知道哪個用戶正在嘗試進行身份驗證,它可以使用此參數向 Google 身份驗證服務器提供提示。服務器通過預先填寫登錄表單中的電子郵件字段或選擇適當的多登錄會話,使用提示來簡化登錄流程。

設置參數值到電子郵件地址或sub標識符,這相當於用戶的谷歌ID。

在Python,設置login_hint通過指定參數login_hint調用時作為關鍵字參數flow.authorization_url方法:

authorization_url, state = flow.authorization_url(
    access_type='offline',
    login_hint='None',
    include_granted_scopes='true')
prompt可選的

以空格分隔、區分大小寫的提示列表,以呈現給用戶。如果您不指定此參數,則僅在您的項目第一次請求訪問時才會提示用戶。見提示重新同意,以獲取更多信息。

在Python,設置prompt通過指定參數prompt調用時作為關鍵字參數flow.authorization_url方法:

authorization_url, state = flow.authorization_url(
      access_type='offline',
      prompt='consent',
      include_granted_scopes='true')

可能的值為:

none不顯示任何身份驗證或同意屏幕。不得與其他值一起指定。
consent提示用戶同意。
select_account提示用戶選擇一個帳戶。

紅寶石

使用您創建的 client_secrets.json 文件在應用程序中配置客戶端對象。配置客戶端對象時,指定應用程序需要訪問的範圍,以及應用程序的 auth 端點的 URL,它將處理來自 OAuth 2.0 服務器的響應。

例如,此代碼請求對用戶的 Google Drive 進行只讀、離線訪問:

require 'google/apis/drive_v2'
require 'google/api_client/client_secrets'

client_secrets = Google::APIClient::ClientSecrets.load
auth_client = client_secrets.to_authorization
auth_client.update!(
  :scope => 'https://www.googleapis.com/auth/drive.metadata.readonly',
  :redirect_uri => 'http://www.example.com/oauth2callback',
  :additional_parameters => {
    "access_type" => "offline",         # offline access
    "include_granted_scopes" => "true"  # incremental auth
  }
)

您的應用程序使用客戶端對象來執行 OAuth 2.0 操作,例如生成授權請求 URL 並將訪問令牌應用於 HTTP 請求。

HTTP/REST

谷歌的OAuth 2.0終點是https://accounts.google.com/o/oauth2/v2/auth 。此端點只能通過 HTTPS 訪問。拒絕普通 HTTP 連接。

Google 授權服務器支持 Web 服務器應用程序的以下查詢字符串參數:

參數
client_id必需的

您的應用程序的客戶端 ID。你可以找到在這個值 API ConsoleCredentials page

redirect_uri必需的

確定用戶完成授權流程後 API 服務器將用戶重定向到何處。該值必須完全匹配授權的重定向的URI的OAuth 2.0用戶端,您可以在您的客戶機的配置的一個 API ConsoleCredentials page。如果此值不為所提供的匹配授權的重新導向URI client_id你會得到一個redirect_uri_mismatch錯誤。

注意, httphttps方案,案例,和斜線(' / ')必須全部匹配。

response_type必需的

確定 Google OAuth 2.0 端點是否返回授權代碼。

設置參數值code的Web服務器應用程序。

scope必需的

一個以空格分隔的範圍列表,用於標識您的應用程序可以代表用戶訪問的資源。這些值通知 Google 向用戶顯示的同意屏幕。

範圍使您的應用程序能夠僅請求訪問它需要的資源,同時還使用戶能夠控制他們授予您的應用程序的訪問權限。因此,請求的範圍數量與獲得用戶同意的可能性之間存在反比關係。

我們建議您的應用程序盡可能請求訪問上下文中的授權範圍。通過請求訪問用戶數據的情況下,通過增量授權,你幫助用戶更容易理解為什麼您的應用程序需要被請求的訪問。

access_type受到推崇的

指示當用戶不在瀏覽器時您的應用程序是否可以刷新訪問令牌。有效的參數值是online ,這是默認值,而offline

將該值設置為offline ,如果你的應用需要刷新訪問令牌,當用戶不存在於瀏覽器。這是本文檔後面描述的刷新訪問令牌的方法。該值指示谷歌授權服務器返回令牌的刷新令牌首次訪問您的應用程序交流的令牌的授權碼。

state受到推崇的

指定您的應用程序用於維護授權請求和授權服務器響應之間的狀態的任何字符串值。服務器返回您發送的精確值name=value的URL查詢組件對( ?對的) redirect_uri用戶同意後,或拒絕您的應用程序的訪問請求。

您可以將此參數用於多種用途,例如將用戶定向到應用程序中的正確資源、發送隨機數以及減少跨站點請求偽造。由於您的redirect_uri可以猜到,使用state值可以增加你保證傳入連接的認證請求的結果。如果您生成隨機字符串或對 cookie 的哈希值或捕獲客戶端狀態的其他值進行編碼,則可以驗證響應以額外確保請求和響應源自同一瀏覽器,從而防止跨站點等攻擊請求偽造。見ID連接文檔中如何創建並確認一個例子state令牌。

include_granted_scopes可選的

使應用程序能夠使用增量授權來請求訪問上下文中的其他範圍。如果這個參數的值設置為true和授權請求被批准,那麼新的訪問令牌也將覆蓋該用戶以前授予的應用程序訪問的任何範圍。見增量授權的示例部分。

login_hint可選的

如果您的應用程序知道哪個用戶正在嘗試進行身份驗證,它可以使用此參數向 Google 身份驗證服務器提供提示。服務器通過在登錄表單中預填電子郵件字段或選擇適當的多登錄會話,使用提示來簡化登錄流程。

設置參數值到電子郵件地址或sub標識符,這相當於用戶的谷歌ID。

prompt可選的

以空格分隔、區分大小寫的提示列表,以呈現給用戶。如果您不指定此參數,則僅在您的項目第一次請求訪問時才會提示用戶。見提示重新同意,以獲取更多信息。

可能的值為:

none不顯示任何身份驗證或同意屏幕。不得與其他值一起指定。
consent提示用戶同意。
select_account提示用戶選擇一個帳戶。

第 2 步:重定向到 Google 的 OAuth 2.0 服務器

將用戶重定向到 Google 的 OAuth 2.0 服務器以啟動身份驗證和授權過程。通常,當您的應用程序首先需要訪問用戶的數據時,就會發生這種情況。在的情況下,增量授權,當你的應用程序首先需要獲取額外的資源,它並沒有權限訪問這個步驟也發生。

PHP

  1. 生成谷歌的OAuth 2.0服務器的URL請求訪問:
    $auth_url = $client->createAuthUrl();
  2. 將用戶重定向到$auth_url
    header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));

Python

此示例顯示如何使用 Flask Web 應用程序框架將用戶重定向到授權 URL:

return flask.redirect(authorization_url)

紅寶石

  1. 生成谷歌的OAuth 2.0服務器的URL請求訪問:
    auth_uri = auth_client.authorization_uri.to_s
  2. 將用戶重定向到auth_uri

HTTP/REST

重定向到 Google 授權服務器的示例

下面顯示了一個示例 URL,為了便於閱讀,帶有換行符和空格。

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly&
 access_type=offline&
 include_granted_scopes=true&
 response_type=code&
 state=state_parameter_passthrough_value&
 redirect_uri=https%3A//oauth2.example.com/code&
 client_id=client_id

創建請求 URL 後,將用戶重定向到它。

Google 的 OAuth 2.0 服務器對用戶進行身份驗證並獲得用戶同意,讓您的應用程序訪問請求的範圍。使用您指定的重定向 URL 將響應發送回您的應用程序。

第 3 步:Google 提示用戶同意

在此步驟中,用戶決定是否授予您的應用程序請求的訪問權限。在此階段,Google 會顯示一個同意窗口,其中顯示您的應用程序的名稱以及它請求使用用戶授權憑據訪問的 Google API 服務以及要授予的訪問權限範圍的摘要。然後,用戶可以同意授予對您的應用程序請求的一個或多個範圍的訪問權限或拒絕該請求。

您的應用程序在此階段無需執行任何操作,因為它會等待來自 Google 的 OAuth 2.0 服務器的響應,指示是否授予任何訪問權限。該響應將在以下步驟中進行解釋。

錯誤

對 Google 的 OAuth 2.0 授權端點的請求可能會顯示面向用戶的錯誤消息,而不是預期的身份驗證和授權流程。下面列出了常見的錯誤代碼和建議的解決方法。

admin_policy_enforced

由於 Google Workspace 管理員的政策,Google 帳戶無法授權一個或多個請求的範圍。看到谷歌工作區管理員說明文章控制哪些第三方和內部應用程序訪問谷歌工作區數據有關,直到訪問被明確授予您的OAuth用戶端ID管理員可以如何限制對所有範圍或敏感和受限制的作用域的詳細信息。

disallowed_useragent

授權端點是由谷歌的不允許的嵌入式用戶代理內部顯示的OAuth 2.0政策

安卓

在打開的授權請求時,Android開發可能會遇到此錯誤消息android.webkit.WebView 。開發者應該使用的Android庫,如谷歌登錄Android版或OpenID基金會的AppAuth未為Android

當 Android 應用程序在嵌入式用戶代理中打開通用 Web 鏈接並且用戶從您的站點導航到 Google 的 OAuth 2.0 授權端點時,Web 開發人員可能會遇到此錯誤。開發者應該允許一般鏈接到操作系統,其中包括默認鏈路處理器打開Android應用程序鏈接的處理程序或默認瀏覽器應用程序。在Android的自定義選項卡庫也是支持的選項。

iOS

在打開的授權請求時,iOS和MacOS的開發商可能會遇到這個錯誤WKWebView 。開發者應該使用的iOS庫,如谷歌登錄在為iOS或OpenID基金會的AppAuth未適用於iOS

當 iOS 或 macOS 應用程序在嵌入式用戶代理中打開通用 Web 鏈接並且用戶從您的站點導航到 Google 的 OAuth 2.0 授權端點時,Web 開發人員可能會遇到此錯誤。開發者應該允許一般鏈接到操作系統,其中包括默認鏈路處理器打開通用鏈接處理程序或默認瀏覽器應用程序。該SFSafariViewController庫也是支持的選項。

org_internal

在請求的OAuth用戶端ID是項目限制在一個特定的訪問谷歌帳戶的一部分,谷歌雲組織。有關此配置選項的詳細信息,請參閱用戶類型的設置您的OAuth同意畫面幫助文章節。

redirect_uri_mismatch

redirect_uri在授權請求傳遞不匹配的OAuth用戶端ID被授權的重定向URI。審查授權的重定向URI的 Google API Console Credentials page

步驟 4:處理 OAuth 2.0 服務器響應

OAuth 2.0 服務器使用請求中指定的 URL 響應應用程序的訪問請求。

如果用戶批准訪問請求,則響應包含授權代碼。如果用戶不批准請求,則響應包含錯誤消息。返回給Web服務器的授權碼或錯誤信息出現在查詢字符串中,如下圖:

錯誤響應:

https://oauth2.example.com/auth?error=access_denied

授權碼響應:

https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7

OAuth 2.0 服務器響應示例

您可以通過單擊以下示例 URL 來測試此流程,該示例 URL 請求只讀訪問權限以查看 Google Drive 中文件的元數據:

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly&
 access_type=offline&
 include_granted_scopes=true&
 response_type=code&
 state=state_parameter_passthrough_value&
 redirect_uri=https%3A//oauth2.example.com/code&
 client_id=client_id

After completing the OAuth 2.0 flow, you should be redirected to http://localhost/oauth2callback , which will likely yield a 404 NOT FOUND error unless your local machine serves a file at that address. The next step provides more detail about the information returned in the URI when the user is redirected back to your application.

Step 5: Exchange authorization code for refresh and access tokens

After the web server receives the authorization code, it can exchange the authorization code for an access token.

PHP

To exchange an authorization code for an access token, use the authenticate method:

$client->authenticate($_GET['code']);

You can retrieve the access token with the getAccessToken method:

$access_token = $client->getAccessToken();

Python

On your callback page, use the google-auth library to verify the authorization server response. Then, use the flow.fetch_token method to exchange the authorization code in that response for an access token:

state = flask.session['state']
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'],
    state=state)
flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

authorization_response = flask.request.url
flow.fetch_token(authorization_response=authorization_response)

# Store the credentials in the session.
# ACTION ITEM for developers:
#     Store user's access and refresh tokens in your data store if
#     incorporating this code into your real app.
credentials = flow.credentials
flask.session['credentials'] = {
    'token': credentials.token,
    'refresh_token': credentials.refresh_token,
    'token_uri': credentials.token_uri,
    'client_id': credentials.client_id,
    'client_secret': credentials.client_secret,
    'scopes': credentials.scopes}

Ruby

To exchange an authorization code for an access token, use the fetch_access_token! method:

auth_client.code = auth_code
auth_client.fetch_access_token!

HTTP/REST

To exchange an authorization code for an access token, call the https://oauth2.googleapis.com/token endpoint and set the following parameters:

Fields
client_id The client ID obtained from the API ConsoleCredentials page.
client_secret The client secret obtained from the API ConsoleCredentials page.
code The authorization code returned from the initial request.
grant_type As defined in the OAuth 2.0 specification , this field's value must be set to authorization_code .
redirect_uri One of the redirect URIs listed for your project in the API ConsoleCredentials page for the given client_id .

The following snippet shows a sample request:

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

Google responds to this request by returning a JSON object that contains a short-lived access token and a refresh token. Note that the refresh token is only returned if your application set the access_type parameter to offline in the initial request to Google's authorization server .

The response contains the following fields:

Fields
access_token The token that your application sends to authorize a Google API request.
expires_in The remaining lifetime of the access token in seconds.
refresh_token A token that you can use to obtain a new access token. Refresh tokens are valid until the user revokes access. Again, this field is only present in this response if you set the access_type parameter to offline in the initial request to Google's authorization server.
scope The scopes of access granted by the access_token expressed as a list of space-delimited, case-sensitive strings.
token_type The type of token returned. At this time, this field's value is always set to Bearer .

The following snippet shows a sample response:

{
  "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in": 3920,
  "token_type": "Bearer",
  "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
  "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}

Calling Google APIs

PHP

Use the access token to call Google APIs by completing the following steps:

  1. If you need to apply an access token to a new Google_Client object—for example, if you stored the access token in a user session—use the setAccessToken method:
    $client->setAccessToken($access_token);
  2. Build a service object for the API that you want to call. You build a service object by providing an authorized Google_Client object to the constructor for the API you want to call. For example, to call the Drive API:
    $drive = new Google_Service_Drive($client);
  3. Make requests to the API service using the interface provided by the service object . For example, to list the files in the authenticated user's Google Drive:
    $files = $drive->files->listFiles(array())->getItems();

Python

After obtaining an access token, your application can use that token to authorize API requests on behalf of a given user account or service account. Use the user-specific authorization credentials to build a service object for the API that you want to call, and then use that object to make authorized API requests.

  1. Build a service object for the API that you want to call. You build a service object by calling the googleapiclient.discovery library's build method with the name and version of the API and the user credentials: For example, to call version 2 of the Drive API:
    from googleapiclient.discovery import build
    
    drive = build('drive', 'v2', credentials=credentials)
  2. Make requests to the API service using the interface provided by the service object . For example, to list the files in the authenticated user's Google Drive:
    files = drive.files().list().execute()

Ruby

Use the auth_client object to call Google APIs by completing the following steps:

  1. Build a service object for the API that you want to call. For example, to call version 2 of the Drive API:
    drive = Google::Apis::DriveV2::DriveService.new
  2. Set the credentials on the service:
    drive.authorization = auth_client
  3. Make requests to the API service using the interface provided by the service object . For example, to list the files in the authenticated user's Google Drive:
    files = drive.list_files

Alternately, authorization can be provided on a per-method basis by supplying the options parameter to a method:

files = drive.list_files(options: { authorization: auth_client })

HTTP/REST

After your application obtains an access token, you can use the token to make calls to a Google API on behalf of a given user account if the scope(s) of access required by the API have been granted. To do this, include the access token in a request to the API by including either an access_token query parameter or an Authorization HTTP header Bearer value. When possible, the HTTP header is preferable, because query strings tend to be visible in server logs. In most cases you can use a client library to set up your calls to Google APIs (for example, when calling the Drive Files API ).

You can try out all the Google APIs and view their scopes at the OAuth 2.0 Playground .

HTTP GET examples

A call to the drive.files endpoint (the Drive Files API) using the Authorization: Bearer HTTP header might look like the following. Note that you need to specify your own access token:

GET /drive/v2/files HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer access_token

Here is a call to the same API for the authenticated user using the access_token query string parameter:

GET https://www.googleapis.com/drive/v2/files?access_token=access_token

curl examples

You can test these commands with the curl command-line application. Here's an example that uses the HTTP header option (preferred):

curl -H "Authorization: Bearer access_token" https://www.googleapis.com/drive/v2/files

Or, alternatively, the query string parameter option:

curl https://www.googleapis.com/drive/v2/files?access_token=access_token

Complete example

The following example prints a JSON-formatted list of files in a user's Google Drive after the user authenticates and gives consent for the application to access the user's Drive metadata.

PHP

To run this example:

  1. In the API Console, add the URL of the local machine to the list of redirect URLs. For example, add http://localhost:8080 .
  2. Create a new directory and change to it. For example:
    mkdir ~/php-oauth2-example
    cd ~/php-oauth2-example
  3. Install the Google API Client Library for PHP using Composer :
    composer require google/apiclient:^2.0
  4. Create the files index.php and oauth2callback.php with the content below.
  5. Run the example with a web server configured to serve PHP. If you use PHP 5.4 or newer, you can use PHP's built-in test web server:
    php -S localhost:8080 ~/php-oauth2-example

index.php

<?php
require_once __DIR__.'/vendor/autoload.php';

session_start();

$client = new Google_Client();
$client->setAuthConfig('client_secrets.json');
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);

if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
  $client->setAccessToken($_SESSION['access_token']);
  $drive = new Google_Service_Drive($client);
  $files = $drive->files->listFiles(array())->getItems();
  echo json_encode($files);
} else {
  $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

oauth2callback.php

<?php
require_once __DIR__.'/vendor/autoload.php';

session_start();

$client = new Google_Client();
$client->setAuthConfigFile('client_secrets.json');
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);

if (! isset($_GET['code'])) {
  $auth_url = $client->createAuthUrl();
  header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
  $client->authenticate($_GET['code']);
  $_SESSION['access_token'] = $client->getAccessToken();
  $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

Python

This example uses the Flask framework. It runs a web application at http://localhost:8080 that lets you test the OAuth 2.0 flow. If you go to that URL, you should see four links:

  • Test an API request: This link points to a page that tries to execute a sample API request. If necessary, it starts the authorization flow. If successful, the page displays the API response.
  • Test the auth flow directly: This link points to a page that tries to send the user through the authorization flow . The app requests permission to submit authorized API requests on the user's behalf.
  • Revoke current credentials: This link points to a page that revokes permissions that the user has already granted to the application.
  • Clear Flask session credentials: This link clears authorization credentials that are stored in the Flask session. This lets you see what would happen if a user who had already granted permission to your app tried to execute an API request in a new session. It also lets you see the API response your app would get if a user had revoked permissions granted to your app, and your app still tried to authorize a request with a revoked access token.
# -*- coding: utf-8 -*-

import os
import flask
import requests

import google.oauth2.credentials
import google_auth_oauthlib.flow
import googleapiclient.discovery

# This variable specifies the name of a file that contains the OAuth 2.0
# information for this application, including its client_id and client_secret.
CLIENT_SECRETS_FILE = "client_secret.json"

# This OAuth 2.0 access scope allows for full read/write access to the
# authenticated user's account and requires requests to use an SSL connection.
SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly']
API_SERVICE_NAME = 'drive'
API_VERSION = 'v2'

app = flask.Flask(__name__)
# Note: A secret key is included in the sample so that it works.
# If you use this code in your application, replace this with a truly secret
# key. See https://flask.palletsprojects.com/quickstart/#sessions.
app.secret_key = 'REPLACE ME - this value is here as a placeholder.'


@app.route('/')
def index():
  return print_index_table()


@app.route('/test')
def test_api_request():
  if 'credentials' not in flask.session:
    return flask.redirect('authorize')

  # Load credentials from the session.
  credentials = google.oauth2.credentials.Credentials(
      **flask.session['credentials'])

  drive = googleapiclient.discovery.build(
      API_SERVICE_NAME, API_VERSION, credentials=credentials)

  files = drive.files().list().execute()

  # Save credentials back to session in case access token was refreshed.
  # ACTION ITEM: In a production app, you likely want to save these
  #              credentials in a persistent database instead.
  flask.session['credentials'] = credentials_to_dict(credentials)

  return flask.jsonify(**files)


@app.route('/authorize')
def authorize():
  # Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps.
  flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
      CLIENT_SECRETS_FILE, scopes=SCOPES)

  # The URI created here must exactly match one of the authorized redirect URIs
  # for the OAuth 2.0 client, which you configured in the API Console. If this
  # value doesn't match an authorized URI, you will get a 'redirect_uri_mismatch'
  # error.
  flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

  authorization_url, state = flow.authorization_url(
      # Enable offline access so that you can refresh an access token without
      # re-prompting the user for permission. Recommended for web server apps.
      access_type='offline',
      # Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes='true')

  # Store the state so the callback can verify the auth server response.
  flask.session['state'] = state

  return flask.redirect(authorization_url)


@app.route('/oauth2callback')
def oauth2callback():
  # Specify the state when creating the flow in the callback so that it can
  # verified in the authorization server response.
  state = flask.session['state']

  flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
      CLIENT_SECRETS_FILE, scopes=SCOPES, state=state)
  flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

  # Use the authorization server's response to fetch the OAuth 2.0 tokens.
  authorization_response = flask.request.url
  flow.fetch_token(authorization_response=authorization_response)

  # Store credentials in the session.
  # ACTION ITEM: In a production app, you likely want to save these
  #              credentials in a persistent database instead.
  credentials = flow.credentials
  flask.session['credentials'] = credentials_to_dict(credentials)

  return flask.redirect(flask.url_for('test_api_request'))


@app.route('/revoke')
def revoke():
  if 'credentials' not in flask.session:
    return ('You need to <a href="/authorize">authorize</a> before ' +
            'testing the code to revoke credentials.')

  credentials = google.oauth2.credentials.Credentials(
    **flask.session['credentials'])

  revoke = requests.post('https://oauth2.googleapis.com/revoke',
      params={'token': credentials.token},
      headers = {'content-type': 'application/x-www-form-urlencoded'})

  status_code = getattr(revoke, 'status_code')
  if status_code == 200:
    return('Credentials successfully revoked.' + print_index_table())
  else:
    return('An error occurred.' + print_index_table())


@app.route('/clear')
def clear_credentials():
  if 'credentials' in flask.session:
    del flask.session['credentials']
  return ('Credentials have been cleared.<br><br>' +
          print_index_table())


def credentials_to_dict(credentials):
  return {'token': credentials.token,
          'refresh_token': credentials.refresh_token,
          'token_uri': credentials.token_uri,
          'client_id': credentials.client_id,
          'client_secret': credentials.client_secret,
          'scopes': credentials.scopes}

def print_index_table():
  return ('<table>' +
          '<tr><td><a href="/test">Test an API request</a></td>' +
          '<td>Submit an API request and see a formatted JSON response. ' +
          '    Go through the authorization flow if there are no stored ' +
          '    credentials for the user.</td></tr>' +
          '<tr><td><a href="/authorize">Test the auth flow directly</a></td>' +
          '<td>Go directly to the authorization flow. If there are stored ' +
          '    credentials, you still might not be prompted to reauthorize ' +
          '    the application.</td></tr>' +
          '<tr><td><a href="/revoke">Revoke current credentials</a></td>' +
          '<td>Revoke the access token associated with the current user ' +
          '    session. After revoking credentials, if you go to the test ' +
          '    page, you should see an <code>invalid_grant</code> error.' +
          '</td></tr>' +
          '<tr><td><a href="/clear">Clear Flask session credentials</a></td>' +
          '<td>Clear the access token currently stored in the user session. ' +
          '    After clearing the token, if you <a href="/test">test the ' +
          '    API request</a> again, you should go back to the auth flow.' +
          '</td></tr></table>')


if __name__ == '__main__':
  # When running locally, disable OAuthlib's HTTPs verification.
  # ACTION ITEM for developers:
  #     When running in production *do not* leave this option enabled.
  os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'

  # Specify a hostname and port that are set as a valid redirect URI
  # for your API project in the Google API Console.
  app.run('localhost', 8080, debug=True)

Ruby

This example uses the Sinatra framework.

require 'google/apis/drive_v2'
require 'google/api_client/client_secrets'
require 'json'
require 'sinatra'

enable :sessions
set :session_secret, 'setme'

get '/' do
  unless session.has_key?(:credentials)
    redirect to('/oauth2callback')
  end
  client_opts = JSON.parse(session[:credentials])
  auth_client = Signet::OAuth2::Client.new(client_opts)
  drive = Google::Apis::DriveV2::DriveService.new
  files = drive.list_files(options: { authorization: auth_client })
  "<pre>#{JSON.pretty_generate(files.to_h)}</pre>"
end

get '/oauth2callback' do
  client_secrets = Google::APIClient::ClientSecrets.load
  auth_client = client_secrets.to_authorization
  auth_client.update!(
    :scope => 'https://www.googleapis.com/auth/drive.metadata.readonly',
    :redirect_uri => url('/oauth2callback'))
  if request['code'] == nil
    auth_uri = auth_client.authorization_uri.to_s
    redirect to(auth_uri)
  else
    auth_client.code = request['code']
    auth_client.fetch_access_token!
    auth_client.client_secret = nil
    session[:credentials] = auth_client.to_json
    redirect to('/')
  end
end

HTTP/REST

This Python example uses the Flask framework and the Requests library to demonstrate the OAuth 2.0 web flow. We recommend using the Google API Client Library for Python for this flow. (The example in the Python tab does use the client library.)

import json

import flask
import requests


app = flask.Flask(__name__)

CLIENT_ID = '123456789.apps.googleusercontent.com'
CLIENT_SECRET = 'abc123'  # Read from a file or environmental variable in a real app
SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly'
REDIRECT_URI = 'http://example.com/oauth2callback'


@app.route('/')
def index():
  if 'credentials' not in flask.session:
    return flask.redirect(flask.url_for('oauth2callback'))
  credentials = json.loads(flask.session['credentials'])
  if credentials['expires_in'] <= 0:
    return flask.redirect(flask.url_for('oauth2callback'))
  else:
    headers = {'Authorization': 'Bearer {}'.format(credentials['access_token'])}
    req_uri = 'https://www.googleapis.com/drive/v2/files'
    r = requests.get(req_uri, headers=headers)
    return r.text


@app.route('/oauth2callback')
def oauth2callback():
  if 'code' not in flask.request.args:
    auth_uri = ('https://accounts.google.com/o/oauth2/v2/auth?response_type=code'
                '&client_id={}&redirect_uri={}&scope={}').format(CLIENT_ID, REDIRECT_URI, SCOPE)
    return flask.redirect(auth_uri)
  else:
    auth_code = flask.request.args.get('code')
    data = {'code': auth_code,
            'client_id': CLIENT_ID,
            'client_secret': CLIENT_SECRET,
            'redirect_uri': REDIRECT_URI,
            'grant_type': 'authorization_code'}
    r = requests.post('https://oauth2.googleapis.com/token', data=data)
    flask.session['credentials'] = r.text
    return flask.redirect(flask.url_for('index'))


if __name__ == '__main__':
  import uuid
  app.secret_key = str(uuid.uuid4())
  app.debug = False
  app.run()

Redirect URI validation rules

Google applies the following validation rules to redirect URIs in order to help developers keep their applications secure. Your redirect URIs must adhere to these rules. See RFC 3986 section 3 for the definition of domain, host, path, query, scheme and userinfo, mentioned below.

Validation rules
Scheme

Redirect URIs must use the HTTPS scheme, not plain HTTP. Localhost URIs (including localhost IP address URIs) are exempt from this rule.

Host

Hosts cannot be raw IP addresses. Localhost IP addresses are exempted from this rule.

Domain
  • Host TLDs ( Top Level Domains ) must belong to the public suffix list .
  • Host domains cannot be “googleusercontent.com” .
  • Redirect URIs cannot contain URL shortener domains (eg goo.gl ) unless the app owns the domain. Furthermore, if an app that owns a shortener domain chooses to redirect to that domain, that redirect URI must either contain “/google-callback/” in its path or end with “/google-callback” .
  • Userinfo

    Redirect URIs cannot contain the userinfo subcomponent.

    Path

    Redirect URIs cannot contain a path traversal (also called directory backtracking), which is represented by an “/..” or “\..” or their URL encoding.

    Query

    Redirect URIs cannot contain open redirects .

    Fragment

    Redirect URIs cannot contain the fragment component.

    Characters Redirect URIs cannot contain certain characters including:
    • Wildcard characters ( '*' )
    • Non-printable ASCII characters
    • Invalid percent encodings (any percent encoding that does not follow URL-encoding form of a percent sign followed by two hexadecimal digits)
    • Null characters (an encoded NULL character, eg, %00 , %C0%80 )

    Incremental authorization

    In the OAuth 2.0 protocol, your app requests authorization to access resources, which are identified by scopes. It is considered a best user-experience practice to request authorization for resources at the time you need them. To enable that practice, Google's authorization server supports incremental authorization. This feature lets you request scopes as they are needed and, if the user grants permission for the new scope, returns an authorization code that may be exchanged for a token containing all scopes the user has granted the project.

    For example, an app that lets people sample music tracks and create mixes might need very few resources at sign-in time, perhaps nothing more than the name of the person signing in. However, saving a completed mix would require access to their Google Drive. Most people would find it natural if they only were asked for access to their Google Drive at the time the app actually needed it.

    In this case, at sign-in time the app might request the openid and profile scopes to perform basic sign-in, and then later request the https://www.googleapis.com/auth/drive.file scope at the time of the first request to save a mix.

    To implement incremental authorization, you complete the normal flow for requesting an access token but make sure that the authorization request includes previously granted scopes. This approach allows your app to avoid having to manage multiple access tokens.

    The following rules apply to an access token obtained from an incremental authorization:

    • The token can be used to access resources corresponding to any of the scopes rolled into the new, combined authorization.
    • When you use the refresh token for the combined authorization to obtain an access token, the access token represents the combined authorization and can be used for any of the scope values included in the response.
    • The combined authorization includes all scopes that the user granted to the API project even if the grants were requested from different clients. For example, if a user granted access to one scope using an application's desktop client and then granted another scope to the same application via a mobile client, the combined authorization would include both scopes.
    • If you revoke a token that represents a combined authorization, access to all of that authorization's scopes on behalf of the associated user are revoked simultaneously.

    The language-specific code samples in Step 1: Set authorization parameters and the sample HTTP/REST redirect URL in Step 2: Redirect to Google's OAuth 2.0 server all use incremental authorization. The code samples below also show the code that you need to add to use incremental authorization.

    PHP

    $client->setIncludeGrantedScopes(true);

    Python

    In Python, set the include_granted_scopes keyword argument to true to ensure that an authorization request includes previously granted scopes. It is very possible that include_granted_scopes will not be the only keyword argument that you set, as shown in the example below.

    authorization_url, state = flow.authorization_url(
        # Enable offline access so that you can refresh an access token without
        # re-prompting the user for permission. Recommended for web server apps.
        access_type='offline',
        # Enable incremental authorization. Recommended as a best practice.
        include_granted_scopes='true')

    Ruby

    auth_client.update!(
      :additional_parameters => {"include_granted_scopes" => "true"}
    )

    HTTP/REST

    GET https://accounts.google.com/o/oauth2/v2/auth?
      client_id=your_client_id&
      response_type=code&
      state=state_parameter_passthrough_value&
      scope=https%3A//www.googleapis.com/auth/drive.file&
      redirect_uri=https%3A//oauth2.example.com/code&
      prompt=consent&
      include_granted_scopes=true

    Refreshing an access token (offline access)

    Access tokens periodically expire and become invalid credentials for a related API request. You can refresh an access token without prompting the user for permission (including when the user is not present) if you requested offline access to the scopes associated with the token.

    • If you use a Google API Client Library, the client object refreshes the access token as needed as long as you configure that object for offline access.
    • If you are not using a client library, you need to set the access_type HTTP query parameter to offline when redirecting the user to Google's OAuth 2.0 server . In that case, Google's authorization server returns a refresh token when you exchange an authorization code for an access token. Then, if the access token expires (or at any other time), you can use a refresh token to obtain a new access token.

    Requesting offline access is a requirement for any application that needs to access a Google API when the user is not present. For example, an app that performs backup services or executes actions at predetermined times needs to be able to refresh its access token when the user is not present. The default style of access is called online .

    Server-side web applications, installed applications, and devices all obtain refresh tokens during the authorization process. Refresh tokens are not typically used in client-side (JavaScript) web applications.

    PHP

    If your application needs offline access to a Google API, set the API client's access type to offline :

    $client->setAccessType("offline");

    After a user grants offline access to the requested scopes, you can continue to use the API client to access Google APIs on the user's behalf when the user is offline. The client object will refresh the access token as needed.

    Python

    In Python, set the access_type keyword argument to offline to ensure that you will be able to refresh the access token without having to re-prompt the user for permission. It is very possible that access_type will not be the only keyword argument that you set, as shown in the example below.

    authorization_url, state = flow.authorization_url(
        # Enable offline access so that you can refresh an access token without
        # re-prompting the user for permission. Recommended for web server apps.
        access_type='offline',
        # Enable incremental authorization. Recommended as a best practice.
        include_granted_scopes='true')

    After a user grants offline access to the requested scopes, you can continue to use the API client to access Google APIs on the user's behalf when the user is offline. The client object will refresh the access token as needed.

    Ruby

    If your application needs offline access to a Google API, set the API client's access type to offline :

    auth_client.update!(
      :additional_parameters => {"access_type" => "offline"}
    )

    After a user grants offline access to the requested scopes, you can continue to use the API client to access Google APIs on the user's behalf when the user is offline. The client object will refresh the access token as needed.

    HTTP/REST

    To refresh an access token, your application sends an HTTPS POST request to Google's authorization server ( https://oauth2.googleapis.com/token ) that includes the following parameters:

    Fields
    client_id The client ID obtained from the API Console.
    client_secret The client secret obtained from the API Console.
    grant_type As defined in the OAuth 2.0 specification , this field's value must be set to refresh_token .
    refresh_token The refresh token returned from the authorization code exchange.

    The following snippet shows a sample request:

    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

    As long as the user has not revoked the access granted to the application, the token server returns a JSON object that contains a new access token. The following snippet shows a sample response:

    {
      "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
      "expires_in": 3920,
      "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
      "token_type": "Bearer"
    }

    Note that there are limits on the number of refresh tokens that will be issued; one limit per client/user combination, and another per user across all clients. You should save refresh tokens in long-term storage and continue to use them as long as they remain valid. If your application requests too many refresh tokens, it may run into these limits, in which case older refresh tokens will stop working.

    Revoking a token

    In some cases a user may wish to revoke access given to an application. A user can revoke access by visiting Account Settings . See the Remove site or app access section of the Third-party sites & apps with access to your account support document for more information.

    It is also possible for an application to programmatically revoke the access given to it. Programmatic revocation is important in instances where a user unsubscribes, removes an application, or the API resources required by an app have significantly changed. In other words, part of the removal process can include an API request to ensure the permissions previously granted to the application are removed.

    PHP

    To programmatically revoke a token, call revokeToken() :

    $client->revokeToken();

    Python

    To programmatically revoke a token, make a request to https://oauth2.googleapis.com/revoke that includes the token as a parameter and sets the Content-Type header:

    requests.post('https://oauth2.googleapis.com/revoke',
        params={'token': credentials.token},
        headers = {'content-type': 'application/x-www-form-urlencoded'})

    Ruby

    To programmatically revoke a token, make an HTTP request to the oauth2.revoke endpoint:

    uri = URI('https://oauth2.googleapis.com/revoke')
    response = Net::HTTP.post_form(uri, 'token' => auth_client.access_token)
    

    The token can be an access token or a refresh token. If the token is an access token and it has a corresponding refresh token, the refresh token will also be revoked.

    If the revocation is successfully processed, then the status code of the response is 200 . For error conditions, a status code 400 is returned along with an error code.

    HTTP/REST

    To programmatically revoke a token, your application makes a request to https://oauth2.googleapis.com/revoke and includes the token as a parameter:

    curl -d -X -POST --header "Content-type:application/x-www-form-urlencoded" \
            https://oauth2.googleapis.com/revoke?token={token}

    The token can be an access token or a refresh token. If the token is an access token and it has a corresponding refresh token, the refresh token will also be revoked.

    If the revocation is successfully processed, then the HTTP status code of the response is 200 . For error conditions, an HTTP status code 400 is returned along with an error code.