Utiliser le modèle de jeton

La bibliothèque JavaScript google.accounts.oauth2 vous permet de demander le consentement de l'utilisateur et d'obtenir un jeton d'accès pour utiliser les données utilisateur. Il est basé sur le flux d'attribution implicite OAuth 2.0 et conçu pour vous permettre d'appeler des API Google directement à l'aide de REST et CORS, ou d'utiliser notre bibliothèque cliente des API Google pour JavaScript (également appelée gapi.client) pour un accès simple et flexible à nos API plus complexes.

Avant d'accéder aux données utilisateur protégées à partir d'un navigateur, les utilisateurs de votre site déclenchent des processus de sélection de compte, de connexion et de consentement basés sur le Web par Google, et enfin les serveurs OAuth de Google émettent et renvoient un jeton d'accès à votre application Web.

Dans le modèle d'autorisation basé sur les jetons, il n'est pas nécessaire de stocker des jetons d'actualisation par utilisateur sur votre serveur backend.

Nous vous recommandons d'adopter l'approche décrite ici plutôt que les techniques abordées dans l'ancien guide OAuth 2.0 pour les applications Web côté client.

Configuration

Pour obtenir ou créer un ID client, suivez la procédure décrite dans le guide Obtenir votre ID client pour les API Google. Ensuite, ajoutez la bibliothèque cliente aux pages de votre site qui appelleront les API Google. Enfin, initialisez le client de jeton. En règle générale, cette opération s'effectue dans le gestionnaire onload de la bibliothèque cliente.

Initialiser un client de jeton

Appelez initTokenClient() pour initialiser un nouveau client de jeton avec l'ID client de votre application Web. Vous pouvez éventuellement inclure une liste d'un ou plusieurs champs d'application auxquels l'utilisateur doit accéder:

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly',
  callback: (response) => {
    ...
  },
});

Déclencher le flux de jetons OAuth 2.0

