Questo documento spiega come le applicazioni server web utilizzano le librerie client delle API di Google o gli endpoint Google OAuth 2.0 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 degli utenti. È progettato per le applicazioni che possono archiviare informazioni riservate e mantenere lo stato. Un'applicazione server web autorizzata correttamente può accedere a un'API mentre l'utente interagisce con l'applicazione o dopo che l'utente ha abbandonato l'applicazione.
Le applicazioni server web utilizzano spesso anche service account per autorizzare le richieste API, in particolare quando chiamano le API Cloud per accedere ai dati basati su progetti anziché ai dati specifici dell'utente. Le applicazioni del server web possono utilizzare i service account insieme all'autorizzazione dell'utente.
Librerie client
Gli esempi specifici per i 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 l'applicazione deve acquisire nuovamente il consenso. La libreria client genera anche URL di reindirizzamento corretti e aiuta a implementare gestori di reindirizzamento che scambiano i codici di autorizzazione con i 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 abilitarle nella console API.
Per abilitare un'API per il tuo progetto:
- Apri la libreria API nella console API di Google.
- Se richiesto, seleziona un progetto o creane uno nuovo.
- La libreria API 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.
- Seleziona l'API che vuoi abilitare, quindi fai clic sul pulsante Abilita.
- Se richiesto, abilita la fatturazione.
- Se richiesto, leggi e accetta i Termini di servizio dell'API.
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 la identificano per il server OAuth 2.0 di Google. I passaggi seguenti spiegano come creare le credenziali per il tuo progetto. Le tue applicazioni possono quindi utilizzare le credenziali per accedere alle API che hai abilitato per quel progetto.
- Vai alla pagina Clienti.
- Fai clic su Crea client.
- Seleziona il tipo di applicazione Applicazione web.
- 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. Tutti gli esempi in questo documento utilizzanohttp://localhost:8080come URI di reindirizzamento.Ti consigliamo di progettare gli endpoint di autenticazione della tua app in modo che l'applicazione non esponga i codici di autorizzazione ad altre risorse della pagina.
Dopo aver creato le credenziali, scarica il file client_secret.json dalla console API. Archivia il file in modo sicuro in una posizione accessibile solo alla tua applicazione.
Identifica gli ambiti di accesso
Gli ambiti consentono alla tua applicazione di richiedere l'accesso solo alle risorse di cui ha bisogno, consentendo al contempo agli utenti di controllare il livello di accesso che concedono 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 per cui la tua app avrà bisogno dell'autorizzazione di accesso.
Ti consigliamo inoltre di richiedere l'accesso agli ambiti di autorizzazione tramite un processo di autorizzazione incrementale, in cui l'applicazione richiede l'accesso ai dati utente nel contesto. Questa best practice aiuta gli utenti a capire più facilmente perché la tua applicazione ha bisogno dell'accesso che sta richiedendo.
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 qualsiasi 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 il linguaggio nelle sezioni seguenti.
PHP
Per eseguire gli esempi di codice PHP in questo documento, devi disporre di:
- PHP 8.0 o versioni successive con l'interfaccia a riga di comando (CLI) e l'estensione JSON installate.
- Lo strumento di gestione delle dipendenze Composer.
-
La libreria client delle API di 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, devi disporre di:
- Python 3.7 o versioni successive
- Lo strumento di gestione dei pacchetti pip.
- La release 2.0 della libreria client delle API di Google per Python:
pip install --upgrade google-api-python-client
google-auth,google-auth-oauthlibegoogle-auth-httplib2per 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
Consulta la nota di rilascio della libreria client Python dell'API di Google se non riesci a eseguire l'upgrade di Python e della guida alla migrazione associata.
Ruby
Per eseguire gli esempi di codice Ruby in questo documento, devi:
- Ruby 2.6 o versioni successive
-
La libreria Google Auth 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 Sinatra Ruby.
gem install sinatra
Node.js
Per eseguire gli esempi di codice Node.js in questo documento, devi disporre di:
- La versione LTS di manutenzione, LTS attiva o corrente di Node.js.
-
Il client Node.js delle 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 seguenti mostrano come l'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 avere questo consenso prima di poter eseguire una richiesta API di Google che richiede l'autorizzazione dell'utente.
Il seguente elenco riassume rapidamente questi passaggi:
- La tua applicazione identifica le autorizzazioni di cui ha bisogno.
- L'applicazione reindirizza l'utente a Google insieme all'elenco delle autorizzazioni richieste.
- L'utente decide se concedere le autorizzazioni alla tua applicazione.
- La tua applicazione scopre la decisione dell'utente.
- 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 l'utente dovrà concedere alla tua applicazione.
- Se utilizzi una libreria client di Google per l'autenticazione e l'autorizzazione OAuth 2.0, devi creare e configurare un oggetto che definisca questi parametri.
- Se chiami direttamente l'endpoint Google OAuth 2.0, genererai un URL e imposterai i parametri su quell'URL.
Le seguenti schede definiscono i parametri di autorizzazione supportati per le applicazioni server web. Gli esempi specifici per 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 Creazione delle credenziali di autorizzazione. L'oggetto identifica anche 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 dal 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 nel calendario 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. Questo oggetto identifica anche gli ambiti per cui l'applicazione richiede l'autorizzazione di accesso e l'URL dell'endpoint di autenticazione dell'applicazione, che gestirà la risposta dal 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 nel calendario 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 l'applicazione deve accedere, insieme all'URL dell'endpoint di autenticazione dell'applicazione, che gestirà la risposta dal server OAuth 2.0.
Ad esempio, questo codice richiede l'accesso offline di sola lettura ai metadati di Google Drive e agli eventi nel calendario 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, come la generazione di URL di richiesta di autorizzazione e l'applicazione di 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 l'applicazione. Per chiedere a un utente le autorizzazioni per recuperare un token di accesso, reindirizzalo a una pagina di consenso. Per creare un URL della 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 semplici vengono rifiutate.
Il server di autorizzazione di Google supporta i seguenti parametri della stringa di query per le applicazioni server web:
| Parametri | |||||||
|---|---|---|---|---|---|---|---|
client_id |
Obbligatorio
L'ID client della tua applicazione. Puoi trovare questo valore nella pagina Client della console Cloud. |
||||||
redirect_uri |
Obbligatorio
Determina la pagina a cui il server API reindirizza l'utente dopo che quest'ultimo 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 nella pagina Client della console Cloud del tuo client. Se questo valore non corrisponde a un URI di reindirizzamento autorizzato per il Tieni presente che lo schema |
||||||
response_type |
Obbligatorio
Determina se l'endpoint Google OAuth 2.0 restituisce un codice di autorizzazione. Imposta il valore parametro su |
||||||
scope |
Obbligatorio
Un elenco di ambiti delimitati da spazi che identificano le risorse a cui l'applicazione potrebbe accedere per conto dell'utente. Questi valori informano la schermata per il 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 il livello 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 fare in modo che la tua applicazione richieda l'accesso agli ambiti di autorizzazione nel contesto, se possibile. Richiedendo l'accesso ai dati utente nel contesto, utilizzando l'autorizzazione incrementale, aiuti gli utenti a capire perché la tua applicazione ha bisogno dell'accesso che sta richiedendo. |
||||||
access_type |
Consigliato
Indica se l'applicazione può aggiornare i token di accesso quando l'utente non è presente nel browser. I valori parametro validi sono Imposta il valore su |
||||||
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 Puoi utilizzare questo parametro per diversi scopi, ad esempio per indirizzare l'utente alla risorsa corretta nella tua applicazione, inviare nonce e mitigare gli attacchi di tipo richiesta cross-site forgery. Poiché il tuo |
||||||
include_granted_scopes |
Facoltativo
Consente alle applicazioni di utilizzare l'autorizzazione incrementale per richiedere l'accesso ad ambiti aggiuntivi nel contesto. Se imposti il valore di questo parametro su |
||||||
enable_granular_consent |
Facoltativo
Il valore predefinito è Quando Google attiva le autorizzazioni granulari per un'applicazione, questo parametro non avrà più alcun effetto. |
||||||
login_hint |
Facoltativo
Se la tua applicazione conosce l'utente che sta tentando di eseguire l'autenticazione, 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 |
||||||
prompt |
Facoltativo
Un elenco di prompt sensibile alle maiuscole, delimitato da spazi, da presentare all'utente. Se non specifichi questo parametro, all'utente verrà chiesto di concedere l'accesso solo la prima volta che il tuo progetto lo richiede. Per saperne di più, consulta Richiedere nuovamente il consenso. I valori possibili sono:
|
||||||
Passaggio 2: reindirizza al server OAuth 2.0 di Google
Reindirizza l'utente al server OAuth 2.0 di Google per avviare il processo di autenticazione e autorizzazione. In genere, questo accade quando l'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 accedere per la prima volta a risorse aggiuntive per le quali non dispone dell'autorizzazione di accesso.
PHP
- Genera un URL per richiedere l'accesso dal server OAuth 2.0 di Google:
$auth_url = $client->createAuthUrl(); - 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 dell'applicazione web Flask:
return flask.redirect(authorization_url)
Ruby
- Genera un URL per richiedere l'accesso dal server OAuth 2.0 di Google:
auth_uri = authorizer.get_authorization_url(request: request)
- Reindirizza l'utente a
auth_uri.
Node.js
-
Utilizza l'URL generato
authorizationUrldal metodo Passaggio 1generateAuthUrlper richiedere l'accesso dal server OAuth 2.0 di Google. -
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 una maggiore 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//developers.google.com/oauthplayground& 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 alla tua applicazione utilizzando l'URL di reindirizzamento specificato.
Passaggio 3: Google chiede il consenso dell'utente
In questo passaggio, l'utente decide se concedere alla tua applicazione l'accesso richiesto. In questa fase, Google mostra una finestra di consenso che riporta il nome della tua applicazione e i servizi API di Google per cui richiede l'autorizzazione di accesso con le credenziali di autorizzazione dell'utente, nonché 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, ma deve attendere la risposta del server OAuth 2.0 di Google che indica se è stato concesso l'accesso. La risposta è spiegata nel passaggio successivo.
Errori
Le richieste all'endpoint di autorizzazione OAuth 2.0 di Google potrebbero visualizzare messaggi di errore rivolti agli utenti anziché i flussi di autenticazione e autorizzazione previsti. I codici di errore comuni e le soluzioni suggerite sono:
admin_policy_enforced
L'Account Google non è in grado di autorizzare uno o più ambiti richiesti a causa delle policy dell'amministratore 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 restrizioni fino a quando non viene concesso esplicitamente l'accesso al tuo ID client OAuth, consulta l'articolo del Centro assistenza per gli amministratori di Google Workspace Specifica quali app di terze parti e interne possono accedere ai dati di Google Workspace.
disallowed_useragent
L'endpoint di autorizzazione viene visualizzato all'interno di uno user agent incorporato non consentito dalle norme OAuth 2.0 di Google.
Gli sviluppatori iOS e macOS potrebbero riscontrare questo errore quando aprono le richieste di autorizzazione in WKWebView.
Gli sviluppatori devono invece utilizzare librerie iOS come
Accedi con Google 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 uno user agent 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 generali nel gestore dei link predefinito del sistema operativo, che include sia i gestori di link universali sia l'app del browser predefinita. 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 un' organizzazione Google Cloud specifica. Per saperne di più su questa opzione di configurazione, consulta la sezione Tipo di utente nell'articolo del Centro assistenza Configurazione della schermata per il consenso OAuth.
invalid_client
Il client secret OAuth non è corretto. Esamina la configurazione del client OAuth, inclusi l'ID client e il secret utilizzati per questa richiesta.
deleted_client
Il client OAuth utilizzato per effettuare la richiesta è stato eliminato. L'eliminazione può avvenire manualmente o automaticamente nel caso di client inutilizzati . I client eliminati possono essere ripristinati entro 30 giorni dall'eliminazione. Scopri di più .
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 consenso dell'utente per ottenere nuovi token. Se continui a visualizzare questo errore, assicurati che l'applicazione sia stata configurata correttamente e di utilizzare 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 nella pagina Client della console Google Cloud.
Il parametro redirect_uri potrebbe fare riferimento al flusso out-of-band (OOB) di OAuth, che è stato deprecato e non è più supportato. Consulta la guida alla migrazione per aggiornare l'integrazione.
invalid_request
Si è verificato un problema con la richiesta che hai effettuato. Ciò potrebbe essere dovuto a una serie di motivi:
- La richiesta non è stata formattata correttamente
- Nella richiesta mancavano i parametri obbligatori
- La richiesta utilizza un metodo di autorizzazione non supportato da Google. Verifica 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 della tua 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 negli esempi seguenti:
Una risposta di errore:
https://oauth2.example.com/auth?error=access_denied
Una risposta con 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 l'accesso di sola lettura per visualizzare i metadati dei file in Google Drive e l'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//developers.google.com/oauthplayground& client_id=client_id
Dopo aver completato il flusso OAuth 2.0, il browser ti reindirizza a OAuth 2.0 Playground, uno strumento per testare i flussi OAuth. Vedrai che OAuth 2.0 Playground ha acquisito automaticamente il codice di autorizzazione.
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 browser session storage, but for security: client_id, client_secret, # and token_uri are instead stored only on the backend server. credentials = flow.credentials flask.session['credentials'] = { 'token': credentials.token, 'refresh_token': credentials.refresh_token, '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, lo scambio del codice viene posticipato archiviando temporaneamente i risultati nella sessione dell'utente.
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 dalla pagina Clienti della console Cloud. |
client_secret |
Facoltativo
Il client secret ottenuto dalla pagina Client della console Cloud. |
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 nella pagina Client della console Cloud per il client_id specificato. |
Sebbene l'utilizzo di DPoP sia facoltativo, è consigliato per una maggiore sicurezza. La sicurezza di DPoP si basa sulla limitazione della chiave privata a un singolo dispositivo; ti consigliamo di archiviarla in modo che non possa essere copiata fuori dal dispositivo, ad esempio utilizzando TPM, Secure Enclave o altri keystore con crittografia hardware. Per utilizzare DPoP, l'applicazione deve generare un nuovo JWT di prova DPoP univoco per ogni richiesta all'endpoint del token e aggiungerlo come intestazione della richiesta HTTP.
| Intestazione | Obbligatorio | Descrizione |
|---|---|---|
DPoP |
Facoltativo | Una prova DPoP è un JWT che dimostra il possesso di una chiave privata. Si tratta di un'intestazione, non di un parametro. Se forniti, i token restituiti sono associati a questa chiave. Per ogni richiesta deve essere generata una nuova prova univoca, che deve includere le attestazioni htm (metodo HTTP) e htu (URI HTTP) corrispondenti alla richiesta. |
Il seguente snippet mostra una richiesta di esempio:
POST /token HTTP/1.1 Host: oauth2.googleapis.com Content-Type: application/x-www-form-urlencoded DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik\ VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR\ nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE\ QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiItQndDM0VTYzZhY2MybFRjIiwiaHRtIj\ oiUE9TVCIsImh0dSI6Imh0dHBzOi8vc2VydmVyLmV4YW1wbGUuY29tL3Rva2VuIiwia\ WF0IjoxNTYyMjYyNjE2fQ.2-GxA6T8lP4vfrg8v-FdWP0A0zdrj8igiMLvqRMUvwnQg\ 4PtFLbdLXiOSsX0x7NVY-FNyJK70nfbV37xRZT3Lg code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7& client_id=your_client_id& redirect_uri=https%3A//developers.google.com/oauthplayground& grant_type=authorization_code
Crea una prova DPoP
I passaggi seguenti mostrano come creare una prova DPoP utilizzando OpenSSL dalla riga di comando:
- Genera una coppia di chiavi EC P-256:
openssl ecparam -name prime256v1 -genkey -noout -out dpop_private.pem openssl ec -in dpop_private.pem -pubout -out dpop_public.pem
- Crea l'intestazione DPoP:
L'intestazione deve includere le attestazioni
typ,algejwk(chiave pubblica). I valorixeysono le coordinate con codifica Base64Url della tua chiave pubblica EC. Codifica questo JSON in Base64Url:{ "typ":"dpop+jwt", "alg":"ES256", "jwk": { "kty":"EC", "x":"YOUR_PUBLIC_KEY_X", "y":"YOUR_PUBLIC_KEY_Y", "crv":"P-256" } } - Crea il payload DPoP:
Il payload deve includere
jti(un identificatore univoco per la richiesta),htm(metodo HTTP, ad esempioPOST),htu(URI HTTP, ad esempiohttps://oauth2.googleapis.com/token) eiat(ora di emissione). Se hai ricevuto un nonce dal server in un'intestazioneDPoP-Noncenella risposta a una richiesta precedente, devi includere il valore del nonce in un claimnonce. La dichiarazione nonce è facoltativa per gli scambi di codici di autorizzazione e viene utilizzata solo quando l'intestazione DPoP-Nonce è stata ricevuta in precedenza. Codifica questo JSON in Base64Url:{ "jti":"JTI_VALUE", "htm":"POST", "htu":"https://oauth2.googleapis.com/token", "iat":YOUR_JWT_ISSUED_TIME, "nonce":"SERVER_PROVIDED_NONCE" }Il valore
jtidipende dal tipo di piattaforma di scambio:- Per gli scambi di codici di autorizzazione,
jtideve essere l'hash SHA256 con codifica Base64Url del codice di autorizzazione:"jti":"BASE64URL(SHA256(AUTHORIZATION_CODE))". - Per gli scambi di token di aggiornamento,
jtideve essere un identificatore univoco per richiesta:"jti":"YOUR_UNIQUE_PER_REQUEST_IDENTIFIER".
- Per gli scambi di codici di autorizzazione,
- Firma la bozza:
Concatena l'intestazione e il payload codificati con un punto (
.), quindi firma il risultato con la tua chiave privata utilizzando ES256. Tieni presente che JWS richiede che la firma sia in un formato concatenatoR | Snon elaborato (64 byte per P-256). Se utilizzi direttamente OpenSSL, devi convertire la firma predefinita con codifica ASN.1 DER in questo formato non elaborato.
Uno scambio riuscito è indicato da una risposta 200 OK contenente i token. Se durante lo scambio viene utilizzata una prova DPoP valida, il token di aggiornamento restituito da Google sarà associato alla tua chiave tramite DPoP, ma i token di accesso non saranno associati tramite DPoP. I token di accesso manterranno il token_type di
Bearer anziché DPoP.
Inoltre, Google restituisce un'intestazione HTTP DPoP-Nonce nella risposta.
Il client deve memorizzare nella cache questo nonce e includerlo nella dichiarazione nonce della prova DPoP nelle richieste successive (ad esempio quando scambia un token di aggiornamento con un nuovo token di accesso o quando chiama API protette da DPoP). Utilizzando questo nonce emesso in anticipo, puoi evitare un errore di round trip aggiuntivo (use_dpop_nonce) nella richiesta successiva.
Le prove DPoP devono essere incluse per le richieste di scambio di token effettuate con token di aggiornamento associati a DPoP.
Uno scambio non riuscito si verifica se l'intestazione DPoP non è presente quando prevista, non è valida o se la prova utilizza una chiave diversa da quella associata al token. In questi casi, il server restituisce un errore 400 Bad Request.
Se la prova DPoP presenta attestazioni htm o htu non corrispondenti, un'attestazione iat scaduta, un'attestazione jti riutilizzata o una firma non valida, Google restituisce un codice di errore invalid_dpop_proof.
Se è richiesto un nonce DPoP, ad esempio durante uno scambio di token di aggiornamento, e nella prova DPoP manca un claim nonce o il valore del nonce non è accettabile per il server (ad esempio, è scaduto, è già stato utilizzato o non è corretto), Google restituisce un codice di errore use_dpop_nonce insieme a un'intestazione HTTP DPoP-Nonce contenente un nuovo nonce che puoi utilizzare in una richiesta successiva.
Altri errori potrebbero restituire invalid_grant.
Google risponde a questa richiesta restituendo un oggetto JSON che contiene un token di accesso di breve durata e un token di aggiornamento.
Tieni presente che il token di aggiornamento viene restituito solo se l'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 che la tua applicazione invia per autorizzare una richiesta 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 o finché il token di aggiornamento non scade. Se è stato utilizzato DPoP, il token di aggiornamento è associato alla chiave privata utilizzata per firmare la prova DPoP.
Anche in questo caso, questo campo è presente in questa risposta solo se imposti il parametro access_type su offline nella richiesta iniziale al server di autorizzazione di Google.
|
refresh_token_expires_in |
La durata rimanente del token di aggiornamento in secondi. Questo valore viene impostato solo quando l'utente concede l'accesso basato sul tempo. |
scope |
Gli ambiti di accesso concessi da access_token espressi come un elenco di stringhe sensibili alle maiuscole delimitate da spazi. |
token_type |
Il tipo di token restituito. Questo valore è sempre Bearer, anche quando viene utilizzato DPoP. |
Il seguente snippet mostra un esempio di intestazioni e corpo della risposta corretta quando viene utilizzato DPoP:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
DPoP-Nonce: AN3XwJjZsjnb0ZuWkRlek8QU7wY-Zhf-5IP6tO0tORz0KgtDT1Bo8FX-w4nz3r5lnepI
{
"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. In questa sezione sono elencati i codici di errore comuni e le soluzioni suggerite.
invalid_grant
Il codice di autorizzazione fornito non è valido o è nel formato errato. Richiedi un nuovo codice riavviando la procedura OAuth per chiedere di nuovo il consenso all'utente.
Passaggio 6: controlla gli ambiti concessi dagli utenti
Quando richiedi più autorizzazioni (ambiti), gli utenti potrebbero non concedere alla tua app l'accesso a tutte. La tua app deve verificare quali ambiti sono stati effettivamente concessi e gestire correttamente le situazioni in cui alcune autorizzazioni vengono negate, in genere disattivando le funzionalità che si basano su questi ambiti negati.
Tuttavia, ci sono delle eccezioni. Le app Google Workspace Enterprise con delega di autorità a livello di dominio o le app contrassegnate come Attendibili ignorano la schermata per il consenso alle autorizzazioni granulari. Per queste app, gli utenti non vedranno la schermata per il consenso alle autorizzazioni granulari. La tua app riceverà invece tutti gli ambiti richiesti o nessuno.
Per informazioni più dettagliate, consulta Come gestire le autorizzazioni granulari.
PHP
Per verificare 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 di ambiti che l'utente ha concesso alla tua app.
credentials = flow.credentials flask.session['credentials'] = { 'token': credentials.token, 'refresh_token': credentials.refresh_token, '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 ambiti 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 ambiti 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 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 l'attività di Drive e gli eventi nel calendario:
{ "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 di Google completando i seguenti passaggi:
- Se devi applicare un token di accesso a un nuovo oggetto
Google\Client, ad esempio se hai memorizzato il token di accesso in una sessione utente, utilizza il metodosetAccessToken:$client->setAccessToken($access_token); - Crea un oggetto di servizio per l'API che vuoi chiamare. Per creare un oggetto di servizio, fornisci un oggetto
Google\Clientautorizzato al costruttore per l'API che vuoi chiamare. Ad esempio, per chiamare l'API Drive:$drive = new Google\Service\Drive($client); - Invia richieste al servizio API utilizzando l'
interfaccia fornita dall'oggetto di servizio.
Ad esempio, per elencare i file su Google Drive dell'utente autenticato:
$files = $drive->files->listFiles(array());
Python
Dopo aver ottenuto un token di accesso, la tua applicazione può utilizzarlo per autorizzare le richieste API per conto di un determinato account utente o service account. Utilizza le credenziali di autorizzazione specifiche dell'utente per creare un oggetto di servizio per l'API che vuoi chiamare, quindi utilizza l'oggetto per effettuare richieste API autorizzate.
- Crea un oggetto di servizio per l'API che vuoi chiamare. Puoi creare un oggetto di servizio chiamando il metodo
builddella libreriagoogleapiclient.discoverycon 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)
- Invia richieste al servizio API utilizzando l'interfaccia fornita dall'oggetto di servizio.
Ad esempio, per elencare i file su Google Drive dell'utente autenticato:
files = drive.files().list().execute()
Ruby
Dopo aver ottenuto un token di accesso, la tua applicazione può utilizzarlo per effettuare richieste API per conto di un determinato account utente o service account. Utilizza le credenziali di autorizzazione specifiche dell'utente per creare un oggetto di servizio per l'API che vuoi chiamare, quindi utilizza l'oggetto per effettuare richieste API autorizzate.
- Crea un oggetto di servizio per l'API che vuoi chiamare.
Ad esempio, per chiamare la versione 3 dell'API Drive:
drive = Google::Apis::DriveV3::DriveService.new
- Imposta le credenziali sul servizio:
drive.authorization = credentials
- Invia richieste al servizio API utilizzando l'interfaccia fornita dall'oggetto di servizio.
Ad esempio, per elencare i file nel Google Drive dell'utente autenticato:
files = drive.list_files
In alternativa, l'autorizzazione può essere fornita in base al metodo, fornendo il parametro options a 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 service account. Crea un oggetto di servizio per l'API che vuoi chiamare.
Ad esempio, il codice seguente utilizza l'API Google Drive per elencare i nomi file nel 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 sono stati concessi gli ambiti di accesso richiesti dall'API. 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 visualizzare i relativi ambiti in OAuth 2.0 Playground.
Esempi di HTTP GET
Una chiamata all'endpoint
drive.files (l'API Drive Files) utilizzando l'intestazione HTTP Authorization: Bearer potrebbe essere simile alla seguente. 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 (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 su Google Drive di un utente dopo che l'utente ha eseguito l'autenticazione e ha dato il consenso all'applicazione per accedere ai metadati di Drive dell'utente.
PHP
Per eseguire questo esempio:
- Nella console API, aggiungi l'URL della macchina locale all'elenco degli URL di reindirizzamento. Ad esempio, aggiungi
http://localhost:8080. - Crea una nuova directory e passa a questa directory. Ad esempio:
mkdir ~/php-oauth2-example cd ~/php-oauth2-example
- Installa la libreria client dell'API di Google per PHP utilizzando Composer:
composer require google/apiclient:^2.15.0
- Crea i file
index.phpeoauth2callback.phpcon i seguenti contenuti. - 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 vai 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 fittizia per chiamare l'API Calendar:questo link rimanda a una pagina fittizia che tenta di eseguire una richiesta API Calendar 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.
- Testa direttamente il flusso di autenticazione:questo link rimanda a una pagina che tenta di inviare l'utente tramite il flusso di autorizzazione. L'app richiede l'autorizzazione per inviare richieste API autorizzate per conto dell'utente.
- Revoca le credenziali attuali:questo link rimanda a una pagina che revoca le autorizzazioni che l'utente ha già concesso all'applicazione.
- Cancella le credenziali della sessione Flask:questo link cancella le credenziali di autorizzazione archiviate nella sessione Flask. In questo modo puoi vedere cosa succederebbe se un utente che aveva già concesso l'autorizzazione alla tua app provasse a eseguire una richiesta API in una nuova sessione. Inoltre, ti consente di visualizzare 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 tentato di autorizzare una richiesta con un token di accesso revocato.
# -*- coding: utf-8 -*- import os import flask import json 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 client secrets from the server-side file. with open(CLIENT_SECRETS_FILE, 'r') as f: client_config = json.load(f)['web'] # Load user-specific credentials from browser session storage. session_credentials = flask.session['credentials'] # Reconstruct the credentials object. credentials = google.oauth2.credentials.Credentials( refresh_token=session_credentials.get('refresh_token'), scopes=session_credentials.get('granted_scopes'), token=session_credentials.get('token'), client_id=client_config.get('client_id'), client_secret=client_config.get('client_secret'), token_uri=client_config.get('token_uri')) 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. flask.session['credentials'] = credentials_to_dict(credentials) return flask.jsonify(**files) else: # User didn't authorize read-only Drive activity permission. 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.') # Load client secrets from the server-side file. with open(CLIENT_SECRETS_FILE, 'r') as f: client_config = json.load(f)['web'] # Load user-specific credentials from the session. session_credentials = flask.session['credentials'] # Reconstruct the credentials object. credentials = google.oauth2.credentials.Credentials( refresh_token=session_credentials.get('refresh_token'), scopes=session_credentials.get('granted_scopes'), token=session_credentials.get('token'), client_id=client_config.get('client_id'), client_secret=client_config.get('client_secret'), token_uri=client_config.get('token_uri')) 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: # Clear the user's session credentials after successful revocation if 'credentials' in flask.session: del flask.session['credentials'] del flask.session['features'] 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, '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="/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="/drive">Call Drive API directly</a></td>' + '<td> Use stored credentials to call the API, you still might not be prompted to reauthorize ' + ' the application.</td></tr>' + '<tr><td><a href="/calendar">Call Calendar API directly</a></td>' + '<td> Use stored credentials to call the API, 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="/authorize">authorize</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:
-
Nella console API, aggiungi l'URL della macchina locale all'elenco degli URL di reindirizzamento. Ad esempio, aggiungi
http://localhost. - Assicurati di avere installato la versione LTS di manutenzione, la versione LTS attiva o la release corrente di Node.js.
-
Crea una nuova directory e passa a questa directory. Ad esempio:
mkdir ~/nodejs-oauth2-example cd ~/nodejs-oauth2-example
-
Installa la libreria client dell'API di Google per Node.js utilizzando npm:
npm install googleapis
-
Crea i file
main.jscon i seguenti contenuti. -
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 di Python utilizza il framework Flask e la libreria Requests per mostrare il flusso web OAuth 2.0. Per questo flusso, ti 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 dell'URI di reindirizzamento
Google applica le seguenti regole di convalida agli URI di reindirizzamento per aiutare gli sviluppatori a mantenere sicure le loro applicazioni. Gli URI di reindirizzamento devono rispettare queste regole. Consulta la sezione 3 di RFC 3986 per la definizione di dominio, host, percorso, query, schema e informazioni utente, utilizzati in queste regole.
| Regole di convalida | |
|---|---|
| Schema |
Gli URI di reindirizzamento devono utilizzare lo schema HTTPS, non il semplice HTTP. Gli URI localhost (inclusi gli URI degli 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 |
“googleusercontent.com”.goo.gl), a meno che l'app non sia proprietaria del dominio. Inoltre, se un'app proprietaria di un dominio di abbreviazione sceglie di reindirizzare 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 path traversal (chiamato anche backtracking della directory), rappresentato da |
| Query |
Gli URI di reindirizzamento non possono contenere reindirizzamenti aperti. |
| Frammento |
Gli URI di reindirizzamento non possono contenere il componente del frammento. |
| Caratteri |
Gli URI di reindirizzamento non possono contenere determinati caratteri, tra cui:
|
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 nel momento in cui ne hai bisogno. Per consentire questa pratica, il server di autorizzazione di Google supporta l'autorizzazione incrementale. Questa funzionalità ti consente di richiedere gli ambiti quando sono necessari e, se l'utente concede l'autorizzazione per il nuovo ambito, restituisce un codice di autorizzazione che può essere scambiato con un token contenente tutti gli ambiti concessi dall'utente al progetto.
Ad esempio, un'app che consente agli utenti 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, l'app deve accedere al suo Google Drive. La maggior parte delle persone troverebbe naturale che l'accesso a Google Drive venisse richiesto solo nel momento in cui 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, quindi richiedere l'ambito https://www.googleapis.com/auth/drive.file al momento della prima richiesta di salvataggio di 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.
A un token di accesso ottenuto da un'autorizzazione incrementale si applicano le seguenti regole:
- Il token può essere utilizzato per accedere alle risorse corrispondenti a uno qualsiasi degli ambiti inclusi 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 uno qualsiasi dei valori
scopeinclusi nella risposta. - L'autorizzazione combinata include tutti gli ambiti concessi dall'utente al progetto API, anche se le concessioni sono state richieste da client 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 questa autorizzazione per conto dell'utente associato viene revocato contemporaneamente.
Gli esempi di codice specifici per il linguaggio nel Passaggio 1: imposta il reindirizzamento dell'autorizzazione al server OAuth 2.0 di Google utilizzano tutti l'autorizzazione incrementale. I seguenti esempi di codice mostrano anche il codice che devi 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 di parola chiave che imposti, 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')
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//developers.google.com/oauthplayground& prompt=consent& include_granted_scopes=true
Aggiorna 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 l'autorizzazione all'utente (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 configuri l'oggetto per l'accesso offline.
- Se non utilizzi una libreria client, devi impostare il parametro di query HTTP
access_typesuofflinequando reindirizzi 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. In seguito, se il token di accesso scade (o in qualsiasi altro momento), puoi utilizzare un token di aggiornamento per ottenere un nuovo token di accesso.
La richiesta di accesso offline è un requisito per qualsiasi applicazione che deve accedere a un'API di Google quando l'utente non è presente. Ad esempio, un'app che esegue servizi di backup o
esegue azioni in orari predeterminati deve essere in grado di aggiornare il proprio token di accesso quando l'utente
non è presente. Lo stile di accesso predefinito è chiamato online.
Le applicazioni web lato server, le applicazioni installate e i dispositivi ottengono tutti i token di aggiornamento durante il processo di autorizzazione. I token di aggiornamento non vengono in genere utilizzati nelle applicazioni web lato client (JavaScript).
PHP
Se la tua applicazione richiede l'accesso offline a un'API di Google, imposta il tipo di accesso del client API su offline:
$client->setAccessType("offline");Dopo che un utente concede l'accesso offline agli ambiti richiesti, puoi continuare a utilizzare il client API per accedere alle API di Google per conto dell'utente quando quest'ultimo è 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 l'autorizzazione all'utente. È molto probabile che access_type non sia l'unico argomento di parole chiave che imposti, 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 concede l'accesso offline agli ambiti richiesti, puoi continuare a utilizzare il client API per accedere alle API di Google per conto dell'utente quando quest'ultimo è offline. L'oggetto client aggiornerà il token di accesso in base alle esigenze.
Ruby
Se la tua applicazione richiede l'accesso 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 concede l'accesso offline agli ambiti richiesti, puoi continuare a utilizzare il client API per accedere alle API di Google per conto dell'utente quando quest'ultimo è offline. L'oggetto client aggiornerà il token di accesso in base alle esigenze.
Node.js
Se la tua applicazione richiede l'accesso 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 concede l'accesso offline agli ambiti richiesti, puoi continuare a utilizzare il client API per accedere alle API di Google per conto dell'utente quando quest'ultimo è offline. L'oggetto client aggiornerà il token di accesso in base alle esigenze.
I token di accesso scadono. 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 relativo ai 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 alla tua app le autorizzazioni necessarie senza impostare i vincoli appropriati per la ricezione di un token di aggiornamento, dovrai autorizzare nuovamente l'applicazione per 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 HTTPS POST al server di autorizzazione di Google (https://oauth2.googleapis.com/token) che include i seguenti parametri nel corpo della richiesta:
| Nome | Valore |
|---|---|
client_id |
L'ID client ottenuto dalla console API. |
client_secret |
Facoltativo
Il client secret ottenuto dalla console API. |
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. |
Sebbene l'utilizzo di DPoP sia facoltativo, è consigliato per una maggiore sicurezza. Per utilizzare DPoP con un token di aggiornamento, l'applicazione deve generare un nuovo JWT di prova DPoP univoco per ogni richiesta all'endpoint del token. Questa prova deve essere firmata con la stessa chiave privata utilizzata durante lo scambio iniziale del codice di autorizzazione. La tua applicazione aggiunge la prova come intestazione della richiesta HTTP.
| Intestazione | Obbligatorio | Descrizione |
|---|---|---|
DPoP |
Facoltativo | Una prova DPoP è un JWT che dimostra il possesso di una chiave privata. Si tratta di un'intestazione, non di un parametro. Se forniti, i token restituiti sono associati a questa chiave. Per ogni richiesta deve essere generata una nuova prova univoca, che deve includere le attestazioni htm (metodo HTTP) e htu (URI HTTP) corrispondenti alla richiesta. |
Il seguente snippet mostra una richiesta di esempio:
POST /token HTTP/1.1 Host: oauth2.googleapis.com Content-Type: application/x-www-form-urlencoded DPoP: DPOP_PROOF_JWT client_id=your_client_id& refresh_token=refresh_token& grant_type=refresh_token
Per utilizzare DPoP con un token di aggiornamento, devi generare un nuovo JWT di prova DPoP univoco per la richiesta. Consulta Crea una prova DPoP per istruzioni passo passo sulla generazione della coppia di chiavi e sulla creazione del JWT.
Uno scambio riuscito è indicato da una risposta 200 OK contenente un nuovo token di accesso. Quando viene utilizzato DPoP, token_type è Bearer. Una risposta positiva conferma che la prova DPoP per il token di aggiornamento è stata accettata. Google potrebbe anche restituire una nuova intestazione HTTP DPoP-Nonce nella risposta. Se restituita, il client deve memorizzare nella cache questo nonce e includerlo nella rivendicazione nonce della prova DPoP nelle richieste successive.
Uno scambio non riuscito si verifica se l'intestazione DPoP è mancante, non valida o utilizza una chiave errata. Per informazioni dettagliate su codici di errore DPoP specifici e sulla gestione dei nonce, consulta Scambio non riuscito.
Il seguente snippet mostra un esempio di intestazioni e corpo della risposta corretta quando viene utilizzato DPoP:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
DPoP-Nonce: AN3XwJjZsjnb0ZuWkRlek8QU7wY-Zhf-5IP6tO0tORz0KgtDT1Bo8FX-w4nz3r5lnepI
{
"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 client/utente e un altro per utente in tutti i client. Devi salvare i token di aggiornamento nello spazio di archiviazione a lungo termine e continuare a utilizzarli finché rimangono validi. Se la tua applicazione richiede troppi token di aggiornamento, potrebbe raggiungere questi limiti e, in questo caso, i token di aggiornamento meno recenti smetteranno di funzionare.
Revoca dei 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 ulteriori informazioni, consulta la sezione Rimuovere l'accesso di un sito o di un'app del documento di assistenza Siti e app di terze parti con accesso al tuo account.
È anche possibile che un'applicazione revochi l'accesso concesso in modo programmatico. La revoca programmatica è importante nei casi in cui un utente annulla l'iscrizione, rimuove un'applicazione o le risorse 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 che le autorizzazioni precedentemente concesse all'applicazione vengano rimosse.
PHP
Per revocare un token in modo programmatico, 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, verrà revocato anche il token di aggiornamento.
Se la revoca viene elaborata correttamente, il codice di stato della risposta è
200. In caso di 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, verrà revocato anche il token di aggiornamento.
Se la revoca viene elaborata correttamente, il codice di stato della risposta è
200. In caso di 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, verrà revocato anche il token di aggiornamento.
Se la revoca viene elaborata correttamente, il codice di stato HTTP della risposta è
200. In caso di condizioni di errore, viene restituito un codice di stato HTTP 400 insieme a un codice di errore.
Accesso in base al tempo
L'accesso basato sul tempo consente a un utente di concedere alla tua app l'accesso ai suoi dati per un periodo di tempo limitato per completare un'azione. L'accesso basato sul tempo è disponibile in alcuni prodotti Google durante il flusso di consenso e offre agli utenti la possibilità di concedere l'accesso per un periodo di tempo limitato. Un esempio è l' API Data Portability, che consente un trasferimento dei dati una tantum.
Quando un utente concede alla tua applicazione l'accesso basato sul tempo, il token di aggiornamento scade dopo la durata specificata. Tieni presente che i token di aggiornamento potrebbero essere invalidati prima in circostanze specifiche; per maggiori dettagli, consulta questi casi. In questi casi, il campo refresh_token_expires_in restituito nella risposta dello scambio del codice di autorizzazione rappresenta il tempo rimanente prima della scadenza del token di aggiornamento.
Implementa la Protezione su più account
Un ulteriore passaggio da eseguire per proteggere gli account degli utenti è l'implementazione della Protezione su più account utilizzando il servizio Protezione su più account di Google. Questo servizio ti consente di iscriverti alle notifiche di eventi di sicurezza che forniscono alla tua applicazione informazioni su modifiche importanti all'account utente. Puoi quindi utilizzare le informazioni per passare all'azione a seconda di come decidi di rispondere agli eventi.
Ecco alcuni esempi dei tipi di eventi inviati alla tua app dal servizio di Protezione su più 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 protezione su più account e per l'elenco completo degli eventi disponibili, consulta la pagina Proteggi gli account utente con la protezione su più account .