Utiliser OAuth 2.0 pour les applications de serveur Web

Ce document explique comment les applications de serveur Web utilisent les bibliothèques clientes pour les API Google ou les points de terminaison Google OAuth 2.0 afin de mettre en œuvre l'autorisation OAuth 2.0 pour l'accès aux API Google.

OAuth 2.0 permet aux utilisateurs de partager des données spécifiques avec une application tout en préservant la confidentialité de leurs noms d'utilisateur, mots de passe et autres informations. Par exemple, une application peut utiliser OAuth 2.0 pour obtenir l'autorisation des utilisateurs de stocker des fichiers dans leur Google Drive.

Ce flux OAuth 2.0 est spécifiquement destiné à l'autorisation des utilisateurs. Il est conçu pour les applications pouvant stocker des informations confidentielles et gérer l'état. Une application de serveur Web correctement autorisée peut accéder à une API pendant que l'utilisateur interagit avec l'application ou après que l'utilisateur a quitté l'application.

Les applications de serveur Web utilisent également fréquemment des comptes de service pour autoriser les requêtes d'API, en particulier lors de l'appel d'API Cloud pour accéder aux données basées sur le projet plutôt qu'aux données spécifiques à l'utilisateur. Les applications de serveur Web peuvent utiliser des comptes de service en association avec l'autorisation de l'utilisateur.

Bibliothèques clientes

Les exemples spécifiques au langage présentés sur cette page utilisent les bibliothèques clientes des API Google pour mettre en œuvre l'autorisation OAuth 2.0. Pour exécuter les exemples de code, vous devez d'abord installer la bibliothèque cliente associée à votre langage.

Lorsque vous utilisez une bibliothèque cliente d'API Google pour gérer le flux OAuth 2.0 de votre application, la bibliothèque cliente effectue de nombreuses actions que l'application devrait gérer elle-même. Par exemple, il détermine quand l'application peut utiliser ou actualiser les jetons d'accès stockés, ainsi que quand elle doit récupérer l'autorisation. La bibliothèque cliente génère également les URL de redirection appropriées et aide à implémenter des gestionnaires de redirection qui échangent des codes d'autorisation contre des jetons d'accès.

Les bibliothèques clientes des API Google pour les applications côté serveur sont disponibles pour les langages suivants:

Prérequis

Activer les API pour votre projet.

Toute application qui appelle des API Google doit les activer dans API Console.

Pour activer une API pour votre projet:

  1. Open the API Library dans le Google API Console.
  2. If prompted, select a project, or create a new one.
  3. API Library répertorie toutes les API disponibles, regroupées par famille de produits et par popularité. Si l'API que vous souhaitez activer n'apparaît pas dans la liste, utilisez la fonctionnalité de recherche pour la trouver ou cliquez sur Tout afficher dans la famille de produits à laquelle elle appartient.
  4. Sélectionnez l'API que vous souhaitez activer, puis cliquez sur le bouton Activer.
  5. If prompted, enable billing.
  6. If prompted, read and accept the API's Terms of Service.

Créer des identifiants d'autorisation

Toute application qui utilise OAuth 2.0 pour accéder aux API Google doit disposer d'identifiants d'autorisation qui identifient l'application auprès du serveur OAuth 2.0 de Google. Les étapes suivantes expliquent comment créer des identifiants pour votre projet. Vos applications peuvent ensuite utiliser les identifiants pour accéder aux API que vous avez activées pour ce projet.

  1. Go to the Credentials page.
  2. Cliquez sur Créer des identifiants > ID client OAuth.
  3. Sélectionnez le type d'application Application Web.
  4. Remplissez le formulaire, puis cliquez sur Créer. Les applications qui utilisent des langages et des frameworks tels que PHP, Java, Python, Ruby et .NET doivent spécifier des URI de redirection autorisés. Les URI de redirection sont les points de terminaison vers lesquels le serveur OAuth 2.0 peut envoyer des réponses. Ces points de terminaison doivent respecter les règles de validation de Google.

    Pour les tests, vous pouvez spécifier des URI qui font référence à la machine locale, comme http://localhost:8080. À cet égard, notez que tous les exemples de ce document utilisent http://localhost:8080 comme URI de redirection.

    Nous vous recommandons de concevoir les points de terminaison d'autorisation de votre application afin que votre application n'expose pas les codes d'autorisation à d'autres ressources de la page.

Après avoir créé vos identifiants, téléchargez le fichier client_secret.json à partir de API Console. Stockez le fichier de manière sécurisée dans un emplacement auquel seule votre application peut accéder.

Identifier les niveaux d'accès

Les champs d'application permettent à votre application de demander uniquement l'accès aux ressources dont elle a besoin, tout en permettant aux utilisateurs de contrôler le nombre d'accès qu'ils accordent à votre application. Par conséquent, il peut exister une relation inverse entre le nombre de champs d'application demandés et la probabilité d'obtenir le consentement de l'utilisateur.

Avant de commencer à implémenter l'autorisation OAuth 2.0, nous vous recommandons d'identifier les champs d'application pour lesquels votre application aura besoin d'une autorisation d'accès.

Nous vous recommandons également de demander à votre application d'accéder aux champs d'application d'autorisation via un processus d'autorisation incrémentielle, dans lequel votre application demande l'accès aux données utilisateur en contexte. Cette bonne pratique permet aux utilisateurs de comprendre plus facilement pourquoi votre application a besoin de l'accès qu'elle demande.

Le document Champs d'application des API OAuth 2.0 contient la liste complète des champs d'application que vous pouvez utiliser pour accéder aux API Google.

Exigences spécifiques à la langue

Pour exécuter l'un des exemples de code de ce document, vous avez besoin d'un compte Google, d'un accès à Internet et d'un navigateur Web. Si vous utilisez l'une des bibliothèques clientes de l'API, consultez également les exigences spécifiques à chaque langage ci-dessous.

PHP

Pour exécuter les exemples de code PHP de ce document, vous avez besoin des éléments suivants:

  • PHP 8.0 ou version ultérieure avec l'interface de ligne de commande (CLI) et l'extension JSON installées
  • L'outil de gestion des dépendances Composer
  • Bibliothèque cliente des API Google pour PHP:

    composer require google/apiclient:^2.15.0

Pour en savoir plus, consultez la page Bibliothèque cliente des API Google pour PHP.

Python

Pour exécuter les exemples de code Python de ce document, vous avez besoin des éléments suivants:

  • Python 3.7 ou version ultérieure
  • L'outil de gestion de paquets pip
  • La version 2.0 de la bibliothèque cliente des API Google pour Python:
    pip install --upgrade google-api-python-client
  • google-auth, google-auth-oauthlib et google-auth-httplib2 pour l'autorisation des utilisateurs.
    pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2
  • Framework d'application Web Python Flask
    pip install --upgrade flask
  • Bibliothèque HTTP requests.
    pip install --upgrade requests

Consultez la note de version de la bibliothèque cliente Python des API Google si vous ne parvenez pas à mettre à niveau Python et le guide de migration associé.

