Utilizzo di OAuth 2.0 per applicazioni server web

Questo documento spiega come le applicazioni server web utilizzano le librerie client delle API di Google o gli endpoint OAuth 2.0 di Google per implementare l'autorizzazione OAuth 2.0 per accedere alle API di Google.

OAuth 2.0 consente agli utenti di condividere dati specifici con un'applicazione, mantenendo privati i propri nomi utente, le password e altre informazioni. Ad esempio, un'applicazione può utilizzare OAuth 2.0 per ottenere l'autorizzazione degli utenti ad archiviare file nei loro Google Drive.

Questo flusso OAuth 2.0 è specifico per l'autorizzazione utente. È progettato per applicazioni che possono memorizzare informazioni riservate e mantenere lo stato. Un'applicazione del server web correttamente autorizzata può accedere a un'API mentre l'utente interagisce con l'applicazione o dopo che l'utente ha abbandonato l'applicazione.

Le applicazioni del server web utilizzano spesso anche gli account di servizio per autorizzare le richieste API, in particolare quando chiamano le API Cloud per accedere ai dati basati su progetto anziché a quelli specifici dell'utente. Le applicazioni del server web possono utilizzare gli account di servizio in combinazione con l'autorizzazione utente.

Librerie client

Gli esempi specifici per i vari linguaggi in questa pagina utilizzano le librerie client delle API di Google per implementare l'autorizzazione OAuth 2.0. Per eseguire gli esempi di codice, devi prima installare la libreria client per il tuo linguaggio.

Quando utilizzi una libreria client delle API di Google per gestire il flusso OAuth 2.0 della tua applicazione, la libreria client esegue molte azioni che altrimenti l'applicazione dovrebbe gestire autonomamente. Ad esempio, determina quando l'applicazione può utilizzare o aggiornare i token di accesso archiviati, nonché quando deve riacquisire il consenso. La libreria client genera anche URL di reindirizzamento corretti e aiuta a implementare gestori di reindirizzamento che scambiano codici di autorizzazione con token di accesso.

Le librerie client delle API di Google per le applicazioni lato server sono disponibili per i seguenti linguaggi:

Prerequisiti

Abilita le API per il tuo progetto

Qualsiasi applicazione che chiama le API di Google deve attivarle in API Console.

Per attivare un'API per il tuo progetto:

  1. Open the API Library in Google API Console.
  2. If prompted, select a project, or create a new one.
  3. La pagina API Library elenca tutte le API disponibili, raggruppate per famiglia di prodotti e popolarità. Se l'API che vuoi attivare non è visibile nell'elenco, utilizza la ricerca per trovarla o fai clic su Visualizza tutto nella famiglia di prodotti a cui appartiene.
  4. Seleziona l'API che vuoi attivare, poi fai clic sul pulsante Attiva.
  5. If prompted, enable billing.
  6. If prompted, read and accept the API's Terms of Service.

Crea le credenziali di autorizzazione

Qualsiasi applicazione che utilizza OAuth 2.0 per accedere alle API di Google deve disporre di credenziali di autorizzazione che identificano l'applicazione per il server OAuth 2.0 di Google. I passaggi riportati di seguito spiegano come creare le credenziali per il progetto. Le applicazioni possono quindi utilizzare le credenziali per accedere alle API che hai attivato per il progetto.

  1. Go to the Credentials page.
  2. Fai clic su Crea credenziali > ID client OAuth.
  3. Seleziona il tipo di applicazione Applicazione web.
  4. Compila il modulo e fai clic su Crea. Le applicazioni che utilizzano linguaggi e framework come PHP, Java, Python, Ruby e .NET devono specificare URI di reindirizzamento autorizzati. Gli URI di reindirizzamento sono gli endpoint a cui il server OAuth 2.0 può inviare risposte. Questi endpoint devono rispettare le regole di convalida di Google.

    Per i test, puoi specificare URI che fanno riferimento alla macchina locale, ad esempio http://localhost:8080. Tenendo presente questo, tieni presente che tutti gli esempi in questo documento utilizzano http://localhost:8080 come URI di reindirizzamento.

    Ti consigliamo di progettare gli endpoint di autenticazione della tua app in modo che la tua applicazione non esponga i codici di autorizzazione ad altre risorse nella pagina.

Dopo aver creato le credenziali, scarica il file client_secret.json da API Console. Memorizza il file in una posizione a cui solo la tua applicazione può accedere.

Identificare gli ambiti di accesso

Gli ambiti consentono alla tua applicazione di richiedere l'accesso solo alle risorse di cui ha bisogno, consentendo inoltre agli utenti di controllare la quantità di accesso concessa alla tua applicazione. Pertanto, potrebbe esserci una relazione inversa tra il numero di ambiti richiesti e la probabilità di ottenere il consenso dell'utente.

Prima di iniziare a implementare l'autorizzazione OAuth 2.0, ti consigliamo di identificare gli ambiti a cui la tua app avrà bisogno di accedere.

Ti consigliamo inoltre di richiedere l'accesso agli ambiti di autorizzazione tramite una procedura di autorizzazione incrementale, in cui l'applicazione richiede l'accesso ai dati utente nel contesto. Questa best practice aiuta gli utenti a comprendere più facilmente perché la tua applicazione ha bisogno dell'accesso richiesto.

Il documento Ambiti API OAuth 2.0 contiene un elenco completo degli ambiti che potresti utilizzare per accedere alle API di Google.

Requisiti specifici per lingua

Per eseguire uno degli esempi di codice in questo documento, devi disporre di un Account Google, dell'accesso a internet e di un browser web. Se utilizzi una delle librerie client dell'API, consulta anche i requisiti specifici per i vari linguaggi riportati di seguito.

PHP

Per eseguire gli esempi di codice PHP in questo documento, ti serviranno:

  • PHP 8.0 o versioni successive con interfaccia a riga di comando (CLI) ed estensione JSON installate.
  • Lo strumento di gestione delle dipendenze di Composer.
  • La libreria client delle API Google per PHP:

    composer require google/apiclient:^2.15.0

Per saperne di più, consulta la libreria client delle API di Google per PHP.

Python

Per eseguire gli esempi di codice Python in questo documento, ti serviranno:

  • Python 3.7 o versioni successive
  • Lo strumento di gestione dei pacchetti pip.
  • La versione 2.0 della libreria client delle API di Google per Python:
    pip install --upgrade google-api-python-client
  • google-auth, google-auth-oauthlib e google-auth-httplib2 per l'autorizzazione utente.
    pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2
  • Il framework per applicazioni web Python Flask.
    pip install --upgrade flask
  • La libreria HTTP requests.
    pip install --upgrade requests

Esamina la release note della libreria client Python dell'API di Google se non riesci ad eseguire l'upgrade di Python e consulta la guida alla migrazione associata.

Ruby

Per eseguire gli esempi di codice Ruby in questo documento, ti serviranno:

  • Ruby 2.6 o versioni successive
  • La libreria di autenticazione Google per Ruby:

    gem install googleauth
  • Le librerie client per le API di Google Drive e Calendar:

    gem install google-apis-drive_v3 google-apis-calendar_v3
  • Il framework per applicazioni web Ruby Sinatra.

    gem install sinatra

Node.js

Per eseguire gli esempi di codice Node.js in questo documento, devi disporre di:

  • La versione LTS di manutenzione, la versione LTS attiva o la versione corrente di Node.js.
  • Il client Node.js per le API di Google:

    npm install googleapis crypto express express-session

HTTP/REST

Non è necessario installare librerie per poter chiamare direttamente gli endpoint OAuth 2.0.

Ottenere i token di accesso OAuth 2.0

I passaggi che seguono mostrano come la tua applicazione interagisce con il server OAuth 2.0 di Google per ottenere il consenso di un utente a eseguire una richiesta API per suo conto. La tua applicazione deve disporre di questo consenso prima di poter eseguire una richiesta all'API Google che richiede l'autorizzazione dell'utente.

L'elenco seguente riassume rapidamente questi passaggi:

  1. L'applicazione identifica le autorizzazioni di cui ha bisogno.
  2. L'applicazione reindirizza l'utente a Google insieme all'elenco delle autorizzazioni richieste.
  3. L'utente decide se concedere le autorizzazioni alla tua applicazione.
  4. L'applicazione scopre cosa ha deciso l'utente.
  5. Se l'utente ha concesso le autorizzazioni richieste, l'applicazione recupera i token necessari per effettuare richieste API per conto dell'utente.

Passaggio 1: imposta i parametri di autorizzazione

Il primo passaggio consiste nel creare la richiesta di autorizzazione. Questa richiesta imposta i parametri che identificano la tua applicazione e definiscono le autorizzazioni che all'utente verrà chiesto di concedere alla tua applicazione.

  • Se utilizzi una libreria client Google per l'autenticazione e l'autorizzazione OAuth 2.0, crea e configura un oggetto che definisce questi parametri.
  • Se chiami direttamente l'endpoint OAuth 2.0 di Google, generi un URL e imposti i parametri su quell'URL.

Le schede riportate di seguito definiscono i parametri di autorizzazione supportati per le applicazioni del server web. Gli esempi specifici per ciascun linguaggio mostrano anche come utilizzare una libreria client o una libreria di autorizzazione per configurare un oggetto che imposta questi parametri.

PHP

Il seguente snippet di codice crea un oggetto Google\Client(), che definisce i parametri nella richiesta di autorizzazione.