Utilisez la méthode requestAccessToken() pour déclencher le flux d'expérience utilisateur et obtenir un jeton d'accès. Google invite l'utilisateur à:

  • choisir son compte ;
  • vous connecter au compte Google (si ce n'est pas déjà fait) ;
  • autorisez votre application Web à accéder à chaque niveau d'accès demandé.

Un geste utilisateur déclenche le flux de jetons : <button onclick="client.requestAccessToken();">Authorize me</button>

Google renvoie ensuite un TokenResponse contenant un jeton d'accès et une liste de champs d'application auxquels l'utilisateur a accordé l'accès à votre gestionnaire de rappel, ou une erreur.

Les utilisateurs peuvent fermer le sélecteur de compte ou les fenêtres de connexion, auquel cas votre fonction de rappel n'est pas appelée.

La conception et l'expérience utilisateur de votre application ne doivent être mises en œuvre qu'après un examen approfondi des règles OAuth 2.0 de Google. Ces règles couvrent l'utilisation de plusieurs niveaux d'accès, la gestion du consentement des utilisateurs et à quel moment.

L'autorisation incrémentielle est une méthodologie de conception de règles et d'applications qui permet de demander l'accès aux ressources à l'aide de champs d'application, uniquement lorsque cela est nécessaire plutôt que de manière initiale, et ce en une seule fois. Les utilisateurs peuvent approuver ou refuser le partage des ressources individuelles demandées par votre application. Il s'agit d'autorisations précises.

Au cours de ce processus, Google demande le consentement de l'utilisateur et répertorie individuellement chaque champ d'application demandé. Il sélectionne ensuite les ressources à partager avec votre application et, en dernier lieu, Google appelle votre fonction de rappel pour renvoyer un jeton d'accès et des champs d'application approuvés par l'utilisateur. Votre application gère ensuite en toute sécurité les différents résultats possibles avec des autorisations précises.

Autorisation incrémentielle

Pour les applications Web, les deux scénarios généraux suivants illustrent une autorisation incrémentielle:

  • Application Ajax monopage, utilisant souvent XMLHttpRequest avec accès dynamique aux ressources
  • Plusieurs pages Web et ressources sont séparées et gérées par page.

Ces deux scénarios sont présentés pour illustrer des considérations de conception et des méthodologies, mais ne constituent pas des recommandations exhaustives sur la façon d'intégrer le consentement dans votre application. Les applications réelles peuvent utiliser une variante ou une combinaison de ces techniques.

Ajax

Ajoutez la prise en charge de l'autorisation incrémentielle à votre application en effectuant plusieurs appels à requestAccessToken() et en utilisant le paramètre scope de l'objet OverridableTokenClientConfig pour demander des champs d'application individuels au moment où ils en ont besoin et uniquement si nécessaire. Dans cet exemple, les ressources ne sont demandées et visibles qu'une fois que l'utilisateur a développé une section de contenu réduite.

Application Ajax
Initialisez le client de jeton au chargement de la page :
        const client = google.accounts.oauth2.initTokenClient({
          client_id: 'YOUR_GOOGLE_CLIENT_ID',
          callback: "onTokenResponse",
        });
      
Demandez le consentement et obtenez des jetons d'accès via des gestes utilisateur. Cliquez sur"+"pour ouvrir:

Docs à lire

Afficher les documents récents

          client.requestAccessToken(
            overrideConfig = ({
               scope = 'https://www.googleapis.com/auth/documents.readonly'
             })
           );
        

Événements à venir

Afficher les informations de l'agenda

          client.requestAccessToken(
            overrideConfig = ({
               scope = 'https://www.googleapis.com/auth/calendar.readonly'
             })
           );
        

Afficher les photos

          client.requestAccessToken(
            overrideConfig = ({
               scope = 'https://www.googleapis.com/auth/photoslibrary.readonly'
             })
           );
        

Chaque appel à requestAccessToken déclenche un moment de consentement de l'utilisateur, votre application n'a accès qu'aux ressources requises par la section qu'il choisit de développer, ce qui limite le partage des ressources par le choix de l'utilisateur.

Plusieurs pages Web

Lors de la conception d'une autorisation incrémentielle, plusieurs pages permettent de demander uniquement les champs d'application requis pour charger une page. Cela permet de réduire la complexité et de devoir effectuer plusieurs appels afin d'obtenir le consentement de l'utilisateur et récupérer un jeton d'accès.

Application multipage
Page Web Coder
Page 1. Docs à lire
  const client = google.accounts.oauth2.initTokenClient({
    client_id: 'YOUR_GOOGLE_CLIENT_ID',
    callback: "onTokenResponse",
    scope: 'https://www.googleapis.com/auth/documents.readonly',
  });
  client.requestAccessToken();
          
Page 2. Événements à venir
  const client = google.accounts.oauth2.initTokenClient({
    client_id: 'YOUR_GOOGLE_CLIENT_ID',
    callback: "onTokenResponse",
    scope: 'https://www.googleapis.com/auth/calendar.readonly',
  });
  client.requestAccessToken();
          
Page 3. Carrousel de photos
  const client = google.accounts.oauth2.initTokenClient({
    client_id: 'YOUR_GOOGLE_CLIENT_ID',
    callback: "onTokenResponse",
    scope: 'https://www.googleapis.com/auth/photoslibrary.readonly',
  });
  client.requestAccessToken();
          

Chaque page demande le champ d'application nécessaire et obtient un jeton d'accès en appelant initTokenClient() et requestAccessToken() au moment du chargement. Dans ce scénario, des pages Web individuelles permettent de distinguer clairement les fonctionnalités utilisateur et les ressources par champ d'application. En situation réelle, des pages individuelles peuvent demander plusieurs champs d'application associés.

Autorisations précises

Les autorisations précises sont gérées de la même manière dans tous les scénarios. Une fois que requestAccessToken() a appelé votre fonction de rappel et qu'un jeton d'accès a été renvoyé, vérifiez que l'utilisateur a approuvé les champs d'application demandés à l'aide de hasGrantedAllScopes() ou hasGrantedAnyScope(). Exemple :

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly \
          https://www.googleapis.com/auth/documents.readonly \
          https://www.googleapis.com/auth/photoslibrary.readonly',
  callback: (tokenResponse) => {
    if (tokenResponse && tokenResponse.access_token) {
      if (google.accounts.oauth2.hasGrantedAnyScope(tokenResponse,
          'https://www.googleapis.com/auth/photoslibrary.readonly')) {
        // Look at pictures
        ...
      }
      if (google.accounts.oauth2.hasGrantedAllScopes(tokenResponse,
          'https://www.googleapis.com/auth/calendar.readonly',
          'https://www.googleapis.com/auth/documents.readonly')) {
        // Meeting planning and review documents
        ...
      }
    }
  },
});