Ruby

Pour exécuter les exemples de code Ruby de ce document, vous avez besoin des éléments suivants:

  • Ruby 2.6 ou version ultérieure
  • La bibliothèque Google Auth pour Ruby:

    gem install googleauth
  • Les bibliothèques clientes pour les API Google Drive et Agenda:

    gem install google-apis-drive_v3 google-apis-calendar_v3
  • Framework d'application Web Ruby Sinatra.

    gem install sinatra

Node.js

Pour exécuter les exemples de code Node.js de ce document, vous avez besoin des éléments suivants:

  • La version LTS de maintenance, la version LTS active ou la version actuelle de Node.js.
  • Le client Node.js des API Google:

    npm install googleapis crypto express express-session

HTTP/REST

Vous n'avez pas besoin d'installer de bibliothèques pour pouvoir appeler directement les points de terminaison OAuth 2.0.

Obtenir des jetons d'accès OAuth 2.0

Les étapes suivantes montrent comment votre application interagit avec le serveur OAuth 2.0 de Google pour obtenir le consentement d'un utilisateur afin d'effectuer une requête API en son nom. Votre application doit disposer de ce consentement avant de pouvoir exécuter une requête d'API Google nécessitant l'autorisation de l'utilisateur.

La liste ci-dessous résume rapidement ces étapes:

  1. Votre application identifie les autorisations dont elle a besoin.
  2. Votre application redirige l'utilisateur vers Google avec la liste des autorisations demandées.
  3. L'utilisateur décide d'accorder ou non les autorisations à votre application.
  4. Votre application détermine la décision de l'utilisateur.
  5. Si l'utilisateur a accordé les autorisations demandées, votre application récupère les jetons nécessaires pour effectuer des requêtes API au nom de l'utilisateur.

Étape 1: Définissez les paramètres d'autorisation

La première étape consiste à créer la demande d'autorisation. Cette requête définit des paramètres qui identifient votre application et définissent les autorisations que l'utilisateur sera invité à accorder à votre application.

  • Si vous utilisez une bibliothèque cliente Google pour l'authentification et l'autorisation OAuth 2.0, vous créez et configurez un objet qui définit ces paramètres.
  • Si vous appelez directement le point de terminaison Google OAuth 2.0, vous générez une URL et définissez les paramètres sur cette URL.

Les onglets ci-dessous définissent les paramètres d'autorisation acceptés pour les applications de serveur Web. Les exemples spécifiques au langage montrent également comment utiliser une bibliothèque cliente ou une bibliothèque d'autorisation pour configurer un objet qui définit ces paramètres.

PHP

L'extrait de code suivant crée un objet Google\Client(), qui définit les paramètres de la requête d'autorisation.

Cet objet utilise les informations de votre fichier client_secret.json pour identifier votre application. (Pour en savoir plus sur ce fichier, consultez la section Créer des identifiants d'autorisation.) L'objet identifie également les habilitations auxquelles votre application demande l'autorisation d'accéder et l'URL du point de terminaison d'authentification de votre application, qui gérera la réponse du serveur OAuth 2.0 de Google. Enfin, le code définit les paramètres facultatifs access_type et include_granted_scopes.

Par exemple, ce code demande un accès hors connexion en lecture seule aux métadonnées Google Drive et aux événements Agenda d'un utilisateur:

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

L'extrait de code suivant utilise le module google-auth-oauthlib.flow pour créer la requête d'autorisation.

Le code crée un objet Flow, qui identifie votre application à l'aide des informations du fichier client_secret.json que vous avez téléchargé après avoir créé des identifiants d'autorisation. Cet objet identifie également les habilitations auxquelles votre application demande l'autorisation d'accéder et l'URL du point de terminaison d'authentification de votre application, qui gérera la réponse du serveur OAuth 2.0 de Google. Enfin, le code définit les paramètres facultatifs access_type et include_granted_scopes.

Par exemple, ce code demande un accès hors connexion en lecture seule aux métadonnées Google Drive et aux événements Agenda d'un utilisateur:

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

Utilisez le fichier client_secrets.json que vous avez créé pour configurer un objet client dans votre application. Lorsque vous configurez un objet client, vous spécifiez les portées auxquelles votre application doit accéder, ainsi que l'URL du point de terminaison d'authentification de votre application, qui gérera la réponse du serveur OAuth 2.0.

Par exemple, ce code demande un accès hors connexion en lecture seule aux métadonnées Google Drive et aux événements Agenda d'un utilisateur:

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)

Votre application utilise l'objet client pour effectuer des opérations OAuth 2.0, telles que la génération d'URL de requête d'autorisation et l'application de jetons d'accès aux requêtes HTTP.

Node.js

L'extrait de code suivant crée un objet google.auth.OAuth2, qui définit les paramètres de la requête d'autorisation.

Cet objet utilise les informations de votre fichier client_secret.json pour identifier votre application. Pour demander à un utilisateur d'autoriser la récupération d'un jeton d'accès, vous devez le rediriger vers une page de consentement. Pour créer une URL de page de consentement:

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

Remarque importante : Le refresh_token n'est renvoyé que lors de la première autorisation. Pour en savoir plus, cliquez ici.

HTTP/REST

Le point de terminaison OAuth 2.0 de Google se trouve à l'adresse https://accounts.google.com/o/oauth2/v2/auth. Ce point de terminaison n'est accessible que via HTTPS. Les connexions HTTP simples sont refusées.

Le serveur d'autorisation Google est compatible avec les paramètres de chaîne de requête suivants pour les applications de serveur Web:

Paramètres
client_id Obligatoire

ID client de votre application. Vous pouvez trouver cette valeur dans le API Console Credentials page.

redirect_uri Obligatoire

Détermine vers quelle page le serveur d'API redirige l'utilisateur une fois qu'il a terminé le flux d'autorisation. La valeur doit correspondre exactement à l'un des URI de redirection autorisés pour le client OAuth 2.0, que vous avez configuré dans le API Console Credentials pagede votre client. Si cette valeur ne correspond pas à un URI de redirection autorisé pour le client_id fourni, une erreur redirect_uri_mismatch s'affiche.

Notez que le schéma http ou https, la casse et la barre oblique finale ("/") doivent tous correspondre.

response_type Obligatoire

Détermine si le point de terminaison OAuth 2.0 de Google renvoie un code d'autorisation.

Définissez la valeur du paramètre sur code pour les applications de serveur Web.

scope Obligatoire

Liste des champs d'application séparés par des espaces qui identifient les ressources auxquelles votre application peut accéder pour le compte de l'utilisateur. Ces valeurs renseignent l'écran de consentement que Google affiche à l'utilisateur.

Les champs d'application permettent à votre application de demander uniquement l'accès aux ressources dont elle a besoin, tout en permettant aux utilisateurs de contrôler le nombre d'accès qu'ils accordent à votre application. Par conséquent, il existe une relation inverse entre le nombre de champs d'application demandés et la probabilité d'obtenir le consentement de l'utilisateur.