Questo oggetto utilizza le informazioni del file client_secret.json per identificare la tua applicazione. Per saperne di più su questo file, consulta la sezione sulla creazione delle credenziali di autorizzazione. L'oggetto identifica anche gli ambiti per i quali la tua applicazione richiede l'autorizzazione di accesso e l'URL dell'endpoint di autenticazione dell'applicazione, che gestirà la risposta del server OAuth 2.0 di Google. Infine, il codice imposta i parametri facoltativi access_type e include_granted_scopes.

Ad esempio, questo codice richiede l'accesso offline di sola lettura ai metadati di Google Drive e agli eventi di Calendar di un utente:

use Google\Client;

$client = new Client();

// Required, call the setAuthConfig function to load authorization credentials from
// client_secret.json file.
$client->setAuthConfig('client_secret.json');

// Required, to set the scope value, call the addScope function
$client->addScope([Google\Service\Drive::DRIVE_METADATA_READONLY, Google\Service\Calendar::CALENDAR_READONLY]);

// Required, call the setRedirectUri function to specify a valid redirect URI for the
// provided client_id
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');

// Recommended, 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');

// Recommended, call the setState function. Using a state value can increase your assurance that
// an incoming connection is the result of an authentication request.
$client->setState($sample_passthrough_value);

// Optional, if your application knows which user is trying to authenticate, it can use this
// parameter to provide a hint to the Google Authentication Server.
$client->setLoginHint('hint@example.com');

// Optional, call the setPrompt function to set "consent" will prompt the user for consent
$client->setPrompt('consent');

// Optional, call the setIncludeGrantedScopes function with true to enable incremental
// authorization
$client->setIncludeGrantedScopes(true);

Python

Il seguente snippet di codice utilizza il modulo google-auth-oauthlib.flow per creare la richiesta di autorizzazione.

Il codice crea un oggetto Flow che identifica la tua applicazione utilizzando le informazioni del file client_secret.json che hai scaricato dopo aver creato le credenziali di autorizzazione. L'oggetto identifica inoltre gli ambiti per i quali l'applicazione richiede l'autorizzazione di accesso e l'URL dell'endpoint di autenticazione dell'applicazione, che gestirà la risposta del server OAuth 2.0 di Google. Infine, il codice imposta i parametri facoltativi access_type e include_granted_scopes.

Ad esempio, questo codice richiede l'accesso offline di sola lettura ai metadati di Google Drive e agli eventi di Calendar di un utente:

import google.oauth2.credentials
import google_auth_oauthlib.flow

# Required, call the from_client_secrets_file method to retrieve the client ID from a
# client_secret.json file. The client ID (from that file) and access scopes are required. (You can
# also use the from_client_config method, which passes the client configuration as it originally
# appeared in a client secrets file but doesn't access the file itself.)
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file('client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly',
            'https://www.googleapis.com/auth/calendar.readonly'])

# Required, 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(
    # Recommended, 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',
    # Optional, enable incremental authorization. Recommended as a best practice.
    include_granted_scopes='true',
    # Optional, if your application knows which user is trying to authenticate, it can use this
    # parameter to provide a hint to the Google Authentication Server.
    login_hint='hint@example.com',
    # Optional, set prompt to 'consent' will prompt the user for consent
    prompt='consent')

Ruby

Utilizza il file client_secrets.json che hai creato per configurare un oggetto client nella tua applicazione. Quando configuri un oggetto client, specifichi gli ambiti a cui deve accedere la tua applicazione, insieme all'URL dell'endpoint di autenticazione dell'applicazione, che gestirà la risposta del server OAuth 2.0.

Ad esempio, questo codice richiede l'accesso offline di sola lettura ai metadati di Google Drive e agli eventi di Calendar di un utente:

require 'googleauth'
require 'googleauth/web_user_authorizer'
require 'googleauth/stores/redis_token_store'

require 'google/apis/drive_v3'
require 'google/apis/calendar_v3'

# Required, call the from_file method to retrieve the client ID from a
# client_secret.json file.
client_id = Google::Auth::ClientId.from_file('/path/to/client_secret.json')

# Required, scope value 
# Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar.
scope = ['Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY',
         'Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY']

# Required, Authorizers require a storage instance to manage long term persistence of
# access and refresh tokens.
token_store = Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new)

# Required, 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.
callback_uri = '/oauth2callback'

# To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI
# from the client_secret.json file. To get these credentials for your application, visit
# https://console.cloud.google.com/apis/credentials.
authorizer = Google::Auth::WebUserAuthorizer.new(client_id, scope,
                                                token_store, callback_uri)

L'applicazione utilizza l'oggetto client per eseguire operazioni OAuth 2.0, ad esempio generare URL di richiesta di autorizzazione e applicare token di accesso alle richieste HTTP.

Node.js

Il seguente snippet di codice crea un oggetto google.auth.OAuth2, che definisce i parametri nella richiesta di autorizzazione.

Questo oggetto utilizza le informazioni del file client_secret.json per identificare la tua applicazione. Per chiedere all'utente le autorizzazioni per recuperare un token di accesso, reindirizzalo a una pagina di consenso. Per creare un URL di pagina per il consenso:

const {google} = require('googleapis');
const crypto = require('crypto');
const express = require('express');
const session = require('express-session');

/**
 * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI
 * from the client_secret.json file. To get these credentials for your application, visit
 * https://console.cloud.google.com/apis/credentials.
 */
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar.
const scopes = [
  'https://www.googleapis.com/auth/drive.metadata.readonly',
  'https://www.googleapis.com/auth/calendar.readonly'
];

// Generate a secure random state value.
const state = crypto.randomBytes(32).toString('hex');

// Store state in the session
req.session.state = state;