Toutes les subventions précédemment acceptées lors de sessions ou de demandes précédentes seront également incluses dans la réponse. Un enregistrement de consentement de l'utilisateur est conservé par utilisateur et par ID client, et persiste lors de plusieurs appels à initTokenClient() ou requestAccessToken(). Par défaut, le consentement de l'utilisateur n'est nécessaire que la première fois qu'il visite votre site Web et demande un nouveau champ d'application, mais il peut être demandé à chaque chargement de page à l'aide de prompt=consent dans les objets de configuration Token Client.

Utiliser des jetons

Dans le modèle de jeton, un jeton d'accès n'est pas stocké par l'OS ou le navigateur. Un nouveau jeton est d'abord obtenu au moment du chargement de la page, ou par un appel à requestAccessToken() via un geste utilisateur tel qu'une pression sur un bouton.

Utiliser REST et CORS avec les API Google

Un jeton d'accès peut être utilisé pour envoyer des requêtes authentifiées aux API Google à l'aide de REST et CORS. Cela permet aux utilisateurs de se connecter, d'accorder leur consentement, à Google d'émettre un jeton d'accès et à votre site de travailler avec les données de l'utilisateur.

Dans cet exemple, affichez les événements d'agenda à venir des utilisateurs connectés à l'aide du jeton d'accès renvoyé par tokenRequest():

var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://www.googleapis.com/calendar/v3/calendars/primary/events');
xhr.setRequestHeader('Authorization', 'Bearer ' + tokenResponse.access_token);
xhr.send();

Pour en savoir plus, consultez la page Comment utiliser CORS pour accéder aux API Google.

La section suivante explique comment intégrer facilement des API plus complexes.

Utiliser la bibliothèque JavaScript des API Google

Le client de jeton fonctionne avec la bibliothèque cliente des API Google pour JavaScript. Consultez l'extrait de code ci-dessous.

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly',
  callback: (tokenResponse) => {
    if (tokenResponse && tokenResponse.access_token) {
      gapi.client.setApiKey('YOUR_API_KEY');
      gapi.client.load('calendar', 'v3', listUpcomingEvents);
    }
  },
});

function listUpcomingEvents() {
  gapi.client.calendar.events.list(...);
}

Expiration du jeton

De par leur conception, les jetons d'accès ont une durée de vie limitée. Si le jeton d'accès expire avant la fin de la session de l'utilisateur, obtenez un nouveau jeton en appelant requestAccessToken() à partir d'un événement piloté par l'utilisateur tel qu'un bouton.

Appelez la méthode google.accounts.oauth2.revoke pour supprimer le consentement de l'utilisateur et l'accès aux ressources pour tous les champs d'application accordés à votre application. Un jeton d'accès valide est nécessaire pour révoquer cette autorisation:

google.accounts.oauth2.revoke('414a76cb127a7ece7ee4bf287602ca2b56f8fcbf7fcecc2cd4e0509268120bd7', done => {
    console.log(done);
    console.log(done.successful);
    console.log(done.error);
    console.log(done.error_description);
  });