Nous vous recommandons de demander à votre application d'accéder aux portées d'autorisation dans le contexte chaque fois que cela est possible. En demandant l'accès aux données utilisateur en contexte, via une autorisation incrémentielle, vous aidez les utilisateurs à comprendre plus facilement pourquoi votre application a besoin de l'accès qu'elle demande.

access_type Recommandé

Indique si votre application peut actualiser les jetons d'accès lorsque l'utilisateur n'est pas présent sur le navigateur. Les valeurs de paramètre valides sont online, qui est la valeur par défaut, et offline.

Définissez la valeur sur offline si votre application doit actualiser les jetons d'accès lorsque l'utilisateur n'est pas présent devant le navigateur. Il s'agit de la méthode d'actualisation des jetons d'accès décrite plus loin dans ce document. Cette valeur indique au serveur d'autorisation Google de renvoyer un jeton d'actualisation et un jeton d'accès la première fois que votre application échange un code d'autorisation contre des jetons.

state Recommandé

Spécifie toute valeur de chaîne que votre application utilise pour maintenir l'état entre votre demande d'autorisation et la réponse du serveur d'autorisation. Le serveur renvoie la valeur exacte que vous envoyez en tant que paire name=value dans le composant de requête d'URL (?) de redirect_uri une fois que l'utilisateur a accepté ou refusé la requête d'accès de votre application.

Vous pouvez utiliser ce paramètre à plusieurs fins, par exemple pour rediriger l'utilisateur vers la ressource appropriée dans votre application, envoyer des nonces et atténuer la falsification de requêtes intersites. Étant donné que votre redirect_uri peut être deviné, l'utilisation d'une valeur state peut vous assurer qu'une connexion entrante est le résultat d'une requête d'authentification. Si vous générez une chaîne aléatoire ou encodez le hachage d'un cookie ou d'une autre valeur qui capture l'état du client, vous pouvez valider la réponse pour vous assurer en outre que la requête et la réponse proviennent du même navigateur, ce qui vous protège contre les attaques telles que la falsification de requêtes intersites. Consultez la documentation OpenID Connect pour savoir comment créer et confirmer un jeton state.

include_granted_scopes Optional

Permet aux applications d'utiliser l'autorisation incrémentielle pour demander l'accès à des champs d'application supplémentaires en contexte. Si vous définissez la valeur de ce paramètre sur true et que la requête d'autorisation est accordée, le nouveau jeton d'accès couvrira également tous les champs d'application auxquels l'utilisateur a précédemment accordé l'accès à l'application. Pour obtenir des exemples, consultez la section Autorisation incrémentielle.

login_hint Optional

Si votre application sait quel utilisateur tente de s'authentifier, elle peut utiliser ce paramètre pour fournir un indice au serveur d'authentification Google. Le serveur utilise l'indice pour simplifier le flux de connexion en préremplissant le champ d'adresse e-mail dans le formulaire de connexion ou en sélectionnant la session multiconnexion appropriée.

Définissez la valeur du paramètre sur une adresse e-mail ou un identifiant sub, qui est équivalent à l'ID Google de l'utilisateur.

prompt Optional

Liste d'invites à présenter à l'utilisateur, délimitée par des espaces et sensible à la casse. Si vous ne spécifiez pas ce paramètre, l'utilisateur ne sera invité qu'à la première fois que votre projet demandera l'accès. Pour en savoir plus, consultez la section Demander un nouveau consentement.

Les valeurs possibles sont :

none N'affichez aucun écran d'authentification ni d'autorisation. Ne doit pas être spécifié avec d'autres valeurs.
consent Demandez à l'utilisateur de donner son consentement.
select_account Invitez l'utilisateur à sélectionner un compte.

Étape 2: Rediriger vers le serveur OAuth 2.0 de Google

Redirigez l'utilisateur vers le serveur OAuth 2.0 de Google pour lancer le processus d'authentification et d'autorisation. Cela se produit généralement lorsque votre application doit accéder pour la première fois aux données de l'utilisateur. Dans le cas de l'autorisation incrémentielle, cette étape se produit également lorsque votre application doit d'abord accéder à des ressources supplémentaires auxquelles elle n'est pas encore autorisée.

PHP

  1. Générez une URL pour demander l'accès au serveur OAuth 2.0 de Google:
    $auth_url = $client->createAuthUrl();
  2. Rediriger l'utilisateur vers $auth_url:
    header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));

Python

Cet exemple montre comment rediriger l'utilisateur vers l'URL d'autorisation à l'aide du framework d'application Web Flask:

return flask.redirect(authorization_url)

Ruby

  1. Générez une URL pour demander l'accès au serveur OAuth 2.0 de Google:
    auth_uri = authorizer.get_authorization_url(request: request)
  2. Redirigez l'utilisateur vers auth_uri.

Node.js

  1. Utilisez l'URL authorizationUrl générée à l'étape 1 de la méthode generateAuthUrl pour demander l'accès au serveur OAuth 2.0 de Google.
  2. Redirigez l'utilisateur vers authorizationUrl.
    res.redirect(authorizationUrl);

HTTP/REST

Exemple de redirection vers le serveur d'autorisation de Google

Vous trouverez ci-dessous un exemple d'URL, avec des sauts de ligne et des espaces pour une meilleure lisibilité.

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

Une fois l'URL de la requête créée, redirigez-y l'utilisateur.

Le serveur OAuth 2.0 de Google authentifie l'utilisateur et obtient son consentement pour que votre application puisse accéder aux habilitations demandées. La réponse est renvoyée à votre application à l'aide de l'URL de redirection que vous avez spécifiée.

Étape 3: Google demande à l'utilisateur son consentement

À cette étape, l'utilisateur décide d'accorder ou non l'accès demandé à votre application. À ce stade, Google affiche une fenêtre de consentement indiquant le nom de votre application et les services de l'API Google auxquels il demande l'autorisation d'accéder à l'aide des identifiants de l'utilisateur, ainsi qu'un récapitulatif des niveaux d'accès à accorder. L'utilisateur peut alors accepter d'accorder l'accès à un ou plusieurs champs d'application demandés par votre application ou refuser la requête.

À ce stade, votre application n'a rien à faire, car elle attend la réponse du serveur OAuth 2.0 de Google indiquant si un accès a été accordé. Cette réponse est expliquée à l'étape suivante.

Erreurs

Les requêtes adressées au point de terminaison d'autorisation OAuth 2.0 de Google peuvent afficher des messages d'erreur destinés aux utilisateurs au lieu des flux d'authentification et d'autorisation attendus. Vous trouverez ci-dessous les codes d'erreur courants et les solutions suggérées.

admin_policy_enforced

Le compte Google ne peut pas autoriser un ou plusieurs champs d'application demandés en raison des règles de son administrateur Google Workspace. Pour en savoir plus sur la façon dont un administrateur peut restreindre l'accès à tous les champs d'application ou à des champs d'application sensibles et limités jusqu'à ce que l'accès soit explicitement accordé à votre ID client OAuth, consultez l'article d'aide pour les administrateurs Google Workspace Contrôler l'accès des applications tierces et internes aux données Google Workspace.