// Generate a url that asks permissions for the Drive activity and Google Calendar scope
const authorizationUrl = oauth2Client.generateAuthUrl({
  // 'online' (default) or 'offline' (gets refresh_token)
  access_type: 'offline',
  /** Pass in the scopes array defined above.
    * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
  scope: scopes,
  // Enable incremental authorization. Recommended as a best practice.
  include_granted_scopes: true,
  // Include the state parameter to reduce the risk of CSRF attacks.
  state: state
});

Nota importante: refresh_token viene restituito solo alla prima autorizzazione. Ulteriori dettagli sono disponibili qui.

HTTP/REST

L'endpoint OAuth 2.0 di Google si trova all'indirizzo https://accounts.google.com/o/oauth2/v2/auth. Questo endpoint è accessibile solo tramite HTTPS. Le connessioni HTTP non protette vengono rifiutate.

Il server di autorizzazione di Google supporta i seguenti parametri di stringa di query per le applicazioni di server web:

Parametri
client_id Obbligatorio

L'ID client della tua applicazione. Puoi trovare questo valore in API Console Credentials page.

redirect_uri Obbligatorio

Determina dove il server API reindirizza l'utente dopo che l'utente ha completato il flusso di autorizzazione. Il valore deve corrispondere esattamente a uno degli URI di reindirizzamento autorizzati per il client OAuth 2.0, che hai configurato in API Console Credentials pagedel client. Se questo valore non corrisponde a un URI di reindirizzamento autorizzato per il client_id fornito, verrà visualizzato un errore redirect_uri_mismatch.

Tieni presente che lo schema, le maiuscole e la barra finale http o https ('/') devono corrispondere.

response_type Obbligatorio

Determina se l'endpoint OAuth 2.0 di Google restituisce un codice di autorizzazione.

Imposta il valore del parametro su code per le applicazioni del server web.

scope Obbligatorio

Un elenco di ambiti delimitati da spazi che identificano le risorse a cui la tua applicazione potrebbe accedere per conto dell'utente. Questi valori vengono utilizzati nella schermata di consenso che Google mostra all'utente.

Gli ambiti consentono alla tua applicazione di richiedere l'accesso solo alle risorse di cui ha bisogno, consentendo al contempo agli utenti di controllare la quantità di accesso che concedono alla tua applicazione. Pertanto, esiste una relazione inversa tra il numero di ambiti richiesti e la probabilità di ottenere il consenso dell'utente.

Ti consigliamo di richiedere all'applicazione di richiedere l'accesso agli ambiti di autorizzazione in contesto , se possibile. Se richiedi l'accesso ai dati utente nel contesto tramite autorizzazione incrementale, aiuterai gli utenti a comprendere più facilmente perché la tua applicazione ha bisogno dell'accesso richiesto.

access_type Consigliato

Indica se la tua applicazione può aggiornare i token di accesso quando l'utente non è presente nel browser. I valori di parametro validi sono online, che è il valore predefinito, e offline.

Imposta il valore su offline se la tua applicazione deve aggiornare i token di accesso quando l'utente non è presente nel browser. Questo è il metodo di aggiornamento dei token di accesso descritto più avanti in questo documento. Questo valore indica al server di autorizzazione di Google di restituire un token di aggiornamento e un token di accesso la prima volta che la tua applicazione scambia un codice di autorizzazione con i token.

state Consigliato

Specifica qualsiasi valore di stringa utilizzato dall'applicazione per mantenere lo stato tra la richiesta di autorizzazione e la risposta del server di autorizzazione. Il server restituisce il valore esatto che invii come coppia name=value nel componente della query dell'URL (?) del redirect_uri dopo che l'utente ha acconsentito o negato la richiesta di accesso della tua applicazione.

Puoi utilizzare questo parametro per diversi scopi, ad esempio per indirizzare l'utente alla risorsa corretta nella tua applicazione, inviare nonce e mitigare la contraffazione delle richieste cross-site. Poiché il tuo redirect_uri può essere dedotto, l'utilizzo di un valore state può aumentare la certezza che una connessione in entrata sia il risultato di una richiesta di autenticazione. Se generi una stringa casuale o codifichi l'hash di un cookie o di un altro valore che acquisisce lo stato del client, puoi convalidare la risposta per assicurarti inoltre che la richiesta e la risposta abbiano avuto origine nello stesso browser, offrendo protezione contro attacchi come la contraffazione di richieste cross-site. Consulta la documentazione di OpenID Connect per un esempio di come creare e confermare un token state.

include_granted_scopes Facoltativo

Consente alle applicazioni di utilizzare l'autorizzazione incrementale per richiedere l'accesso a ambiti aggiuntivi nel contesto. Se imposti il valore di questo parametro su true e la richiesta di autorizzazione viene concessa, il nuovo token di accesso coprirà anche tutti gli ambiti a cui l'utente ha precedentemente concesso l'accesso all'applicazione. Per esempi, consulta la sezione Autorizzazione incrementale.

login_hint Facoltativo

Se la tua applicazione sa quale utente sta tentando di autenticarsi, può utilizzare questo parametro per fornire un suggerimento al server di autenticazione di Google. Il server utilizza il suggerimento per semplificare il flusso di accesso precompilando il campo email nel modulo di accesso o selezionando la sessione di accesso multiplo appropriata.

Imposta il valore del parametro su un indirizzo email o un identificatore sub, che è equivalente all'ID Google dell'utente.

prompt Facoltativo

Un elenco di prompt da presentare all'utente, separati da spazi e sensibili alle maiuscole. Se non specifichi questo parametro, all'utente verrà chiesto di confermare solo la prima volta che il progetto richiede l'accesso. Per saperne di più, consulta la sezione Richiesta di un nuovo consenso.

I valori possibili sono:

none Non mostrare schermate di autenticazione o consenso. Non deve essere specificato con altri valori.
consent Chiedi all'utente il consenso.
select_account Chiedi all'utente di selezionare un account.

Passaggio 2: reindirizza al server OAuth 2.0 di Google

Reindirizza l'utente al server OAuth 2.0 di Google per avviare la procedura di autenticazione e autorizzazione. In genere, questo accade quando la tua applicazione deve accedere per la prima volta ai dati dell'utente. Nel caso dell'autorizzazione incrementale, questo passaggio si verifica anche quando l'applicazione deve prima accedere a risorse aggiuntive a cui non ha ancora l'autorizzazione di accesso.

PHP

  1. Genera un URL per richiedere l'accesso dal server OAuth 2.0 di Google:
    $auth_url = $client->createAuthUrl();
  2. Reindirizza l'utente a $auth_url:
    header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));

Python

Questo esempio mostra come reindirizzare l'utente all'URL di autorizzazione utilizzando il framework per applicazioni web Flask:

return flask.redirect(authorization_url)

Ruby

  1. Genera un URL per richiedere l'accesso dal server OAuth 2.0 di Google:
    auth_uri = authorizer.get_authorization_url(request: request)
  2. Reindirizza l'utente a auth_uri.

Node.js

  1. Utilizza l'URL authorizationUrl generato nel passaggio 1 generateAuthUrl per richiedere l'accesso dal server OAuth 2.0 di Google.
  2. Reindirizza l'utente a authorizationUrl.
    res.redirect(authorizationUrl);

HTTP/REST

Esempio di reindirizzamento al server di autorizzazione di Google

Di seguito è riportato un URL di esempio, con interruzioni di riga e spazi per la leggibilità.

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly%20https%3A//www.googleapis.com/auth/calendar.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

Dopo aver creato l'URL della richiesta, reindirizza l'utente a questo URL.

Il server OAuth 2.0 di Google autentica l'utente e ottiene il suo consenso per consentire alla tua applicazione di accedere agli ambiti richiesti. La risposta viene inviata nuovamente alla tua applicazione utilizzando l'URL di reindirizzamento specificato.

Passaggio 3: Google chiede all'utente il consenso

In questo passaggio, l'utente decide se concedere all'applicazione l'accesso richiesto. A questo punto, Google mostra una finestra di consenso che mostra il nome dell'applicazione e i servizi dell'API di Google a cui sta richiedendo l'autorizzazione ad accedere con le credenziali di autorizzazione dell'utente e un riepilogo degli ambiti di accesso da concedere. L'utente può quindi acconsentire a concedere l'accesso a uno o più ambiti richiesti dalla tua applicazione o rifiutare la richiesta.

In questa fase l'applicazione non deve fare nulla mentre attende la risposta del server OAuth 2.0 di Google che indica se è stato concesso l'accesso. Questa risposta è spiegata nel passaggio successivo.

Errori

Le richieste all'endpoint di autorizzazione OAuth 2.0 di Google potrebbero mostrare messaggi di errore rivolti agli utenti anziché i flussi di autenticazione e autorizzazione previsti. Di seguito sono riportati i codici di errore comuni e le soluzioni suggerite.

admin_policy_enforced

L'Account Google non è in grado di autorizzare uno o più ambiti richiesti a causa delle norme dell'amministratore di Google Workspace. Consulta l'articolo del Centro assistenza Google Workspace Specificare quali app di terze parti e interne possono accedere ai dati di Google Workspace per saperne di più su come un amministratore può limitare l'accesso a tutti gli ambiti o agli ambiti sensibili e con limitazioni finché l'accesso non viene concesso esplicitamente al tuo ID cliente OAuth.

disallowed_useragent

L'endpoint di autorizzazione viene visualizzato all'interno di un user-agent incorporato non consentito dalle Norme di OAuth 2.0 di Google.

Android

Gli sviluppatori Android potrebbero visualizzare questo messaggio di errore quando aprono le richieste di autorizzazione in android.webkit.WebView. Gli sviluppatori dovrebbero invece utilizzare librerie Android come Accesso Google per Android o AppAuth per Android della OpenID Foundation.

Gli sviluppatori web potrebbero riscontrare questo errore quando un'app per Android apre un link web generico in un agente utente incorporato e un utente accede all'endpoint di autorizzazione OAuth 2.0 di Google dal tuo sito. Gli sviluppatori devono consentire l'apertura dei link generici nel gestore dei link predefinito del sistema operativo, che include sia i gestori di Android App Links sia l'app browser predefinita. Anche la libreria Android Custom Tabs è un'opzione supportata.

iOS

Gli sviluppatori iOS e macOS potrebbero riscontrare questo errore quando aprono le richieste di autorizzazione in WKWebView. Gli sviluppatori dovrebbero invece utilizzare librerie per iOS come Google Sign-In per iOS o AppAuth per iOS di OpenID Foundation.

Gli sviluppatori web potrebbero riscontrare questo errore quando un'app per iOS o macOS apre un link web generico in un agente utente incorporato e un utente accede all'endpoint di autorizzazione OAuth 2.0 di Google dal tuo sito. Gli sviluppatori devono consentire l'apertura dei link generici nel gestore dei link predefinito del sistema operativo, che include sia i gestori dei link universali sia l'app del browser predefinito. Anche la libreria SFSafariViewController è un'opzione supportata.

org_internal

L'ID client OAuth nella richiesta fa parte di un progetto che limita l'accesso agli Account Google in una organizzazione Google Cloud specifica. Per saperne di più su questa opzione di configurazione, consulta la sezione Tipo di utente dell'articolo del Centro assistenza Configurare la schermata di consenso OAuth.

invalid_client

Il client secret OAuth non è corretto. Esamina la configurazione del client OAuth, inclusi l'ID client e il segreto utilizzati per questa richiesta.

invalid_grant

Quando aggiorni un token di accesso o utilizzi l'autorizzazione incrementale, il token potrebbe essere scaduto o essere stato invalidato. Autentica di nuovo l'utente e chiedi il suo consenso per ottenere nuovi token. Se continui a visualizzare questo errore, assicurati che l'applicazione sia stata configurata correttamente e che tu stia utilizzando i token e i parametri corretti nella richiesta. In caso contrario, l'account utente potrebbe essere stato eliminato o disattivato.

redirect_uri_mismatch

Il valore redirect_uri passato nella richiesta di autorizzazione non corrisponde a un URI di reindirizzamento autorizzato per l'ID client OAuth. Esamina gli URI di reindirizzamento autorizzati in Google API Console Credentials page.

Il parametro redirect_uri potrebbe fare riferimento al flusso OAuth out-of-band (OOB) che è stato ritirato e non è più supportato. Consulta la guida alla migrazione per aggiornare l'integrazione.

invalid_request

Si è verificato un problema con la richiesta che hai inviato. Ciò potrebbe essere dovuto a diversi motivi:

  • La richiesta non è stata formattata correttamente
  • Nella richiesta mancavano i parametri obbligatori
  • La richiesta utilizza un metodo di autorizzazione non supportato da Google. Verificare che l'integrazione OAuth utilizzi un metodo di integrazione consigliato

Passaggio 4: gestisci la risposta del server OAuth 2.0

Il server OAuth 2.0 risponde alla richiesta di accesso dell'applicazione utilizzando l'URL specificato nella richiesta.

Se l'utente approva la richiesta di accesso, la risposta contiene un codice di autorizzazione. Se l'utente non approva la richiesta, la risposta contiene un messaggio di errore. Il codice di autorizzazione o il messaggio di errore restituito al server web viene visualizzato nella stringa di query, come mostrato di seguito:

Una risposta di errore:

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

Una risposta con il codice di autorizzazione:

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

Esempio di risposta del server OAuth 2.0

Puoi testare questo flusso facendo clic sul seguente URL di esempio, che richiede accesso di sola lettura per visualizzare i metadati dei file in Google Drive e accesso di sola lettura per visualizzare gli eventi di Google Calendar:

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly%20https%3A//www.googleapis.com/auth/calendar.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

Dopo aver completato il flusso OAuth 2.0, dovresti essere reindirizzato a http://localhost/oauth2callback, che probabilmente restituirà un errore 404 NOT FOUND, a meno che la tua macchina locale non pubblichi un file a quell'indirizzo. Il passaggio successivo fornisce ulteriori dettagli sulle informazioni restituite nell'URI quando l'utente viene reindirizzato alla tua applicazione.

Passaggio 5: scambia il codice di autorizzazione con i token di aggiornamento e di accesso

Dopo aver ricevuto il codice di autorizzazione, il server web può scambiarlo con un token di accesso.

PHP

Per scambiare un codice di autorizzazione con un token di accesso, utilizza il metodo fetchAccessTokenWithAuthCode:

$access_token = $client->fetchAccessTokenWithAuthCode($_GET['code']);

Python

Nella pagina di callback, utilizza la libreria google-auth per verificare la risposta del server di autorizzazione. Quindi, utilizza il metodo flow.fetch_token per scambiare il codice di autorizzazione nella risposta con un token di accesso:

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,
    'granted_scopes': credentials.granted_scopes}

Ruby

Nella pagina di callback, utilizza la libreria googleauth per verificare la risposta del server di autorizzazione. Utilizza il metodo authorizer.handle_auth_callback_deferred per salvare il codice di autorizzazione e reindirizzare all'URL che ha richiesto l'autorizzazione in origine. In questo modo, l'utente posticipa lo scambio del codice memorizzando temporaneamente i risultati nella sessione.

  target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request)
  redirect target_url

Node.js

Per scambiare un codice di autorizzazione con un token di accesso, utilizza il metodo getToken:

const url = require('url');

// Receive the callback from Google's OAuth 2.0 server.
app.get('/oauth2callback', async (req, res) => {
  let q = url.parse(req.url, true).query;

  if (q.error) { // An error response e.g. error=access_denied
    console.log('Error:' + q.error);
  } else if (q.state !== req.session.state) { //check state value
    console.log('State mismatch. Possible CSRF attack');
    res.end('State mismatch. Possible CSRF attack');
  } else { // Get access and refresh tokens (if access_type is offline)

    let { tokens } = await oauth2Client.getToken(q.code);
    oauth2Client.setCredentials(tokens);
});

HTTP/REST

Per scambiare un codice di autorizzazione con un token di accesso, chiama l'endpoint https://oauth2.googleapis.com/token e imposta i seguenti parametri:

Campi
client_id L'ID client ottenuto da API Console Credentials page.
client_secret Il client secret ottenuto da API Console Credentials page.
code Il codice di autorizzazione restituito dalla richiesta iniziale.
grant_type Come definito nella specifica OAuth 2.0, il valore di questo campo deve essere impostato su authorization_code.
redirect_uri Uno degli URI di reindirizzamento elencati per il tuo progetto in API Console Credentials page per il dato client_id.

Lo snippet seguente mostra una richiesta di esempio:

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 risponde a questa richiesta restituendo un oggetto JSON contenente un token di accesso di breve durata e un token di aggiornamento. Tieni presente che il token di aggiornamento viene restituito solo se la tua applicazione ha impostato il parametro access_type su offline nella richiesta iniziale al server di autorizzazione di Google.

La risposta contiene i seguenti campi:

Campi
access_token Il token inviato dall'applicazione per autorizzare una richiesta all'API di Google.
expires_in La durata rimanente del token di accesso in secondi.
refresh_token Un token che puoi utilizzare per ottenere un nuovo token di accesso. I token di aggiornamento sono validi finché l'utente non revoca l'accesso. Anche in questo caso, questo campo è presente nella risposta solo se imposti il parametro access_type su offline nella richiesta iniziale al server di autorizzazione di Google.
scope Gli ambiti di accesso concessi dal access_token espressi come un elenco di stringhe sensibili alle maiuscole delimitate da spazi.
token_type Il tipo di token restituito. Al momento, il valore di questo campo è sempre impostato su Bearer.

Il seguente snippet mostra una risposta di esempio:

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

Errori

Quando scambi il codice di autorizzazione con un token di accesso, potresti riscontrare il seguente errore anziché la risposta prevista. Di seguito sono riportati i codici di errore comuni e le relative soluzioni.

invalid_grant

Il codice di autorizzazione fornito non è valido o ha un formato errato. Richiedi un nuovo codice riavviando la procedura OAuth per richiedere nuovamente il consenso all'utente.

Passaggio 6: controlla quali ambiti sono stati concessi dagli utenti

Quando richiedi più ambiti contemporaneamente, gli utenti potrebbero non concedere tutti gli ambiti richiesti dalla tua app. L'app deve sempre controllare quali ambiti sono stati concessi dall'utente e gestire qualsiasi rifiuto degli ambiti disattivando le funzionalità pertinenti. Per ulteriori informazioni, consulta Come gestire le autorizzazioni granulari.

PHP

Per controllare quali ambiti sono stati concessi dall'utente, utilizza il metodo getGrantedScope():

// Space-separated string of granted scopes if it exists, otherwise null.
$granted_scopes = $client->getOAuth2Service()->getGrantedScope();

// Determine which scopes user granted and build a dictionary
$granted_scopes_dict = [
  'Drive' => str_contains($granted_scopes, Google\Service\Drive::DRIVE_METADATA_READONLY),
  'Calendar' => str_contains($granted_scopes, Google\Service\Calendar::CALENDAR_READONLY)
];

Python

L'oggetto credentials restituito ha una proprietà granted_scopes, che è un elenco degli ambiti concessi dall'utente alla tua 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,
    'granted_scopes': credentials.granted_scopes}

La seguente funzione controlla gli ambiti che l'utente ha concesso alla tua app.

def check_granted_scopes(credentials):
  features = {}
  if 'https://www.googleapis.com/auth/drive.metadata.readonly' in credentials['granted_scopes']:
    features['drive'] = True
  else:
    features['drive'] = False

  if 'https://www.googleapis.com/auth/calendar.readonly' in credentials['granted_scopes']:
    features['calendar'] = True
  else:
    features['calendar'] = False

  return features

Ruby

Quando richiedi più ambiti contemporaneamente, controlla quali sono stati concessi tramite la proprietà scope dell'oggetto credentials.

# User authorized the request. Now, check which scopes were granted.
if credentials.scope.include?(Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY)
  # User authorized read-only Drive activity permission.
  # Calling the APIs, etc
else
  # User didn't authorize read-only Drive activity permission.
  # Update UX and application accordingly
end

# Check if user authorized Calendar read permission.
if credentials.scope.include?(Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY)
  # User authorized Calendar read permission.
  # Calling the APIs, etc.
else
  # User didn't authorize Calendar read permission.
  # Update UX and application accordingly
end

Node.js

Quando richiedi più ambiti contemporaneamente, controlla quali sono stati concessi tramite la proprietà scope dell'oggetto tokens.

// User authorized the request. Now, check which scopes were granted.
if (tokens.scope.includes('https://www.googleapis.com/auth/drive.metadata.readonly'))
{
  // User authorized read-only Drive activity permission.
  // Calling the APIs, etc.
}
else
{
  // User didn't authorize read-only Drive activity permission.
  // Update UX and application accordingly
}

// Check if user authorized Calendar read permission.
if (tokens.scope.includes('https://www.googleapis.com/auth/calendar.readonly'))
{
  // User authorized Calendar read permission.
  // Calling the APIs, etc.
}
else
{
  // User didn't authorize Calendar read permission.
  // Update UX and application accordingly
}

HTTP/REST

Per verificare se l'utente ha concesso alla tua applicazione l'accesso a un determinato ambito, esamina il campo scope nella risposta del token di accesso. Gli ambiti di accesso concessi dal token di accesso espressi come un elenco di stringhe sensibili alle maiuscole delimitate da spazi.

Ad esempio, la seguente risposta di esempio del token di accesso indica che l'utente ha concesso alla tua applicazione l'accesso alle autorizzazioni di sola lettura per le attività di Drive e gli eventi di Calendar:

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

Chiama le API di Google

PHP

Utilizza il token di accesso per chiamare le API Google completando i seguenti passaggi:

  1. Se devi applicare un token di accesso a un nuovo oggetto Google\Client, ad esempio se hai archiviato il token di accesso in una sessione utente, utilizza il metodo setAccessToken:
    $client->setAccessToken($access_token);
  2. Crea un oggetto servizio per l'API che vuoi chiamare. Per creare un oggetto di servizio, fornisci un oggetto Google\Client autorizzato al costruttore dell'API che vuoi chiamare. Ad esempio, per chiamare l'API Drive:
    $drive = new Google\Service\Drive($client);
  3. Invia richieste al servizio API utilizzando l' interfaccia fornita dall'oggetto servizio. Ad esempio, per elencare i file in Google Drive dell'utente autenticato:
    $files = $drive->files->listFiles(array());

Python

Dopo aver ottenuto un token di accesso, l'applicazione può utilizzarlo per autorizzare le richieste API per conto di un determinato account utente o account di servizio. Utilizza le credenziali di autorizzazione specifiche dell'utente per creare un oggetto di servizio per l'API che vuoi chiamare, quindi utilizza questo oggetto per effettuare richieste API autorizzate.

  1. Crea un oggetto servizio per l'API che vuoi chiamare. Puoi creare un oggetto di servizio chiamando il metodo googleapiclient.discovery della libreria build con il nome e la versione dell'API e le credenziali utente: Ad esempio, per chiamare la versione 3 dell'API Drive:
    from googleapiclient.discovery import build
    
    drive = build('drive', 'v2', credentials=credentials)
  2. Invia richieste al servizio API utilizzando l'interfaccia fornita dall'oggetto servizio. Ad esempio, per elencare i file in Google Drive dell'utente autenticato:
    files = drive.files().list().execute()

Ruby

Dopo aver ottenuto un token di accesso, l'applicazione può utilizzarlo per effettuare richieste API per conto di un determinato account utente o account di servizio. Utilizza le credenziali di autorizzazione specifiche dell'utente per creare un oggetto di servizio per l'API che vuoi chiamare, quindi utilizza questo oggetto per effettuare richieste API autorizzate.

  1. Crea un oggetto servizio per l'API che vuoi chiamare. Ad esempio, per chiamare la versione 3 dell'API Drive:
    drive = Google::Apis::DriveV3::DriveService.new
  2. Imposta le credenziali sul servizio:
    drive.authorization = credentials
  3. Invia richieste al servizio API utilizzando l'interfaccia fornita dall'oggetto servizio. Ad esempio, per elencare i file in Google Drive dell'utente autenticato:
    files = drive.list_files

In alternativa, l'autorizzazione può essere fornita in base al metodo specificando il parametro options per un metodo:

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

Node.js

Dopo aver ottenuto un token di accesso e averlo impostato sull'oggetto OAuth2, utilizza l'oggetto per chiamare le API di Google. La tua applicazione può utilizzare questo token per autorizzare le richieste API per conto di un determinato account utente o account di servizio. Crea un oggetto servizio per l'API che vuoi chiamare. Ad esempio, il seguente codice utilizza l'API Google Drive per elencare i nomi dei file in Drive dell'utente.

const { google } = require('googleapis');

// Example of using Google Drive API to list filenames in user's Drive.
const drive = google.drive('v3');
drive.files.list({
  auth: oauth2Client,
  pageSize: 10,
  fields: 'nextPageToken, files(id, name)',
}, (err1, res1) => {
  if (err1) return console.log('The API returned an error: ' + err1);
  const files = res1.data.files;
  if (files.length) {
    console.log('Files:');
    files.map((file) => {
      console.log(`${file.name} (${file.id})`);
    });
  } else {
    console.log('No files found.');
  }
});

HTTP/REST

Dopo che l'applicazione ha ottenuto un token di accesso, puoi utilizzarlo per effettuare chiamate a un'API Google per conto di un determinato account utente se gli ambiti di accesso richiesti dall'API sono stati concessi. Per farlo, includi il token di accesso in una richiesta all'API includendo un parametro di query access_token o un valore Bearer dell'intestazione HTTP Authorization. Se possibile, è preferibile l'intestazione HTTP, perché le stringhe di query tendono a essere visibili nei log del server. Nella maggior parte dei casi puoi utilizzare una libreria client per configurare le chiamate alle API di Google (ad esempio, quando chiami l'API Drive Files).

Puoi provare tutte le API di Google e visualizzarne gli ambiti in OAuth 2.0 Playground.

Esempi di richieste GET HTTP

Una chiamata all'endpoint drive.files (l'API Drive Files) che utilizza l'intestazione HTTP Authorization: Bearer potrebbe avere il seguente aspetto. Tieni presente che devi specificare il tuo token di accesso:

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

Ecco una chiamata alla stessa API per l'utente autenticato che utilizza il parametro della stringa di query access_token:

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

curl esempi

Puoi testare questi comandi con l'applicazione a riga di comando curl. Ecco un esempio che utilizza l'opzione dell'intestazione HTTP (opzione preferita):

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

In alternativa, l'opzione del parametro stringa di query:

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

Esempio completo

L'esempio seguente stampa un elenco di file in formato JSON in Google Drive di un utente dopo che l'utente si è autenticato e ha dato il consenso all'applicazione di accedere ai metadati di Drive.

PHP

Per eseguire questo esempio:

  1. In API Console, aggiungi l'URL della macchina locale all'elenco degli URL di reindirizzamento. Ad esempio, aggiungi http://localhost:8080.
  2. Crea una nuova directory e passaci. Ad esempio:
    mkdir ~/php-oauth2-example
    cd ~/php-oauth2-example
  3. Installa la libreria client dell'API di Google per PHP utilizzando Composer:
    composer require google/apiclient:^2.15.0
  4. Crea i file index.php e oauth2callback.php con i seguenti contenuti.
  5. Esegui l'esempio con il server web di test integrato di PHP:
    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_secret.json');

// User granted permission as an access token is in the session.
if (isset($_SESSION['access_token']) && $_SESSION['access_token'])
{
  $client->setAccessToken($_SESSION['access_token']);
  
  // Check if user granted Drive permission
  if ($_SESSION['granted_scopes_dict']['Drive']) {
    echo "Drive feature is enabled.";
    echo "</br>";
    $drive = new Drive($client);
    $files = array();
    $response = $drive->files->listFiles(array());
    foreach ($response->files as $file) {
        echo "File: " . $file->name . " (" . $file->id . ")";
        echo "</br>";
    }
  } else {
    echo "Drive feature is NOT enabled.";
    echo "</br>";
  }

   // Check if user granted Calendar permission
  if ($_SESSION['granted_scopes_dict']['Calendar']) {
    echo "Calendar feature is enabled.";
    echo "</br>";
  } else {
    echo "Calendar feature is NOT enabled.";
    echo "</br>";
  }
}
else
{
  // Redirect users to outh2call.php which redirects users to Google OAuth 2.0
  $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();

// Required, call the setAuthConfig function to load authorization credentials from
// client_secret.json file.
$client->setAuthConfigFile('client_secret.json');
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST']. $_SERVER['PHP_SELF']);

// Required, to set the scope value, call the addScope function.
$client->addScope([Google\Service\Drive::DRIVE_METADATA_READONLY, Google\Service\Calendar::CALENDAR_READONLY]);

// Enable incremental authorization. Recommended as a best practice.
$client->setIncludeGrantedScopes(true);

// Recommended, 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");

// Generate a URL for authorization as it doesn't contain code and error
if (!isset($_GET['code']) && !isset($_GET['error']))
{
  // Generate and set state value
  $state = bin2hex(random_bytes(16));
  $client->setState($state);
  $_SESSION['state'] = $state;

  // Generate a url that asks permissions.
  $auth_url = $client->createAuthUrl();
  header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
}

// User authorized the request and authorization code is returned to exchange access and
// refresh tokens.
if (isset($_GET['code']))
{
  // Check the state value
  if (!isset($_GET['state']) || $_GET['state'] !== $_SESSION['state']) {
    die('State mismatch. Possible CSRF attack.');
  }

  // Get access and refresh tokens (if access_type is offline)
  $token = $client->fetchAccessTokenWithAuthCode($_GET['code']);

  /** Save access and refresh token to the session variables.
    * ACTION ITEM: In a production app, you likely want to save the
    *              refresh token in a secure persistent storage instead. */
  $_SESSION['access_token'] = $token;
  $_SESSION['refresh_token'] = $client->getRefreshToken();
  
  // Space-separated string of granted scopes if it exists, otherwise null.
  $granted_scopes = $client->getOAuth2Service()->getGrantedScope();

  // Determine which scopes user granted and build a dictionary
  $granted_scopes_dict = [
    'Drive' => str_contains($granted_scopes, Google\Service\Drive::DRIVE_METADATA_READONLY),
    'Calendar' => str_contains($granted_scopes, Google\Service\Calendar::CALENDAR_READONLY)
  ];
  $_SESSION['granted_scopes_dict'] = $granted_scopes_dict;
  
  $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

// An error response e.g. error=access_denied
if (isset($_GET['error']))
{
  echo "Error: ". $_GET['error'];
}
?>

Python

Questo esempio utilizza il framework Flask. Esegue un'applicazione web all'indirizzo http://localhost:8080 che ti consente di testare il flusso OAuth 2.0. Se accedi a questo URL, dovresti vedere cinque link:

  • Chiama l'API Drive:questo link rimanda a una pagina che tenta di eseguire una richiesta API di esempio se gli utenti hanno concesso l'autorizzazione. Se necessario, avvia il flusso di autorizzazione. In caso di esito positivo, la pagina mostra la risposta dell'API.
  • Pagina simulata per chiamare l'API Calendar: questo link rimanda a una pagina simulata che tenta di eseguire una richiesta di esempio dell'API Calendar se gli utenti hanno concesso l'autorizzazione. Se necessario, avvia il flusso di autorizzazione. In caso di esito positivo, la pagina mostra la risposta dell'API.
  • Esegui direttamente il test del flusso di autenticazione:questo link rimanda a una pagina che tenta di inviare l'utente al flusso di autorizzazione. L'app richiede l'autorizzazione per inviare richieste API autorizzate per conto dell'utente.
  • Revoca credenziali attuali:questo link rimanda a una pagina che revoca le autorizzazioni che l'utente ha già concesso all'applicazione.
  • Cancella credenziali sessione Flask:questo link cancella le credenziali di autorizzazione memorizzate nella sessione Flask. In questo modo puoi vedere cosa succederebbe se un utente che ha già concesso l'autorizzazione alla tua app provasse a eseguire una richiesta API in una nuova sessione. Inoltre, ti consente di vedere la risposta dell'API che la tua app riceverebbe se un utente avesse revocato le autorizzazioni concesse alla tua app e quest'ultima avesse comunque provato ad autorizzare una richiesta con un token di accesso revocato.
# -*- 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"

# The OAuth 2.0 access scope allows for access to the
# authenticated user's account and requires requests to use an SSL connection.
SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly',
          'https://www.googleapis.com/auth/calendar.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('/drive')
def drive_api_request():
  if 'credentials' not in flask.session:
    return flask.redirect('authorize')

  features = flask.session['features']

  if features['drive']:
    # 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)
  else:
    # User didn't authorize read-only Drive activity permission.
    # Update UX and application accordingly
    return '<p>Drive feature is not enabled.</p>'

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

      features = flask.session['features']

      if features['calendar']:
        # User authorized Calendar read permission.
        # Calling the APIs, etc.
        return ('<p>User granted the Google Calendar read permission. '+
                'This sample code does not include code to call Calendar</p>')
      else:
        # User didn't authorize Calendar read permission.
        # Update UX and application accordingly
        return '<p>Calendar feature is not enabled.</p>'

@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
  
  credentials = credentials_to_dict(credentials)
  flask.session['credentials'] = credentials

  # Check which scopes user granted
  features = check_granted_scopes(credentials)
  flask.session['features'] = features
  return flask.redirect('/')
  

@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,
          'granted_scopes': credentials.granted_scopes}

def check_granted_scopes(credentials):
  features = {}
  if 'https://www.googleapis.com/auth/drive.metadata.readonly' in credentials['granted_scopes']:
    features['drive'] = True
  else:
    features['drive'] = False

  if 'https://www.googleapis.com/auth/calendar.readonly' in credentials['granted_scopes']:
    features['calendar'] = True
  else:
    features['calendar'] = False

  return features

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'

  # This disables the requested scopes and granted scopes check.
  # If users only grant partial request, the warning would not be thrown.
  os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '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

Questo esempio utilizza il framework Sinatra.

require 'googleauth'
require 'googleauth/web_user_authorizer'
require 'googleauth/stores/redis_token_store'

require 'google/apis/drive_v3'
require 'google/apis/calendar_v3'

require 'sinatra'

configure do
  enable :sessions

  # Required, call the from_file method to retrieve the client ID from a
  # client_secret.json file.
  set :client_id, Google::Auth::ClientId.from_file('/path/to/client_secret.json')

  # Required, scope value
  # Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar.
  scope = ['Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY',
           'Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY']

  # Required, Authorizers require a storage instance to manage long term persistence of
  # access and refresh tokens.
  set :token_store, Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new)

  # Required, 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.
  set :callback_uri, '/oauth2callback'

  # To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI
  # from the client_secret.json file. To get these credentials for your application, visit
  # https://console.cloud.google.com/apis/credentials.
  set :authorizer, Google::Auth::WebUserAuthorizer.new(settings.client_id, settings.scope,
                          settings.token_store, callback_uri: settings.callback_uri)
end

get '/' do
  # NOTE: Assumes the user is already authenticated to the app
  user_id = request.session['user_id']

  # Fetch stored credentials for the user from the given request session.
  # nil if none present
  credentials = settings.authorizer.get_credentials(user_id, request)

  if credentials.nil?
    # Generate a url that asks the user to authorize requested scope(s).
    # Then, redirect user to the url.
    redirect settings.authorizer.get_authorization_url(request: request)
  end
  
  # User authorized the request. Now, check which scopes were granted.
  if credentials.scope.include?(Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY)
    # User authorized read-only Drive activity permission.
    # Example of using Google Drive API to list filenames in user's Drive.
    drive = Google::Apis::DriveV3::DriveService.new
    files = drive.list_files(options: { authorization: credentials })
    "<pre>#{JSON.pretty_generate(files.to_h)}</pre>"
  else
    # User didn't authorize read-only Drive activity permission.
    # Update UX and application accordingly
  end

  # Check if user authorized Calendar read permission.
  if credentials.scope.include?(Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY)
    # User authorized Calendar read permission.
    # Calling the APIs, etc.
  else
    # User didn't authorize Calendar read permission.
    # Update UX and application accordingly
  end
end

# Receive the callback from Google's OAuth 2.0 server.
get '/oauth2callback' do
  # Handle the result of the oauth callback. Defers the exchange of the code by
  # temporarily stashing the results in the user's session.
  target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request)
  redirect target_url