disallowed_useragent

Le point de terminaison d'autorisation s'affiche dans un user-agent intégré non autorisé par les Règles OAuth 2.0 de Google.

Android

Les développeurs Android peuvent rencontrer ce message d'erreur lorsqu'ils ouvrent des requêtes d'autorisation dans android.webkit.WebView. Les développeurs doivent plutôt utiliser des bibliothèques Android telles que Google Sign-In pour Android ou AppAuth pour Android de l'OpenID Foundation.

Les développeurs Web peuvent rencontrer cette erreur lorsqu'une application Android ouvre un lien Web général dans un user-agent intégré et qu'un utilisateur accède au point de terminaison d'autorisation OAuth 2.0 de Google depuis votre site. Les développeurs doivent autoriser les liens généraux à s'ouvrir dans le gestionnaire de liens par défaut du système d'exploitation, qui inclut à la fois les gestionnaires de Android App Links et l'application de navigateur par défaut. La bibliothèque Android Custom Tabs est également une option compatible.

iOS

Les développeurs iOS et macOS peuvent rencontrer cette erreur lorsqu'ils ouvrent des demandes d'autorisation dans WKWebView. Les développeurs doivent plutôt utiliser des bibliothèques iOS telles que Google Sign-In pour iOS ou AppAuth pour iOS de l'OpenID Foundation.

Les développeurs Web peuvent rencontrer cette erreur lorsqu'une application iOS ou macOS ouvre un lien Web général dans un user-agent intégré et qu'un utilisateur accède au point de terminaison d'autorisation OAuth 2.0 de Google depuis votre site. Les développeurs doivent autoriser les liens généraux à s'ouvrir dans le gestionnaire de liens par défaut du système d'exploitation, qui inclut à la fois les gestionnaires Universal Links et l'application de navigateur par défaut. La bibliothèque SFSafariViewController est également une option compatible.

org_internal

L'ID client OAuth de la requête fait partie d'un projet limitant l'accès aux comptes Google dans une organisation Google Cloud spécifique. Pour en savoir plus sur cette option de configuration, consultez la section Type d'utilisateur dans l'article d'aide "Configurer votre écran de consentement OAuth".

invalid_client

Le code secret du client OAuth est incorrect. Vérifiez la configuration du client OAuth, y compris l'ID client et le secret utilisés pour cette requête.

invalid_grant

Lorsque vous actualisez un jeton d'accès ou que vous utilisez l'autorisation incrémentielle, il est possible que le jeton ait expiré ou qu'il ait été invalidé. Réauthentifiez l'utilisateur et demandez-lui son consentement pour obtenir de nouveaux jetons. Si cette erreur persiste, assurez-vous que votre application a été correctement configurée et que vous utilisez les jetons et les paramètres appropriés dans votre requête. Sinon, le compte utilisateur a peut-être été supprimé ou désactivé.

redirect_uri_mismatch

L'redirect_uri transmis dans la requête d'autorisation ne correspond pas à un URI de redirection autorisé pour l'ID client OAuth. Examinez les URI de redirection autorisés dans le fichier Google API Console Credentials page.

Le paramètre redirect_uri peut faire référence au flux OAuth hors bande (OOB) qui a été abandonné et n'est plus pris en charge. Consultez le guide de migration pour mettre à jour votre intégration.

invalid_request

Votre demande ne correspond pas aux critères requis. Plusieurs raisons peuvent expliquer ce problème:

  • La requête n'était pas correctement formatée
  • Des paramètres obligatoires manquaient dans la requête.
  • La requête utilise une méthode d'autorisation non acceptée par Google. Vérifier que votre intégration OAuth utilise une méthode d'intégration recommandée

Étape 4: Gérer la réponse du serveur OAuth 2.0

Le serveur OAuth 2.0 répond à la requête d'accès de votre application à l'aide de l'URL spécifiée dans la requête.

Si l'utilisateur approuve la demande d'accès, la réponse contient un code d'autorisation. Si l'utilisateur n'approuve pas la requête, la réponse contient un message d'erreur. Le code d'autorisation ou le message d'erreur renvoyé au serveur Web s'affiche dans la chaîne de requête, comme illustré ci-dessous:

Réponse d'erreur:

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

Une réponse avec code d'autorisation:

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

Exemple de réponse du serveur OAuth 2.0

Vous pouvez tester ce flux en cliquant sur l'exemple d'URL suivant, qui demande un accès en lecture seule pour afficher les métadonnées des fichiers de votre compte Google Drive et un accès en lecture seule pour afficher vos événements Google Agenda:

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

Une fois le flux OAuth 2.0 terminé, vous devriez être redirigé vers http://localhost/oauth2callback, ce qui entraînera probablement une erreur 404 NOT FOUND, sauf si votre ordinateur local diffuse un fichier à cette adresse. L'étape suivante fournit plus d'informations sur les informations renvoyées dans l'URI lorsque l'utilisateur est redirigé vers votre application.

Étape 5: Échangez le code d'autorisation contre des jetons d'actualisation et d'accès

Une fois que le serveur Web a reçu le code d'autorisation, il peut l'échanger contre un jeton d'accès.

PHP

Pour échanger un code d'autorisation contre un jeton d'accès, utilisez la méthode fetchAccessTokenWithAuthCode:

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

Python

Sur votre page de rappel, utilisez la bibliothèque google-auth pour valider la réponse du serveur d'autorisation. Utilisez ensuite la méthode flow.fetch_token pour échanger le code d'autorisation de cette réponse contre un jeton d'accès:

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

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

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

Ruby

Sur votre page de rappel, utilisez la bibliothèque googleauth pour valider la réponse du serveur d'autorisation. Utilisez la méthode authorizer.handle_auth_callback_deferred pour enregistrer le code d'autorisation et rediriger l'utilisateur vers l'URL qui a initialement demandé l'autorisation. Cela diffère l'échange du code en stockant temporairement les résultats dans la session de l'utilisateur.

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

Node.js

Pour échanger un code d'autorisation contre un jeton d'accès, utilisez la méthode 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

Pour échanger un code d'autorisation contre un jeton d'accès, appelez le point de terminaison https://oauth2.googleapis.com/token et définissez les paramètres suivants:

Champs
client_id ID client obtenu auprès de la API Console Credentials page.
client_secret Code secret du client obtenu à partir de API Console Credentials page.
code Code d'autorisation renvoyé par la requête initiale.
grant_type Comme indiqué dans la spécification OAuth 2.0, la valeur de ce champ doit être définie sur authorization_code.
redirect_uri L'un des URI de redirection listés pour votre projet dans la table API Console Credentials page pour le client_id donné.

L'extrait de code suivant présente un exemple de requête:

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=your_client_id&
client_secret=your_client_secret&
redirect_uri=https%3A//oauth2.example.com/code&
grant_type=authorization_code