end

Node.js

Per eseguire questo esempio:

  1. In API Console, aggiungi l'URL della macchina locale all'elenco degli URL di reindirizzamento. Ad esempio, aggiungi http://localhost.
  2. Assicurati di avere installato una versione LTS di manutenzione, LTS attiva o la release corrente di Node.js.
  3. Crea una nuova directory e passaci. Ad esempio:
    mkdir ~/nodejs-oauth2-example
    cd ~/nodejs-oauth2-example
  4. Installa la libreria client dell'API di Google per Node.js utilizzando npm:
    npm install googleapis
  5. Crea i file main.js con i seguenti contenuti.
  6. Esegui l'esempio:
    node .\main.js

main.js

const http = require('http');
const https = require('https');
const url = require('url');
const { google } = require('googleapis');
const crypto = require('crypto');
const express = require('express');
const session = require('express-session');

/**
 * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI.
 * To get these credentials for your application, visit
 * https://console.cloud.google.com/apis/credentials.
 */
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar.
const scopes = [
  'https://www.googleapis.com/auth/drive.metadata.readonly',
  'https://www.googleapis.com/auth/calendar.readonly'
];

/* Global variable that stores user credential in this code example.
 * ACTION ITEM for developers:
 *   Store user's refresh token in your data store if
 *   incorporating this code into your real app.
 *   For more information on handling refresh tokens,
 *   see https://github.com/googleapis/google-api-nodejs-client#handling-refresh-tokens
 */
let userCredential = null;

async function main() {
  const app = express();

  app.use(session({
    secret: 'your_secure_secret_key', // Replace with a strong secret
    resave: false,
    saveUninitialized: false,
  }));

  // Example on redirecting user to Google's OAuth 2.0 server.
  app.get('/', async (req, res) => {
    // Generate a secure random state value.
    const state = crypto.randomBytes(32).toString('hex');
    // Store state in the session
    req.session.state = state;

    // Generate a url that asks permissions for the Drive activity and Google Calendar scope
    const authorizationUrl = oauth2Client.generateAuthUrl({
      // 'online' (default) or 'offline' (gets refresh_token)
      access_type: 'offline',
      /** Pass in the scopes array defined above.
        * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
      scope: scopes,
      // Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes: true,
      // Include the state parameter to reduce the risk of CSRF attacks.
      state: state
    });

    res.redirect(authorizationUrl);
  });

  // Receive the callback from Google's OAuth 2.0 server.
  app.get('/oauth2callback', async (req, res) => {
    // Handle the OAuth 2.0 server response
    let q = url.parse(req.url, true).query;

    if (q.error) { // An error response e.g. error=access_denied
      console.log('Error:' + q.error);
    } else if (q.state !== req.session.state) { //check state value
      console.log('State mismatch. Possible CSRF attack');
      res.end('State mismatch. Possible CSRF attack');
    } else { // Get access and refresh tokens (if access_type is offline)
      let { tokens } = await oauth2Client.getToken(q.code);
      oauth2Client.setCredentials(tokens);

      /** Save credential to the global variable in case access token was refreshed.
        * ACTION ITEM: In a production app, you likely want to save the refresh token
        *              in a secure persistent database instead. */
      userCredential = tokens;
      
      // User authorized the request. Now, check which scopes were granted.
      if (tokens.scope.includes('https://www.googleapis.com/auth/drive.metadata.readonly'))
      {
        // User authorized read-only Drive activity permission.
        // Example of using Google Drive API to list filenames in user's Drive.
        const drive = google.drive('v3');
        drive.files.list({
          auth: oauth2Client,
          pageSize: 10,
          fields: 'nextPageToken, files(id, name)',
        }, (err1, res1) => {
          if (err1) return console.log('The API returned an error: ' + err1);
          const files = res1.data.files;
          if (files.length) {
            console.log('Files:');
            files.map((file) => {
              console.log(`${file.name} (${file.id})`);
            });
          } else {
            console.log('No files found.');
          }
        });
      }
      else
      {
        // User didn't authorize read-only Drive activity permission.
        // Update UX and application accordingly
      }

      // Check if user authorized Calendar read permission.
      if (tokens.scope.includes('https://www.googleapis.com/auth/calendar.readonly'))
      {
        // User authorized Calendar read permission.
        // Calling the APIs, etc.
      }
      else
      {
        // User didn't authorize Calendar read permission.
        // Update UX and application accordingly
      }
    }
  });

  // Example on revoking a token
  app.get('/revoke', async (req, res) => {
    // Build the string for the POST request
    let postData = "token=" + userCredential.access_token;

    // Options for POST request to Google's OAuth 2.0 server to revoke a token
    let postOptions = {
      host: 'oauth2.googleapis.com',
      port: '443',
      path: '/revoke',
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Content-Length': Buffer.byteLength(postData)
      }
    };

    // Set up the request
    const postReq = https.request(postOptions, function (res) {
      res.setEncoding('utf8');
      res.on('data', d => {
        console.log('Response: ' + d);
      });
    });

    postReq.on('error', error => {
      console.log(error)
    });

    // Post the request with data
    postReq.write(postData);
    postReq.end();
  });


  const server = http.createServer(app);
  server.listen(8080);
}
main().catch(console.error);