Google répond à cette requête en renvoyant un objet JSON contenant un jeton d'accès de courte durée et un jeton d'actualisation. Notez que le jeton d'actualisation n'est renvoyé que si votre application a défini le paramètre access_type sur offline dans la requête initiale envoyée au serveur d'autorisation de Google.

La réponse contient les champs suivants :

Champs
access_token Jeton envoyé par votre application pour autoriser une requête d'API Google.
expires_in Durée de vie restante du jeton d'accès, en secondes.
refresh_token Jeton que vous pouvez utiliser pour obtenir un nouveau jeton d'accès. Les jetons d'actualisation sont valides jusqu'à ce que l'utilisateur révoque l'accès. Encore une fois, ce champ n'est présent dans cette réponse que si vous définissez le paramètre access_type sur offline dans la requête initiale adressée au serveur d'autorisation de Google.
scope Champs d'application d'accès accordés par access_token, exprimés sous la forme d'une liste de chaînes sensibles à la casse séparées par des espaces.
token_type Type de jeton renvoyé. À ce stade, la valeur de ce champ est toujours définie sur Bearer.

L'extrait de code suivant montre un exemple de réponse:

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

Erreurs

Lorsque vous échangez le code d'autorisation contre un jeton d'accès, vous pouvez rencontrer l'erreur suivante au lieu de la réponse attendue. Vous trouverez ci-dessous les codes d'erreur courants et les solutions suggérées.

invalid_grant

Le code d'autorisation fourni n'est pas valide ou n'est pas au bon format. Demandez un nouveau code en redémarrant le processus OAuth pour inviter à nouveau l'utilisateur à donner son consentement.

Étape 6: Vérifiez les autorisations accordées par les utilisateurs

Lorsque vous demandez plusieurs niveaux d'accès à la fois, il est possible que les utilisateurs n'accordent pas tous les niveaux d'accès demandés par votre application. Votre application doit toujours vérifier les autorisations accordées par l'utilisateur et gérer tout refus d'autorisation en désactivant les fonctionnalités concernées. Pour en savoir plus, consultez Gérer les autorisations précises.

PHP

Pour vérifier les étendues accordées par l'utilisateur, utilisez la méthode 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'objet credentials renvoyé possède une propriété granted_scopes, qui est une liste des champs d'application que l'utilisateur a accordés à votre application.

credentials = flow.credentials
flask.session['credentials'] = {
    'token': credentials.token,
    'refresh_token': credentials.refresh_token,
    'token_uri': credentials.token_uri,
    'client_id': credentials.client_id,
    'client_secret': credentials.client_secret,
    'granted_scopes': credentials.granted_scopes}

La fonction suivante vérifie les autorisations que l'utilisateur a accordées à votre application.

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

Lorsque vous demandez plusieurs champs d'application à la fois, vérifiez les champs d'application accordés via la propriété scope de l'objet 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

Lorsque vous demandez plusieurs champs d'application à la fois, vérifiez les champs d'application accordés via la propriété scope de l'objet 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

Pour vérifier si l'utilisateur a accordé à votre application l'accès à un champ d'application particulier, examinez le champ scope dans la réponse du jeton d'accès. Champs d'application d'accès accordés par le jeton d'accès, exprimés sous la forme d'une liste de chaînes sensibles à la casse, délimitées par des espaces.

Par exemple, l'exemple de réponse du jeton d'accès suivant indique que l'utilisateur a accordé à votre application l'accès aux autorisations d'activité Drive en lecture seule et aux événements Agenda:

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

Appeler des API Google

PHP

Pour utiliser le jeton d'accès pour appeler les API Google, procédez comme suit:

  1. Si vous devez appliquer un jeton d'accès à un nouvel objet Google\Client (par exemple, si vous avez stocké le jeton d'accès dans une session utilisateur), utilisez la méthode setAccessToken:
    $client->setAccessToken($access_token);
  2. Créez un objet de service pour l'API que vous souhaitez appeler. Vous créez un objet de service en fournissant un objet Google\Client autorisé au constructeur de l'API que vous souhaitez appeler. Par exemple, pour appeler l'API Drive:
    $drive = new Google\Service\Drive($client);
  3. Envoyez des requêtes au service d'API à l'aide de l' interface fournie par l'objet de service. Par exemple, pour lister les fichiers dans Google Drive de l'utilisateur authentifié:
    $files = $drive->files->listFiles(array());

Python

Une fois qu'elle a obtenu un jeton d'accès, votre application peut l'utiliser pour autoriser les requêtes d'API au nom d'un compte utilisateur ou d'un compte de service donné. Utilisez les identifiants d'autorisation spécifiques à l'utilisateur pour créer un objet de service pour l'API que vous souhaitez appeler, puis utilisez cet objet pour effectuer des requêtes API autorisées.

  1. Créez un objet de service pour l'API que vous souhaitez appeler. Vous créez un objet de service en appelant la méthode build de la bibliothèque googleapiclient.discovery avec le nom et la version de l'API, ainsi que les identifiants utilisateur : Par exemple, pour appeler la version 3 de l'API Drive:
    from googleapiclient.discovery import build
    
    drive = build('drive', 'v2', credentials=credentials)
  2. Envoyez des requêtes au service d'API à l'aide de l'interface fournie par l'objet de service. Par exemple, pour lister les fichiers dans Google Drive de l'utilisateur authentifié:
    files = drive.files().list().execute()

Ruby

Une fois qu'elle a obtenu un jeton d'accès, votre application peut l'utiliser pour effectuer des requêtes d'API au nom d'un compte utilisateur ou d'un compte de service donné. Utilisez les identifiants d'autorisation spécifiques à l'utilisateur pour créer un objet de service pour l'API que vous souhaitez appeler, puis utilisez cet objet pour effectuer des requêtes API autorisées.

  1. Créez un objet de service pour l'API que vous souhaitez appeler. Par exemple, pour appeler la version 3 de l'API Drive:
    drive = Google::Apis::DriveV3::DriveService.new
  2. Définissez les identifiants sur le service:
    drive.authorization = credentials
  3. Envoyez des requêtes au service d'API à l'aide de l'interface fournie par l'objet de service. Par exemple, pour lister les fichiers dans Google Drive de l'utilisateur authentifié:
    files = drive.list_files

Vous pouvez également fournir une autorisation par méthode en fournissant le paramètre options à une méthode:

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

Node.js

Après avoir obtenu un jeton d'accès et l'avoir défini sur l'objet OAuth2, utilisez l'objet pour appeler les API Google. Votre application peut utiliser ce jeton pour autoriser les requêtes d'API au nom d'un compte utilisateur ou d'un compte de service donné. Créez un objet de service pour l'API que vous souhaitez appeler. Par exemple, le code suivant utilise l'API Google Drive pour lister les noms de fichiers dans Drive de l'utilisateur.

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