HTTP/REST

Questo esempio in Python utilizza il framework Flask e la libreria Requests per dimostrare il flusso web OAuth 2.0. Per questo flusso consigliamo di utilizzare la libreria client delle API di Google per Python. L'esempio nella scheda Python utilizza la libreria client.

import json
import flask
import requests

app = flask.Flask(__name__)

# To get these credentials (CLIENT_ID CLIENT_SECRET) and for your application, visit
# https://console.cloud.google.com/apis/credentials.
CLIENT_ID = '123456789.apps.googleusercontent.com'
CLIENT_SECRET = 'abc123'  # Read from a file or environmental variable in a real app

# Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar.
SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/calendar.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.
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: 
    # User authorized the request. Now, check which scopes were granted.
    if 'https://www.googleapis.com/auth/drive.metadata.readonly' in credentials['scope']:
      # User authorized read-only Drive activity permission.
      # Example of using Google Drive API to list filenames in user's Drive.
      headers = {'Authorization': 'Bearer {}'.format(credentials['access_token'])}
      req_uri = 'https://www.googleapis.com/drive/v2/files'
      r = requests.get(req_uri, headers=headers).text
    else:
      # User didn't authorize read-only Drive activity permission.
      # Update UX and application accordingly
      r = 'User did not authorize Drive permission.'

    # Check if user authorized Calendar read permission.
    if 'https://www.googleapis.com/auth/calendar.readonly' in credentials['scope']:
      # User authorized Calendar read permission.
      # Calling the APIs, etc.
      r += 'User authorized Calendar permission.'
    else:
      # User didn't authorize Calendar read permission.
      # Update UX and application accordingly
      r += 'User did not authorize Calendar permission.'

  return r

@app.route('/oauth2callback')
def oauth2callback():
  if 'code' not in flask.request.args:
    state = str(uuid.uuid4())
    flask.session['state'] = state
    # Generate a url that asks permissions for the Drive activity
    # and Google Calendar scope. Then, redirect user to the url.
    auth_uri = ('https://accounts.google.com/o/oauth2/v2/auth?response_type=code'
                '&client_id={}&redirect_uri={}&scope={}&state={}').format(CLIENT_ID, REDIRECT_URI,
                                                                          SCOPE, state)
    return flask.redirect(auth_uri)
  else:
    if 'state' not in flask.request.args or flask.request.args['state'] != flask.session['state']:
      return 'State mismatch. Possible CSRF attack.', 400

    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'}

    # Exchange authorization code for access and refresh tokens (if access_type is offline)
    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()

Regole di convalida degli URI di reindirizzamento

Google applica le seguenti regole di convalida agli URI di reindirizzamento per aiutare gli sviluppatori a mantenere le loro applicazioni al sicuro. Gli URI di reindirizzamento devono rispettare queste regole. Consulta RFC 3986 sezione 3 per la definizione di dominio, host, percorso, query, schema e userinfo, riportati di seguito.

Regole di convalida
Schema

Gli URI di reindirizzamento devono utilizzare lo schema HTTPS, non il semplice HTTP. Gli URI localhost (inclusi URI di indirizzi IP localhost) sono esenti da questa regola.

Host

Gli host non possono essere indirizzi IP non elaborati. Gli indirizzi IP localhost sono esenti da questa regola.