Une fois que votre application a obtenu un jeton d'accès, vous pouvez l'utiliser pour effectuer des appels à une API Google au nom d'un compte utilisateur donné si le ou les champs d'application de l'accès requis par l'API ont été accordés. Pour ce faire, incluez le jeton d'accès dans une requête envoyée à l'API en incluant un paramètre de requête access_token ou une valeur Bearer d'en-tête HTTP Authorization. Lorsque c'est possible, l'en-tête HTTP est préférable, car les chaînes de requête ont tendance à être visibles dans les journaux du serveur. Dans la plupart des cas, vous pouvez utiliser une bibliothèque cliente pour configurer vos appels aux API Google (par exemple, lorsque vous appelez l'API Drive Files).

Vous pouvez tester toutes les API Google et consulter leurs champs d'application sur OAuth 2.0 Playground.

Exemples de requêtes HTTP GET

Un appel au point de terminaison drive.files (API Drive Files) à l'aide de l'en-tête HTTP Authorization: Bearer peut se présenter comme suit. Notez que vous devez spécifier votre propre jeton d'accès:

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

Voici un appel à la même API pour l'utilisateur authentifié à l'aide du paramètre de chaîne de requête access_token:

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

curl exemples

Vous pouvez tester ces commandes avec l'application de ligne de commande curl. Voici un exemple qui utilise l'option d'en-tête HTTP (recommandée):

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

Vous pouvez également utiliser l'option de paramètre de chaîne de requête:

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

Exemple complet

L'exemple suivant affiche une liste de fichiers au format JSON dans Google Drive d'un utilisateur après que celui-ci s'est authentifié et a donné son autorisation pour que l'application accède aux métadonnées Drive de l'utilisateur.

PHP

Pour exécuter cet exemple:

  1. Dans API Console, ajoutez l'URL de l'ordinateur local à la liste des URL de redirection. Par exemple, ajoutez http://localhost:8080.
  2. Créez un répertoire et remplacez les éléments par ce qui suit : Exemple :
    mkdir ~/php-oauth2-example
    cd ~/php-oauth2-example
  3. Installez la bibliothèque cliente des API Google pour PHP à l'aide de Composer:
    composer require google/apiclient:^2.15.0
  4. Créez les fichiers index.php et oauth2callback.php avec le contenu suivant.
  5. Exécutez l'exemple avec le serveur Web de test intégré de 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

Cet exemple utilise le framework Flask. Il exécute une application Web sur http://localhost:8080 qui vous permet de tester le flux OAuth 2.0. Si vous accédez à cette URL, vous devriez voir cinq liens:

  • Appeler l'API Drive:ce lien pointe vers une page qui tente d'exécuter un exemple de requête API si les utilisateurs ont accordé l'autorisation. Si nécessaire, il lance le flux d'autorisation. Si l'opération réussit, la page affiche la réponse de l'API.
  • Page fictive pour appeler l'API Agenda:ce lien pointe vers une page fictive qui tente d'exécuter un exemple de requête d'API Agenda si les utilisateurs ont accordé l'autorisation. Si nécessaire, il lance le flux d'autorisation. Si l'opération réussit, la page affiche la réponse de l'API.
  • Tester directement le flux d'autorisation:ce lien pointe vers une page qui tente d'envoyer l'utilisateur via le flux d'autorisation. L'application demande l'autorisation d'envoyer des requêtes API autorisées au nom de l'utilisateur.
  • Révoquer les identifiants actuels:ce lien redirige vers une page qui revokes (révoque) les autorisations que l'utilisateur a déjà accordées à l'application.
  • Effacer les identifiants de session Flask:ce lien efface les identifiants d'autorisation stockés dans la session Flask. Cela vous permet de voir ce qui se passerait si un utilisateur qui avait déjà accordé une autorisation à votre application essayait d'exécuter une requête API dans une nouvelle session. Il vous permet également de voir la réponse de l'API que votre application recevrait si un utilisateur avait révoqué les autorisations accordées à votre application et que votre application tentait toujours d'autoriser une requête avec un jeton d'accès révoqué.
# -*- coding: utf-8 -*-

import os
import flask
import requests

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

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

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

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

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

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

  features = flask.session['features']

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

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

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

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

    return flask.jsonify(**files)
  else:
    # User didn't authorize read-only Drive activity permission.
    # Update UX and application accordingly
    return '<p>Drive feature is not enabled.</p>'

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

      features = flask.session['features']

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

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

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

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

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

  return flask.redirect(authorization_url)

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

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

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

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

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

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

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

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

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

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

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

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

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

  return features

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

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

  # This disables the requested scopes and granted scopes check.
  # If users only grant partial request, the warning would not be thrown.
  os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '1'

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

Ruby

Cet exemple utilise le 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

Pour exécuter cet exemple:

  1. Dans API Console, ajoutez l'URL de l'ordinateur local à la liste des URL de redirection. Par exemple, ajoutez http://localhost.
  2. Assurez-vous d'avoir installé la version LTS de maintenance, la version LTS active ou la version actuelle de Node.js.
  3. Créez un répertoire et remplacez les éléments par ce qui suit : Exemple :
    mkdir ~/nodejs-oauth2-example
    cd ~/nodejs-oauth2-example
  4. Installez la bibliothèque cliente des API Google pour Node.js à l'aide de npm:
    npm install googleapis
  5. Créez les fichiers main.js avec le contenu suivant :
  6. Exécutez l'exemple:
    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

Cet exemple Python utilise le framework Flask et la bibliothèque Requests pour illustrer le flux Web OAuth 2.0. Nous vous recommandons d'utiliser la bibliothèque cliente des API Google pour Python pour ce flux. (L'exemple de l'onglet Python utilise la bibliothèque cliente.)

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

Règles de validation des URI de redirection

Google applique les règles de validation suivantes aux URI de redirection afin d'aider les développeurs à sécuriser leurs applications. Vos URI de redirection doivent respecter ces règles. Consultez la section 3 de la RFC 3986 pour connaître la définition des termes domaine, hôte, chemin d'accès, requête, schéma et userinfo, mentionnés ci-dessous.

Règles de validation
Schéma

Les URI de redirection doivent utiliser le schéma HTTPS, et non HTTP. Les URI localhost (y compris les URI d'adresse IP localhost) sont exemptés de cette règle.

Hôte

Les hôtes ne peuvent pas être des adresses IP brutes. Les adresses IP de l'hôte local sont exclues de cette règle.

Domaine
  • Les domaines de premier niveau (top-level domain) hôtes doivent appartenir à la liste des suffixes publics.
  • Les domaines d'hôte ne peuvent pas être “googleusercontent.com”.
  • Les URI de redirection ne peuvent pas contenir de domaines de raccourcissement d'URL (par exemple, goo.gl) sauf si l'application en est propriétaire. De plus, si une application propriétaire d'un domaine abrégé choisit de rediriger vers ce domaine, l'URI de redirection doit contenir “/google-callback/” dans son chemin d'accès ou se terminer par “/google-callback”.
  • Userinfo

    Les URI de redirection ne doivent pas contenir le sous-composant userinfo.

    Chemin d'accès

    Les URI de redirection ne doivent pas contenir de traversée de répertoire (également appelée "retracement de répertoire"), représentée par un “/..” ou “\..”, ou leur encodage d'URL.

    Query

    Les URI de redirection ne peuvent pas contenir de redirections ouvertes.

    Fragment

    Les URI de redirection ne peuvent pas contenir le composant de fragment.

    Caractères Les URI de redirection ne peuvent pas contenir certains caractères, y compris les suivants :
    • Caractères génériques ('*')
    • Caractères ASCII non imprimables
    • Encodages en pourcentage non valides (tout encodage en pourcentage qui ne suit pas le format d'encodage en URL, à savoir un signe de pourcentage suivi de deux chiffres hexadécimaux)
    • Caractères nuls (un caractère NULL encodé, par exemple, %00, %C0%80)

    Autorisation incrémentielle

    Dans le protocole OAuth 2.0, votre application demande une autorisation pour accéder aux ressources, qui sont identifiées par des champs d'application. Il est considéré comme une bonne pratique d'expérience utilisateur de demander l'autorisation pour les ressources au moment où vous en avez besoin. Pour permettre cette pratique, le serveur d'autorisation de Google est compatible avec l'autorisation incrémentielle. Cette fonctionnalité vous permet de demander des portées au fur et à mesure que vous en avez besoin. Si l'utilisateur accorde l'autorisation pour la nouvelle portée, elle renvoie un code d'autorisation pouvant être échangé contre un jeton contenant toutes les portées que l'utilisateur a accordées au projet.

    Par exemple, une application qui permet aux utilisateurs d'échantillonner des titres musicaux et de créer des mixages peut nécessiter très peu de ressources au moment de la connexion, peut-être rien de plus que le nom de la personne qui se connecte. Toutefois, l'enregistrement d'un mix terminé nécessiterait un accès à son compte Google Drive. La plupart des utilisateurs trouveraient naturel que l'accès à leur compte Google Drive ne leur soit demandé que lorsque l'application en a réellement besoin.

    Dans ce cas, au moment de la connexion, l'application peut demander les habilitations openid et profile pour effectuer une connexion de base, puis demander ultérieurement l'habilitation https://www.googleapis.com/auth/drive.file au moment de la première requête pour enregistrer un mix.

    Pour implémenter l'autorisation incrémentielle, suivez le flux normal pour demander un jeton d'accès, mais assurez-vous que la requête d'autorisation inclut les portées précédemment accordées. Cette approche permet à votre application d'éviter de gérer plusieurs jetons d'accès.

    Les règles suivantes s'appliquent à un jeton d'accès obtenu à partir d'une autorisation incrémentielle:

    • Le jeton peut être utilisé pour accéder aux ressources correspondant à l'un des champs d'application intégrés à la nouvelle autorisation combinée.
    • Lorsque vous utilisez le jeton d'actualisation pour l'autorisation combinée afin d'obtenir un jeton d'accès, le jeton d'accès représente l'autorisation combinée et peut être utilisé pour toutes les valeurs scope incluses dans la réponse.
    • L'autorisation combinée inclut tous les champs d'application que l'utilisateur a accordés au projet d'API, même si les autorisations ont été demandées par différents clients. Par exemple, si un utilisateur a accordé l'accès à un champ d'application à l'aide du client pour ordinateur de bureau de l'application, puis accordé un autre champ à la même application via un client mobile, l'autorisation combinée inclura les deux champs.
    • Si vous révoquez un jeton représentant une autorisation combinée, l'accès à tous les champs d'application de cette autorisation au nom de l'utilisateur associé est révoqué simultanément.

    Les exemples de code propres aux langages de l'étape 1: Définir les paramètres d'autorisation et l'exemple d'URL de redirection HTTP/REST de l'étape 2 : Rediriger vers le serveur OAuth 2.0 de Google utilisent tous l'autorisation incrémentielle. Les exemples de code ci-dessous montrent également le code que vous devez ajouter pour utiliser l'autorisation incrémentielle.

    PHP

    $client->setIncludeGrantedScopes(true);

    Python

    En langage Python, définissez l'argument du mot clé include_granted_scopes sur true pour vous assurer qu'une requête d'autorisation inclut les champs d'application précédemment accordés. Il est très possible que include_granted_scopes ne soit pas le seul argument de mot clé que vous définissez, comme illustré dans l'exemple ci-dessous.

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

    Ruby

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

    Node.js

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

    HTTP/REST

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

    Actualiser un jeton d'accès (accès hors connexion)

    Les jetons d'accès expirent régulièrement et deviennent des identifiants non valides pour une requête API associée. Vous pouvez actualiser un jeton d'accès sans demander l'autorisation à l'utilisateur (y compris lorsqu'il n'est pas présent) si vous avez demandé un accès hors connexion aux champs d'application associés au jeton.

    • Si vous utilisez une bibliothèque cliente d'API Google, l'objet client actualise le jeton d'accès si nécessaire, à condition que vous configuriez cet objet pour l'accès hors connexion.
    • Si vous n'utilisez pas de bibliothèque cliente, vous devez définir le paramètre de requête HTTP access_type sur offline lorsque vous redirigez l'utilisateur vers le serveur OAuth 2.0 de Google. Dans ce cas, le serveur d'autorisation de Google renvoie un jeton d'actualisation lorsque vous échangez un code d'autorisation contre un jeton d'accès. Ensuite, si le jeton d'accès expire (ou à tout autre moment), vous pouvez utiliser un jeton d'actualisation pour obtenir un nouveau jeton d'accès.

    Une requête d'accès hors connexion est requise pour toute application devant accéder à une API Google en l'absence d'utilisateur. Par exemple, une application qui effectue des services de sauvegarde ou exécute des actions à des heures prédéterminées doit pouvoir actualiser son jeton d'accès lorsque l'utilisateur n'est pas présent. Le style d'accès par défaut est appelé online.

    Les applications Web côté serveur, les applications installées et les appareils obtiennent tous des jetons d'actualisation lors du processus d'autorisation. Les jetons d'actualisation ne sont généralement pas utilisés dans les applications Web côté client (JavaScript).

    PHP

    Si votre application a besoin d'un accès hors connexion à une API Google, définissez le type d'accès du client API sur offline:

    $client->setAccessType("offline");

    Une fois qu'un utilisateur a accordé un accès hors connexion aux champs d'application demandés, vous pouvez continuer à utiliser le client de l'API pour accéder aux API Google au nom de l'utilisateur lorsqu'il est hors connexion. L'objet client actualisera le jeton d'accès si nécessaire.

    Python

    En Python, définissez l'argument de mot clé access_type sur offline pour vous assurer de pouvoir actualiser le jeton d'accès sans avoir à demander à nouveau l'autorisation à l'utilisateur. Il est très possible que access_type ne soit pas le seul argument de mot clé que vous définissez, comme illustré dans l'exemple ci-dessous.

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

    Une fois qu'un utilisateur a accordé un accès hors connexion aux champs d'application demandés, vous pouvez continuer à utiliser le client de l'API pour accéder aux API Google au nom de l'utilisateur lorsqu'il est hors connexion. L'objet client actualisera le jeton d'accès si nécessaire.

    Ruby

    Si votre application a besoin d'un accès hors connexion à une API Google, définissez le type d'accès du client API sur offline:

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

    Une fois qu'un utilisateur a accordé un accès hors connexion aux champs d'application demandés, vous pouvez continuer à utiliser le client de l'API pour accéder aux API Google au nom de l'utilisateur lorsqu'il est hors connexion. L'objet client actualisera le jeton d'accès si nécessaire.

    Node.js

    Si votre application a besoin d'un accès hors connexion à une API Google, définissez le type d'accès du client API sur 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
    });

    Une fois qu'un utilisateur a accordé un accès hors connexion aux champs d'application demandés, vous pouvez continuer à utiliser le client de l'API pour accéder aux API Google au nom de l'utilisateur lorsqu'il est hors connexion. L'objet client actualisera le jeton d'accès si nécessaire.

    Les jetons d'accès expirent. Cette bibliothèque utilise automatiquement un jeton d'actualisation pour obtenir un nouveau jeton d'accès s'il est sur le point d'expirer. Pour vous assurer de toujours stocker les jetons les plus récents, utilisez l'événement "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);
    });

    Cet événement de jeton ne se produit que lors de la première autorisation. Vous devez avoir défini votre access_type sur offline lorsque vous appelez la méthode generateAuthUrl pour recevoir le jeton d'actualisation. Si vous avez déjà accordé à votre application les autorisations requises sans définir les contraintes appropriées pour recevoir un jeton d'actualisation, vous devrez réautoriser l'application à recevoir un nouveau jeton d'actualisation.

    Pour définir la refresh_token ultérieurement, vous pouvez utiliser la méthode setCredentials:

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

    Une fois que le client dispose d'un jeton d'actualisation, les jetons d'accès sont acquis et actualisés automatiquement lors du prochain appel de l'API.

    HTTP/REST

    Pour actualiser un jeton d'accès, votre application envoie une requête POST HTTPS au serveur d'autorisation (https://oauth2.googleapis.com/token) de Google, qui inclut les paramètres suivants:

    Champs
    client_id ID client obtenu auprès de API Console.
    client_secret Code secret du client obtenu auprès de API Console.
    grant_type Comme défini dans la spécification OAuth 2.0, la valeur de ce champ doit être définie sur refresh_token.
    refresh_token Jeton d'actualisation renvoyé à la suite de l'échange du code d'autorisation.

    L'extrait de code suivant présente un exemple de requête:

    POST /token HTTP/1.1
    Host: oauth2.googleapis.com
    Content-Type: application/x-www-form-urlencoded
    
    client_id=your_client_id&
    client_secret=your_client_secret&
    refresh_token=refresh_token&
    grant_type=refresh_token

    Tant que l'utilisateur n'a pas révoqué l'accès accordé à l'application, le serveur de jetons renvoie un objet JSON contenant un nouveau jeton d'accès. L'extrait de code suivant montre un exemple de réponse:

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

    Notez que le nombre de jetons d'actualisation émis est limité : une limite par combinaison client/utilisateur et une autre par utilisateur pour tous les clients. Vous devez enregistrer les jetons d'actualisation dans un espace de stockage à long terme et continuer à les utiliser tant qu'ils restent valides. Si votre application demande trop de jetons d'actualisation, elle peut rencontrer ces limites, auquel cas les jetons d'actualisation plus anciens cesseront de fonctionner.

    Révoquer un jeton

    Dans certains cas, un utilisateur peut souhaiter révoquer l'accès accordé à une application. Un utilisateur peut révoquer l'accès en accédant aux paramètres du compte. Pour en savoir plus, consultez la section Supprimer l'accès d'une application ou d'un site du document d'aide "Applications et sites tiers ayant accès à votre compte".

    Une application peut également révoquer de manière programmatique l'accès qui lui a été accordé. La révocation programmatique est importante dans les cas où un utilisateur se désinscrit, supprime une application ou que les ressources d'API requises par une application ont changé de manière significative. En d'autres termes, une partie du processus de suppression peut inclure une requête d'API pour s'assurer que les autorisations précédemment accordées à l'application sont supprimées.

    PHP

    Pour révoquer un jeton de manière automatisée, appelez revokeToken():

    $client->revokeToken();

    Python

    Pour révoquer un jeton de manière programmatique, envoyez une requête à https://oauth2.googleapis.com/revoke qui inclut le jeton en tant que paramètre et définit l'en-tête Content-Type:

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

    Ruby

    Pour révoquer un jeton de manière programmatique, envoyez une requête HTTP au point de terminaison oauth2.revoke:

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

    Il peut s'agir d'un jeton d'accès ou d'un jeton d'actualisation. Si le jeton est un jeton d'accès et qu'il dispose d'un jeton d'actualisation correspondant, le jeton d'actualisation est également révoqué.

    Si la révocation est traitée correctement, le code d'état de la réponse est 200. Pour les conditions d'erreur, un code d'état 400 est renvoyé avec un code d'erreur.

    Node.js

    Pour révoquer un jeton de manière programmatique, envoyez une requête POST HTTPS au point de terminaison /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();

    Le paramètre de jeton peut être un jeton d'accès ou un jeton d'actualisation. Si le jeton est un jeton d'accès et qu'il dispose d'un jeton d'actualisation correspondant, le jeton d'actualisation est également révoqué.

    Si la révocation est traitée correctement, le code d'état de la réponse est 200. Pour les conditions d'erreur, un code d'état 400 est renvoyé avec un code d'erreur.

    HTTP/REST

    Pour révoquer un jeton de manière programmatique, votre application envoie une requête à https://oauth2.googleapis.com/revoke et inclut le jeton en tant que paramètre:

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

    Il peut s'agir d'un jeton d'accès ou d'un jeton d'actualisation. Si le jeton est un jeton d'accès et qu'il dispose d'un jeton d'actualisation correspondant, le jeton d'actualisation est également révoqué.

    Si la révocation est traitée avec succès, le code d'état HTTP de la réponse est 200. Pour les conditions d'erreur, un code d'état HTTP 400 est renvoyé avec un code d'erreur.

    Implémenter la protection multicompte

    Pour protéger les comptes de vos utilisateurs, vous devez également implémenter la protection multicompte à l'aide du service de protection multicompte de Google. Ce service vous permet de vous abonner à des notifications d'événements de sécurité qui fournissent des informations à votre application sur les modifications majeures apportées au compte utilisateur. Vous pouvez ensuite utiliser ces informations pour prendre des mesures en fonction de la façon dont vous décidez de répondre aux événements.

    Voici quelques exemples de types d'événements envoyés à votre application par le service de protection multicompte de 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

    Pour en savoir plus sur l'implémentation de la Protection multicompte et obtenir la liste complète des événements disponibles, consultez la page Protéger les comptes utilisateur avec la Protection multicompte .