Dominio
  • I TLD dell'host (Top Level Domains) devono appartenere all'elenco dei suffissi pubblici.
  • I domini host non possono essere “googleusercontent.com”.
  • Gli URI di reindirizzamento non possono contenere domini di accorciatori di URL (ad es. goo.gl), a meno che non sia di proprietà dell'app. Inoltre, se un'app che possiede un dominio di accorciamento sceglie di eseguire un reindirizzamento a quel dominio, l'URI di reindirizzamento deve contenere “/google-callback/” nel percorso o terminare con “/google-callback”.
  • Userinfo

    Gli URI di reindirizzamento non possono contenere il sottocomponente userinfo.

    Percorso

    Gli URI di reindirizzamento non possono contenere un percorso traversal (chiamato anche backtracking della directory), rappresentato da “/..” o “\..” o dalla loro codifica URL.

    Query

    Gli URI di reindirizzamento non possono contenere reindirizzamenti aperti.

    Fragment

    Gli URI di reindirizzamento non possono contenere il componente del frammento.

    Caratteri Gli URI di reindirizzamento non possono contenere determinati caratteri, tra cui:
    • Caratteri jolly ('*')
    • Caratteri ASCII non stampabili
    • Codifiche percentuali non valide (qualsiasi codifica percentuale che non segue la forma di un segno di percentuale seguito da due cifre esadecimali della codifica dell'URL)
    • Caratteri null (un carattere NULL codificato, ad es. %00, %C0%80)

    Autorizzazione incrementale

    Nel protocollo OAuth 2.0, l'app richiede l'autorizzazione per accedere alle risorse, che sono identificate dagli ambiti. È considerata una best practice per l'esperienza utente richiedere l'autorizzazione per le risorse al momento del bisogno. Per abilitare questa pratica, il server di autorizzazione di Google supporta l'autorizzazione incrementale. Questa funzionalità ti consente di richiedere gli ambiti man mano che sono necessari e, se l'utente concede l'autorizzazione per il nuovo ambito, restituisce un codice di autorizzazione che può essere scambiato per un token contenente tutti gli ambiti concessi dall'utente al progetto.

    Ad esempio, un'app che consente di campionare tracce musicali e creare mix potrebbe richiedere pochissime risorse al momento dell'accesso, forse solo il nome della persona che accede. Tuttavia, per salvare un mix completato è necessario accedere a Google Drive. La maggior parte delle persone troverebbe naturale se gli venisse chiesto di accedere a Google Drive solo quando l'app ne ha effettivamente bisogno.

    In questo caso, al momento dell'accesso l'app potrebbe richiedere gli ambiti openid e profile per eseguire l'accesso di base, per poi richiedere in un secondo momento l'ambito https://www.googleapis.com/auth/drive.file al momento della prima richiesta per salvare un mix.

    Per implementare l'autorizzazione incrementale, completa il normale flusso per richiedere un token di accesso, ma assicurati che la richiesta di autorizzazione includa gli ambiti concessi in precedenza. Questo approccio consente alla tua app di evitare di dover gestire più token di accesso.

    Le seguenti regole si applicano a un token di accesso ottenuto da un'autorizzazione incrementale:

    • Il token può essere utilizzato per accedere alle risorse corrispondenti a uno qualsiasi degli ambiti incorporati nella nuova autorizzazione combinata.
    • Quando utilizzi il token di aggiornamento per l'autorizzazione combinata per ottenere un token di accesso, il token di accesso rappresenta l'autorizzazione combinata e può essere utilizzato per qualsiasi valore scope incluso nella risposta.
    • L'autorizzazione combinata include tutti gli ambiti concessi dall'utente al progetto API anche se le concessioni sono state richieste da clienti diversi. Ad esempio, se un utente ha concesso l'accesso a un ambito utilizzando il client desktop di un'applicazione e poi ha concesso un altro ambito alla stessa applicazione tramite un client mobile, l'autorizzazione combinata includerà entrambi gli ambiti.
    • Se revochi un token che rappresenta un'autorizzazione combinata, l'accesso a tutti gli ambiti di quell'autorizzazione per conto dell'utente associato viene revocato contemporaneamente.

    Gli esempi di codice specifici per lingua nel passaggio 1: imposta i parametri di autorizzazione e l'URL di reindirizzamento HTTP/REST di esempio nel passaggio 2: reindirizza al server OAuth 2.0 di Google utilizzano tutti l'autorizzazione incrementale. Gli esempi di codice riportati di seguito mostrano anche il codice da aggiungere per utilizzare l'autorizzazione incrementale.

    PHP

    $client->setIncludeGrantedScopes(true);

    Python

    In Python, imposta l'argomento della parola chiave include_granted_scopes su true per assicurarti che una richiesta di autorizzazione includa gli ambiti concessi in precedenza. È molto probabile che include_granted_scopes non sia l'unico argomento della parola chiave impostato, come показано nell'esempio seguente.

    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"}
    )

    Node.js

    const authorizationUrl = oauth2Client.generateAuthUrl({
      // 'online' (default) or 'offline' (gets refresh_token)
      access_type: 'offline',
      /** Pass in the scopes array defined above.
        * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
      scope: scopes,
      // Enable incremental authorization. Recommended as a best practice.
      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.metadata.readonly%20https%3A//www.googleapis.com/auth/calendar.readonly&
      redirect_uri=https%3A//oauth2.example.com/code&
      prompt=consent&
      include_granted_scopes=true

    Aggiornamento di un token di accesso (accesso offline)

    I token di accesso scadono periodicamente e diventano credenziali non valide per una richiesta API correlata. Puoi aggiornare un token di accesso senza chiedere all'utente l'autorizzazione (anche quando l'utente non è presente) se hai richiesto l'accesso offline agli ambiti associati al token.

    • Se utilizzi una libreria client dell'API di Google, l'oggetto client aggiorna il token di accesso in base alle necessità, a condizione che tu lo configuri per l'accesso offline.
    • Se non utilizzi una libreria client, devi impostare il parametro di query HTTP access_type su offline quando indirizzi l'utente al server OAuth 2.0 di Google. In questo caso, il server di autorizzazione di Google restituisce un token di aggiornamento quando scambi un codice di autorizzazione con un token di accesso. Se il token di accesso scade (o in qualsiasi altro momento), puoi utilizzare un token di aggiornamento per ottenerne uno nuovo.

    La richiesta di accesso offline è un requisito per qualsiasi applicazione che debba accedere a un'API di Google quando l'utente non è presente. Ad esempio, un'app che esegue servizi di backup o azioni in momenti prestabiliti deve essere in grado di aggiornare il token di accesso quando l'utente non è presente. Lo stile di accesso predefinito si chiama online.

    Le applicazioni web lato server, le applicazioni installate e i dispositivi ottengono tutti i token di aggiornamento durante la procedura di autorizzazione. I token di aggiornamento in genere non vengono utilizzati nelle applicazioni web lato client (JavaScript).

    PHP

    Se la tua applicazione ha bisogno di accedere offline a un'API di Google, imposta il tipo di accesso del client API su offline:

    $client->setAccessType("offline");

    Dopo che un utente ha concesso l'accesso offline agli ambiti richiesti, puoi continuare a utilizzare il client API per accedere alle API di Google per conto dell'utente quando è offline. L'oggetto client aggiornerà il token di accesso in base alle esigenze.

    Python

    In Python, imposta l'argomento della parola chiave access_type su offline per assicurarti di poter aggiornare il token di accesso senza dover chiedere nuovamente all'utente l'autorizzazione. È molto probabile che access_type non sia l'unico argomento della parola chiave impostato, come mostrato nell'esempio seguente.

    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')

    Dopo che un utente ha concesso l'accesso offline agli ambiti richiesti, puoi continuare a utilizzare il client API per accedere alle API di Google per conto dell'utente quando è offline. L'oggetto client aggiornerà il token di accesso in base alle esigenze.

    Ruby

    Se la tua applicazione ha bisogno di accedere offline a un'API di Google, imposta il tipo di accesso del client API su offline:

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

    Dopo che un utente ha concesso l'accesso offline agli ambiti richiesti, puoi continuare a utilizzare il client API per accedere alle API di Google per conto dell'utente quando è offline. L'oggetto client aggiornerà il token di accesso in base alle esigenze.

    Node.js

    Se la tua applicazione ha bisogno di accedere offline a un'API di Google, imposta il tipo di accesso del client API su offline:

    const authorizationUrl = oauth2Client.generateAuthUrl({
      // 'online' (default) or 'offline' (gets refresh_token)
      access_type: 'offline',
      /** Pass in the scopes array defined above.
        * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
      scope: scopes,
      // Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes: true
    });

    Dopo che un utente ha concesso l'accesso offline agli ambiti richiesti, puoi continuare a utilizzare il client API per accedere alle API di Google per conto dell'utente quando è offline. L'oggetto client aggiornerà il token di accesso in base alle esigenze.

    I token di accesso hanno una scadenza. Questa libreria utilizzerà automaticamente un token di aggiornamento per ottenere un nuovo token di accesso se sta per scadere. Un modo semplice per assicurarti di memorizzare sempre i token più recenti è utilizzare l'evento tokens:

    oauth2Client.on('tokens', (tokens) => {
      if (tokens.refresh_token) {
        // store the refresh_token in your secure persistent database
        console.log(tokens.refresh_token);
      }
      console.log(tokens.access_token);
    });

    Questo evento dei token si verifica solo nella prima autorizzazione e devi aver impostato access_type su offline quando chiami il metodo generateAuthUrl per ricevere il token di aggiornamento. Se hai già concesso all'app le autorizzazioni richieste senza impostare i vincoli appropriati per ricevere un token di aggiornamento, dovrai autorizzare nuovamente l'applicazione a ricevere un nuovo token di aggiornamento.

    Per impostare refresh_token in un secondo momento, puoi utilizzare il metodo setCredentials:

    oauth2Client.setCredentials({
      refresh_token: `STORED_REFRESH_TOKEN`
    });

    Una volta che il client ha un token di aggiornamento, i token di accesso verranno acquisiti e aggiornati automaticamente nella chiamata successiva all'API.

    HTTP/REST

    Per aggiornare un token di accesso, l'applicazione invia una richiesta POST HTTPS al server di autorizzazione di Google (https://oauth2.googleapis.com/token) che include i seguenti parametri:

    Campi
    client_id L'ID cliente ottenuto da API Console.
    client_secret Il client secret ottenuto da API Console.
    grant_type Come definito nella specifica OAuth 2.0, il valore di questo campo deve essere impostato su refresh_token.
    refresh_token Il token di aggiornamento restituito dallo scambio del codice di autorizzazione.

    Lo snippet seguente mostra una richiesta di esempio:

    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

    Se l'utente non ha revocato l'accesso concesso all'applicazione, il server di token restituisce un oggetto JSON contenente un nuovo token di accesso. Il seguente snippet mostra un'esempio di risposta:

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

    Tieni presente che esistono limiti al numero di token di aggiornamento che verranno emessi: un limite per combinazione di cliente/utente e un altro per utente su tutti i clienti. Devi salvare i token di aggiornamento in uno spazio di archiviazione a lungo termine e continuare a utilizzarli finché rimangono validi. Se la tua applicazione richiede troppi token di aggiornamento, potrebbe incontrare questi limiti, nel qual caso i token di aggiornamento meno recenti non funzioneranno più.

    Revocare un token

    In alcuni casi, un utente potrebbe voler revocare l'accesso concesso a un'applicazione. Un utente può revocare l'accesso visitando le Impostazioni account. Per saperne di più, consulta la sezione Rimuovere l'accesso di un sito o un'app del documento del Centro assistenza App e siti di terze parti con accesso al tuo account.

    È anche possibile che un'applicazione revochi in modo programmatico l'accesso che le è stato concesso. La revoca programmatica è importante nei casi in cui un utente annulla l'iscrizione, rimuove un'applicazione o le risorse dell'API richieste da un'app sono cambiate in modo significativo. In altre parole, parte del processo di rimozione può includere una richiesta API per garantire la rimozione delle autorizzazioni precedentemente concesse all'applicazione.

    PHP

    Per revocare un token tramite programmazione, chiama revokeToken():

    $client->revokeToken();

    Python

    Per revocare un token in modo programmatico, invia una richiesta a https://oauth2.googleapis.com/revoke che includa il token come parametro e imposti l'intestazione Content-Type:

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

    Ruby

    Per revocare un token in modo programmatico, invia una richiesta HTTP all'endpoint oauth2.revoke:

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

    Il token può essere un token di accesso o un token di aggiornamento. Se il token è un token di accesso e ha un token di aggiornamento corrispondente, anche il token di aggiornamento verrà revocato.

    Se la revoca viene elaborata correttamente, il codice di stato della risposta è 200. Per le condizioni di errore, viene restituito un codice di stato 400 insieme a un codice di errore.

    Node.js

    Per revocare un token in modo programmatico, invia una richiesta POST HTTPS all'endpoint /revoke:

    const https = require('https');
    
    // Build the string for the POST request
    let postData = "token=" + userCredential.access_token;
    
    // Options for POST request to Google's OAuth 2.0 server to revoke a token
    let postOptions = {
      host: 'oauth2.googleapis.com',
      port: '443',
      path: '/revoke',
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Content-Length': Buffer.byteLength(postData)
      }
    };
    
    // Set up the request
    const postReq = https.request(postOptions, function (res) {
      res.setEncoding('utf8');
      res.on('data', d => {
        console.log('Response: ' + d);
      });
    });
    
    postReq.on('error', error => {
      console.log(error)
    });
    
    // Post the request with data
    postReq.write(postData);
    postReq.end();

    Il parametro token può essere un token di accesso o un token di aggiornamento. Se il token è un token di accesso e ha un token di aggiornamento corrispondente, anche il token di aggiornamento verrà revocato.

    Se la revoca viene elaborata correttamente, il codice di stato della risposta è 200. Per le condizioni di errore, viene restituito un codice di stato 400 insieme a un codice di errore.

    HTTP/REST

    Per revocare un token in modo programmatico, l'applicazione invia una richiesta a https://oauth2.googleapis.com/revoke e include il token come parametro:

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

    Il token può essere un token di accesso o un token di aggiornamento. Se il token è un token di accesso e ha un token di aggiornamento corrispondente, anche il token di aggiornamento verrà revocato.

    Se la revoca viene elaborata correttamente, il codice di stato HTTP della risposta è 200. Per le condizioni di errore, viene restituito un codice di stato HTTP 400 insieme a un codice di errore.

    Implementare la Protezione su più account

    Un ulteriore passaggio da seguire per proteggere gli account dei tuoi utenti è implementare la protezione tra account utilizzando il servizio di protezione tra account di Google. Questo servizio ti consente di iscriverti alle notifiche relative agli eventi di sicurezza che forniscono informazioni alla tua applicazione su modifiche importanti all'account utente. Puoi quindi utilizzare le informazioni per intervenire in base a come decidi di rispondere agli eventi.

    Ecco alcuni esempi di tipi di eventi inviati alla tua app dal Servizio di protezione tra account di 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

    Per ulteriori informazioni su come implementare la funzionalità Protezione su più account e per l'elenco completo degli eventi disponibili, consulta la pagina Proteggere gli account utente con la Protezione su più account .