Migra a Google Identity Services

Descripción general

Para obtener un token de acceso por usuario para llamar a las APIs de Google, Google ofrece varias Bibliotecas de JavaScript:

En esta guía, se proporcionan instrucciones para migrar de estas bibliotecas a la página Biblioteca de Identity Services

Si sigues esta guía, podrás hacer lo siguiente:

  • reemplazar la biblioteca obsoleta de la plataforma por la biblioteca de servicios de identidad, y
  • Si usas la biblioteca cliente de la API, quita el módulo obsoleto gapi.auth2. sus métodos y objetos, y los reemplaza por equivalentes de Identity Services.

Para obtener una descripción de lo que cambió en JavaScript de servicios de identidad consulta la descripción general y cómo funciona la autorización de usuarios para revisar en términos y conceptos clave.

Si buscas autenticación para el registro y acceso de usuarios, consulta Migra desde el Acceso con Google en su lugar.

Identifica tu flujo de autorización

Hay dos flujos posibles de autorización de usuarios: el implícito y la autorización. código.

Revisa tu app web para identificar el tipo de flujo de autorización que se encuentra actualmente. en uso.

Indicaciones que tu aplicación web usa el flujo implícito:

Indicaciones que tu aplicación web usa el flujo de código de autorización:

  • Tu implementación se basa en lo siguiente:

  • Tu app se ejecuta en el navegador del usuario y en tu plataforma de backend.

  • Tu plataforma de backend aloja un extremo de código de autorización.

  • Tu plataforma de backend llama a las APIs de Google en nombre de los usuarios sin requerir que estén presentes, lo que también se conoce como modo sin conexión.

  • Tu plataforma de backend administra y almacena los tokens de actualización.

En algunos casos, tu base de código podría admitir ambos flujos.

Elige un flujo de autorización

Antes de comenzar la migración, debes determinar si continúas con tu del flujo existente o adoptar uno diferente que mejor se adapte a tus necesidades.

Consulta cómo elegir un flujo de autorización para comprender las diferencias clave. y las compensaciones entre ambos flujos.

En la mayoría de los casos, se recomienda el flujo de código de autorización, ya que ofrece la el máximo nivel de seguridad del usuario. Implementar este flujo también te permite para agregar fácilmente nuevas funcionalidades sin conexión, como la recuperación de actualizaciones para notificar a los usuarios sobre cambios notables en sus calendarios, fotos, suscripciones y así sucesivamente.

Elige un flujo de autorización con los siguientes selectores.

Flujo implícito

Obtener un token de acceso para usarlo en el navegador mientras el usuario esté presente

Los ejemplos de flujo implícito muestran las aplicaciones web antes y después de la migración a de Google Identity.

Flujo de código de autorización

Se entrega a tu backend un código de autorización por usuario emitido por Google. en la que se intercambia por un token de acceso y un token de actualización.

Los ejemplos de flujo de código de autorización muestran las aplicaciones web antes y después. la migración a Identity Services.

A lo largo de esta guía, sigue las instrucciones en negrita para Agregar, Puedes quitar, actualizar o reemplazar funcionalidades existentes.

Cambios en la aplicación web en el navegador

Esta sección revisa los cambios que realizarás en tu app web en el navegador cuando Migrar a la biblioteca JavaScript de Google Identity Services.

Identifica el código afectado y las pruebas

Una cookie de depuración puede ayudar a localizar el código afectado y a realizar pruebas posteriores a la baja el comportamiento de los usuarios.

En apps grandes o complejas, puede ser difícil encontrar todo el código afectado por el dejará de estar disponible el módulo gapi.auth2. Para registrar el uso existente obsoleta en la consola, establece el valor del G_AUTH2_MIGRATION cookie a informational. También puedes agregar dos puntos seguidos por un valor de clave para registrar también en el almacenamiento de la sesión. Después de acceder recepción de la revisión de credenciales o enviar los registros recopilados a un backend para más tarde de análisis de datos en la nube. Por ejemplo, informational:showauth2use guarda el origen y la URL en una de la sesión con nombre showauth2use.

Para verificar el comportamiento de la app cuando ya no esté cargado el módulo gapi.auth2, configura la el valor de la cookie G_AUTH2_MIGRATION en enforced. Esto permite probar comportamiento posterior a la baja antes de la fecha de aplicación.

Posibles valores de cookie G_AUTH2_MIGRATION:

  • enforced No cargar el módulo gapi.auth2.
  • informational Registra el uso de la funcionalidad obsoleta en la consola de JS. Registrar también al almacenamiento de sesión cuando se establece un nombre de clave opcional: informational:key-name

Para minimizar el impacto en los usuarios, se recomienda primero configurar esta cookie de manera local durante el desarrollo y las pruebas, antes de usarlo en entornos de producción.

Bibliotecas y módulos

El módulo gapi.auth2 administra la autenticación del usuario para el acceso y la para autorización, reemplaza este módulo obsoleto y sus objetos y con la biblioteca de Google Identity Services.

Agrega la biblioteca de Identity Services a tu app web. Para ello, inclúyela en tu documento:

<script src="https://accounts.google.com/gsi/client" async defer></script>

Quita cualquier instancia de carga del módulo auth2 con gapi.load('auth2', function).

La biblioteca de Google Identity Services reemplaza el uso del módulo gapi.auth2. Puedes seguir usando de forma segura el módulo gapi.client de la API de Google Biblioteca cliente para JavaScript y aprovecha su creación automática de métodos de JS que admiten llamadas desde un documento de descubrimiento, agrupar en lotes varias llamadas a la API y funciones de administración de CORS.

Cookies

La autorización del usuario no requiere el uso de cookies.

Consulta Cómo migrar desde el Acceso con Google para obtener detalles sobre cómo se realiza la autenticación de usuarios utiliza cookies, y Cómo utiliza Google las cookies para el uso de cookies por parte de otros en los productos y servicios de Google.

Credenciales

Google Identity Services separa la autenticación y la autorización del usuario en dos operaciones distintas, y las credenciales de usuario son independientes: el token de ID que se usa para identificar a un usuario se devuelve independientemente del token de acceso utilizado para autorización.

Para ver estos cambios, consulta las credenciales de ejemplo.

Flujo implícito

Separar la autenticación y la autorización de usuarios mediante la eliminación del perfil de usuario de los flujos de autorización.

Quita estas referencias de cliente de JavaScript para el Acceso con Google:

Métodos

  • GoogleUser.getBasicProfile()
  • GoogleUser.getId()

Flujo de código de autorización

Identity Services separa las credenciales en el navegador en token de ID y acceso token. Este cambio no se aplica a las credenciales obtenidas a través de a extremos de Google OAuth 2.0 desde tu plataforma de backend o a través las bibliotecas que se ejecutan en un servidor seguro en tu plataforma, como Google Cliente de Node.js de las APIs

Estado de sesión

Anteriormente, Acceso con Google te ayudaba a administrar el estado de acceso de los usuarios mediante:

Eres responsable de administrar el estado de acceso y las sesiones de usuario en tu sitio web .

Quita estas referencias de cliente de JavaScript para el Acceso con Google:

Objetos:

  • gapi.auth2.SignInOptions

Métodos:

  • GoogleAuth.attachClickHandler()
  • GoogleAuth.isSignedIn()
  • GoogleAuth.isSignedIn.get()
  • GoogleAuth.isSignedIn.listen()
  • GoogleAuth.signIn()
  • GoogleAuth.signOut()
  • GoogleAuth.currentUser.get()
  • GoogleAuth.currentUser.listen()
  • GoogleUser.isSignedIn()

Configuración del cliente

Actualiza tu app web para inicializar un cliente de token para la operación implícita o de código de autorización.

Quita estas referencias de cliente de JavaScript para el Acceso con Google:

Objetos:

  • gapi.auth2.ClientConfig
  • gapi.auth2.OfflineAccessOptions

Métodos:

  • gapi.auth2.getAuthInstance()
  • GoogleUser.grant()

Flujo implícito

Agrega un objeto TokenClientConfig y una llamada initTokenClient() a configurar tu aplicación web; para ello, sigue el ejemplo de Inicializar un token cliente.

Reemplaza las referencias de clientes de JavaScript de Acceso con Google por Google Servicios de identidad:

Objetos:

  • gapi.auth2.AuthorizeConfig con TokenClientConfig

Métodos:

  • gapi.auth2.init() con google.accounts.oauth2.initTokenClient()

Parámetros:

  • gapi.auth2.AuthorizeConfig.login_hint con TokenClientConfig.login_hint
  • gapi.auth2.GoogleUser.getHostedDomain() con TokenClientConfig.hd.

Flujo de código de autorización

Agrega un objeto CodeClientConfig y una llamada initCodeClient() para configurar. tu aplicación web, según el ejemplo de Inicializar un cliente de código.

Cuando cambies del flujo de código de autorización implícito al flujo de código de autorización, ten en cuenta lo siguiente:

Quita las referencias de cliente de JavaScript de Acceso con Google

Objetos:

  • gapi.auth2.AuthorizeConfig

Métodos:

  • gapi.auth2.init()

Parámetros:

  • gapi.auth2.AuthorizeConfig.login_hint
  • gapi.auth2.GoogleUser.getHostedDomain()

Solicitud de token

Un gesto del usuario, como un clic en un botón, genera una solicitud que da como resultado una el token de acceso que se devuelve directamente al navegador del usuario con el token o a tu plataforma de backend después de intercambiar un código de autorización por usuario para un token de acceso y un token de actualización.

Flujo implícito

Los tokens de acceso se pueden obtener y usar en el navegador mientras el usuario esté haya accedido a su cuenta y tenga una sesión activa con Google. Para el modo implícito, un usuario se requiere un gesto para solicitar un token de acceso, incluso si hubo un para cada solicitud.

Reemplaza las referencias de clientes de JavaScript de Acceso con Google por Google Servicios de identidad:

Métodos:

  • gapi.auth2.authorize() con TokenClient.requestAccessToken()
  • GoogleUser.reloadAuthResponse() con TokenClient.requestAccessToken()

Agrega un vínculo o botón para llamar a requestAccessToken() y, así, iniciar la del flujo de UX emergente para solicitar un token de acceso u obtener un token nuevo cuando se que venza el token existente.

Actualiza tu base de código de la siguiente manera:

  • Activa el flujo de tokens de OAuth 2.0 con requestAccessToken().
  • Admitir la autorización incremental mediante requestAccessToken y OverridableTokenClientConfig para separar una solicitud para varios permisos en varias solicitudes más pequeñas.
  • Solicita un token nuevo cuando el existente venza o se revoque.

Trabajar con varios permisos puede requerir cambios estructurales en tu base de código. para solicitar acceso a los permisos solo cuando sean necesarios y no todos a la vez, esto se conoce como autorización incremental. Cada solicitud debe contener con pocos alcances posibles y, idealmente, uno solo. Ver cómo manejar las funciones consentimiento para obtener más información sobre cómo actualizar su aplicación para las autorización.

Cuando vence un token de acceso, el módulo gapi.auth2 obtiene automáticamente un token de acceso nuevo y válido para tu app web. Para mejorar la seguridad del usuario, esta El proceso de actualización automática de tokens no es compatible con Google Identity Biblioteca de servicios. Debes actualizar tu app web para detectar un acceso vencido token y solicita uno nuevo. Consulta la sección de manejo de tokens a continuación para obtener más información.

Flujo de código de autorización

Agrega un vínculo o botón para llamar a requestCode() y solicitar una autorización. código de Google. Para ver un ejemplo, consulta Activar el flujo de código de OAuth 2.0.

Consulta la sección de manejo de tokens a continuación para obtener más información sobre cómo responder a un token de acceso vencido o revocado.

Manejo de tokens

Agrega manejo de errores para detectar llamadas a la API de Google fallidas cuando un un token de acceso revocado y para solicitar uno nuevo y válido.

Un código de estado HTTP de mensaje de error 401 Unauthorized y invalid_token es que muestran las APIs de Google cuando se usa un token de acceso vencido o revocado. Para un Por ejemplo, consulta Respuesta de token no válido.

Tokens vencidos

Los tokens de acceso tienen una duración corta y, a menudo, son válidos solo por unos minutos.

Revocación de tokens

El propietario de una Cuenta de Google puede revocar el consentimiento otorgado anteriormente en cualquier momento. Hacer por lo que invalida los tokens de acceso existentes y los de actualización. La revocación puede ser se activa desde su plataforma mediante revoke() o a través de una cuenta de Google Cuenta de Google.

Reemplaza las referencias de clientes de JavaScript de Acceso con Google por Google Servicios de identidad:

Métodos:

  • getAuthInstance().disconnect() con google.accounts.oauth2.revoke()
  • GoogleUser.disconnect() con google.accounts.oauth2.revoke()

Llama a revoke cuando un usuario borre su cuenta en tu plataforma. desea quitar el consentimiento para compartir datos con tu app.

Google muestra un cuadro de diálogo de consentimiento al usuario cuando tu backend plataforma solicita un token de acceso. Ver ejemplos de diálogos de consentimiento que se muestran por Google a los usuarios.

Antes de emitir un token de acceso a tu app, se debe otorgar un permiso para solicitar el consentimiento del usuario y registrar el resultado. El usuario un usuario debe acceder a una Cuenta de Google si una sesión existente no ha ya se establecieron.

Acceso de usuarios

Los usuarios pueden acceder a una Cuenta de Google en una pestaña independiente del navegador, o bien de forma nativa a través de un navegador o sistema operativo. Te recomendamos agregar Acceder con Google a tu sitio para establecer una sesión activa entre una Cuenta de Google y el navegador cuando el usuario abre la aplicación por primera vez. Al hacerlo, se ofrecen beneficios:

  • Minimiza la cantidad de veces que un usuario debe acceder y solicitar acceso. el token inicia el proceso de acceso a la Cuenta de Google si una sesión activa que todavía no existen.
  • Utiliza directamente el campo credential email del token de ID de JWT como el valor de el parámetro login_hint en CodeClientConfig o TokenClientConfig objetos. Esto es muy útil si tu plataforma no mantiene un sistema de administración de cuentas de usuario.
  • Busca y asocia una Cuenta de Google con una cuenta de usuario local existente en tu plataforma, lo que ayuda a minimizar las cuentas duplicadas en ella.
  • Cuando se crea una nueva cuenta local, se pueden consultar los diálogos y el flujo de registro claramente separados de los diálogos y flujos de autenticación del usuario, lo que reduce la la cantidad de pasos necesarios y mejorar el porcentaje de abandono.

Después del acceso y antes de que se emita un token de acceso, los usuarios deben dar su consentimiento para tu aplicación según los permisos solicitados.

Una vez otorgado el consentimiento, se devuelve un token de acceso junto con una lista de permisos aprobados. o rechazan el usuario.

Los permisos detallados permiten que los usuarios aprueben o rechacen permisos individuales. Cuándo solicita acceso a varios permisos, cada uno se otorga o rechaza independientes de los otros alcances. Tu app se basa en la elección del usuario de manera selectiva. habilita características y funcionalidades que dependen de un alcance individual.

Flujo implícito

Reemplaza las referencias de clientes de JavaScript de Acceso con Google por Google Servicios de identidad:

Objetos:

  • gapi.auth2.AuthorizeResponse con TokenClient.TokenResponse
  • gapi.auth2.AuthResponse con TokenClient.TokenResponse

Métodos:

  • GoogleUser.hasGrantedScopes() con google.accounts.oauth2.hasGrantedAllScopes()
  • GoogleUser.getGrantedScopes() con google.accounts.oauth2.hasGrantedAllScopes()

Quita las referencias de cliente de JavaScript de Acceso con Google:

Métodos:

  • GoogleUser.getAuthResponse()

Actualiza tu app web con hasGrantedAllScopes() y hasGrantedAnyScope() siguiendo este ejemplo de permisos detallados.

Flujo de código de autorización

Actualiza o agrega un extremo de código de autorización a tu backend. siguiendo las instrucciones de manejo del código de autorización.

Actualiza tu plataforma para seguir los pasos descritos en la sección Utilizar el código. Guía del modelo para validar la solicitud, obtener un token de acceso y actualizar token.

Actualiza tu plataforma para habilitar o inhabilitar funciones de manera selectiva. funcionalidades basadas en los alcances individuales que el usuario aprobó siguiendo las instrucciones para la autorización incremental y para examinar permisos de acceso otorgados por el usuario.

Ejemplos de flujo implícito

Método anterior

Biblioteca cliente de GAPI

Ejemplo de la biblioteca cliente de la API de Google para JavaScript que se ejecuta en el navegador mediante un diálogo emergente para solicitar el consentimiento del usuario.

El módulo gapi.auth2 se carga y usa automáticamente en gapi.client.init(), y por lo tanto está oculto.

<!DOCTYPE html>
  <html>
    <head>
      <script src="https://apis.google.com/js/api.js"></script>
      <script>
        function start() {
          gapi.client.init({
            'apiKey': 'YOUR_API_KEY',
            'clientId': 'YOUR_CLIENT_ID',
            'scope': 'https://www.googleapis.com/auth/cloud-translation',
            'discoveryDocs': ['https://www.googleapis.com/discovery/v1/apis/translate/v2/rest'],
          }).then(function() {
            // Execute an API request which is returned as a Promise.
            // The method name language.translations.list comes from the API discovery.
            return gapi.client.language.translations.list({
              q: 'hello world',
              source: 'en',
              target: 'de',
            });
          }).then(function(response) {
            console.log(response.result.data.translations[0].translatedText);
          }, function(reason) {
            console.log('Error: ' + reason.result.error.message);
          });
        };

        // Load the JavaScript client library and invoke start afterwards.
        gapi.load('client', start);
      </script>
    </head>
    <body>
      <div id="results"></div>
    </body>
  </html>

Biblioteca cliente de JS

OAuth 2.0 para aplicaciones web del lado del cliente que se ejecutan en el navegador con una Diálogo emergente para el consentimiento del usuario.

El módulo gapi.auth2 se carga de forma manual.

<!DOCTYPE html>
<html><head></head><body>
<script>
  var GoogleAuth;
  var SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly';
  function handleClientLoad() {
    // Load the API's client and auth2 modules.
    // Call the initClient function after the modules load.
    gapi.load('client:auth2', initClient);
  }

  function initClient() {
    // In practice, your app can retrieve one or more discovery documents.
    var discoveryUrl = 'https://www.googleapis.com/discovery/v1/apis/drive/v3/rest';

    // Initialize the gapi.client object, which app uses to make API requests.
    // Get API key and client ID from API Console.
    // 'scope' field specifies space-delimited list of access scopes.
    gapi.client.init({
        'apiKey': 'YOUR_API_KEY',
        'clientId': 'YOUR_CLIENT_ID',
        'discoveryDocs': [discoveryUrl],
        'scope': SCOPE
    }).then(function () {
      GoogleAuth = gapi.auth2.getAuthInstance();

      // Listen for sign-in state changes.
      GoogleAuth.isSignedIn.listen(updateSigninStatus);

      // Handle initial sign-in state. (Determine if user is already signed in.)
      var user = GoogleAuth.currentUser.get();
      setSigninStatus();

      // Call handleAuthClick function when user clicks on
      //      "Sign In/Authorize" button.
      $('#sign-in-or-out-button').click(function() {
        handleAuthClick();
      });
      $('#revoke-access-button').click(function() {
        revokeAccess();
      });
    });
  }

  function handleAuthClick() {
    if (GoogleAuth.isSignedIn.get()) {
      // User is authorized and has clicked "Sign out" button.
      GoogleAuth.signOut();
    } else {
      // User is not signed in. Start Google auth flow.
      GoogleAuth.signIn();
    }
  }

  function revokeAccess() {
    GoogleAuth.disconnect();
  }

  function setSigninStatus() {
    var user = GoogleAuth.currentUser.get();
    var isAuthorized = user.hasGrantedScopes(SCOPE);
    if (isAuthorized) {
      $('#sign-in-or-out-button').html('Sign out');
      $('#revoke-access-button').css('display', 'inline-block');
      $('#auth-status').html('You are currently signed in and have granted ' +
          'access to this app.');
    } else {
      $('#sign-in-or-out-button').html('Sign In/Authorize');
      $('#revoke-access-button').css('display', 'none');
      $('#auth-status').html('You have not authorized this app or you are ' +
          'signed out.');
    }
  }

  function updateSigninStatus() {
    setSigninStatus();
  }
</script>

<button id="sign-in-or-out-button"
        style="margin-left: 25px">Sign In/Authorize</button>
<button id="revoke-access-button"
        style="display: none; margin-left: 25px">Revoke access</button>

<div id="auth-status" style="display: inline; padding-left: 25px"></div><hr>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script async defer src="https://apis.google.com/js/api.js"
        onload="this.onload=function(){};handleClientLoad()"
        onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>
</body></html>

Extremos de OAuth 2.0

OAuth 2.0 para aplicaciones web del lado del cliente que se ejecutan en el navegador con redirige a Google para obtener el consentimiento del usuario.

Este ejemplo muestra las llamadas directas a los extremos de OAuth 2.0 de Google desde el navegador del usuario y no usa el módulo gapi.auth2 ni JavaScript biblioteca.

<!DOCTYPE html>
<html><head></head><body>
<script>
  var YOUR_CLIENT_ID = 'REPLACE_THIS_VALUE';
  var YOUR_REDIRECT_URI = 'REPLACE_THIS_VALUE';
  var fragmentString = location.hash.substring(1);

  // Parse query string to see if page request is coming from OAuth 2.0 server.
  var params = {};
  var regex = /([^&=]+)=([^&]*)/g, m;
  while (m = regex.exec(fragmentString)) {
    params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
  }
  if (Object.keys(params).length > 0) {
    localStorage.setItem('oauth2-test-params', JSON.stringify(params) );
    if (params['state'] && params['state'] == 'try_sample_request') {
      trySampleRequest();
    }
  }

  // If there's an access token, try an API request.
  // Otherwise, start OAuth 2.0 flow.
  function trySampleRequest() {
    var params = JSON.parse(localStorage.getItem('oauth2-test-params'));
    if (params && params['access_token']) {
      var xhr = new XMLHttpRequest();
      xhr.open('GET',
          'https://www.googleapis.com/drive/v3/about?fields=user&' +
          'access_token=' + params['access_token']);
      xhr.onreadystatechange = function (e) {
        if (xhr.readyState === 4 && xhr.status === 200) {
          console.log(xhr.response);
        } else if (xhr.readyState === 4 && xhr.status === 401) {
          // Token invalid, so prompt for user permission.
          oauth2SignIn();
        }
      };
      xhr.send(null);
    } else {
      oauth2SignIn();
    }
  }

  /*

    *   Create form to request access token from Google's OAuth 2.0 server.
 */
function oauth2SignIn() {
  // Google's OAuth 2.0 endpoint for requesting an access token
  var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';

    // Create element to open OAuth 2.0 endpoint in new window.
    var form = document.createElement('form');
    form.setAttribute('method', 'GET'); // Send as a GET request.
    form.setAttribute('action', oauth2Endpoint);

    // Parameters to pass to OAuth 2.0 endpoint.
    var params = {'client_id': YOUR_CLIENT_ID,
                  'redirect_uri': YOUR_REDIRECT_URI,
                  'scope': 'https://www.googleapis.com/auth/drive.metadata.readonly',
                  'state': 'try_sample_request',
                  'include_granted_scopes': 'true',
                  'response_type': 'token'};

    // Add form parameters as hidden input values.
    for (var p in params) {
      var input = document.createElement('input');
      input.setAttribute('type', 'hidden');
      input.setAttribute('name', p);
      input.setAttribute('value', params[p]);
      form.appendChild(input);
    }

    // Add form to page and submit it to open the OAuth 2.0 endpoint.
    document.body.appendChild(form);
    form.submit();
  }
</script>

<button onclick="trySampleRequest();">Try sample request</button>
</body></html>

Método nuevo

Solo GIS

En este ejemplo, solo se muestra la biblioteca JavaScript de Google Identity Service Usar el modelo de token y un cuadro de diálogo emergente para obtener el consentimiento del usuario. Sí para ilustrar la cantidad mínima de pasos necesarios para configurar una cliente, solicitar y obtener un token de acceso y llamar a una API de Google.

<!DOCTYPE html>
<html>
  <head>
    <script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
  </head>
  <body>
    <script>
      var client;
      var access_token;

      function initClient() {
        client = google.accounts.oauth2.initTokenClient({
          client_id: 'YOUR_CLIENT_ID',
          scope: 'https://www.googleapis.com/auth/calendar.readonly \
                  https://www.googleapis.com/auth/contacts.readonly',
          callback: (tokenResponse) => {
            access_token = tokenResponse.access_token;
          },
        });
      }
      function getToken() {
        client.requestAccessToken();
      }
      function revokeToken() {
        google.accounts.oauth2.revoke(access_token, () => {console.log('access token revoked')});
      }
      function loadCalendar() {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', 'https://www.googleapis.com/calendar/v3/calendars/primary/events');
        xhr.setRequestHeader('Authorization', 'Bearer ' + access_token);
        xhr.send();
      }
    </script>
    <h1>Google Identity Services Authorization Token model</h1>
    <button onclick="getToken();">Get access token</button><br><br>
    <button onclick="loadCalendar();">Load Calendar</button><br><br>
    <button onclick="revokeToken();">Revoke token</button>
  </body>
</html>

GAPI asíncrono/esperar

En este ejemplo se muestra cómo agregar la biblioteca de Google Identity Service con la token de inicio, quita el módulo gapi.auth2 y llama a una API con el Biblioteca cliente de las APIs de Google para JavaScript.

Las promesas, async y await se usan para aplicar el orden de carga de la biblioteca y detectar y reintentar errores de autorización. Una llamada a la API se realiza solo después de que el token de acceso esté disponible.

Se espera que los usuarios presionen el botón “Mostrar calendario” cuando el token de acceso falta cuando la página se carga por primera vez o después del token de acceso. ha caducado.

<!DOCTYPE html>
<html>
<head></head>
<body>
  <h1>GAPI with GIS async/await</h1>
  <button id="showEventsBtn" onclick="showEvents();">Show Calendar</button><br><br>
  <button id="revokeBtn" onclick="revokeToken();">Revoke access token</button>

  <script>

    const gapiLoadPromise = new Promise((resolve, reject) => {
      gapiLoadOkay = resolve;
      gapiLoadFail = reject;
    });
    const gisLoadPromise = new Promise((resolve, reject) => {
      gisLoadOkay = resolve;
      gisLoadFail = reject;
    });

    var tokenClient;

    (async () => {
      document.getElementById("showEventsBtn").style.visibility="hidden";
      document.getElementById("revokeBtn").style.visibility="hidden";

      // First, load and initialize the gapi.client
      await gapiLoadPromise;
      await new Promise((resolve, reject) => {
        // NOTE: the 'auth2' module is no longer loaded.
        gapi.load('client', {callback: resolve, onerror: reject});
      });
      await gapi.client.init({
        // NOTE: OAuth2 'scope' and 'client_id' parameters have moved to initTokenClient().
      })
      .then(function() {  // Load the Calendar API discovery document.
        gapi.client.load('https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest');
      });

      // Now load the GIS client
      await gisLoadPromise;
      await new Promise((resolve, reject) => {
        try {
          tokenClient = google.accounts.oauth2.initTokenClient({
              client_id: 'YOUR_CLIENT_ID',
              scope: 'https://www.googleapis.com/auth/calendar.readonly',
              prompt: 'consent',
              callback: '',  // defined at request time in await/promise scope.
          });
          resolve();
        } catch (err) {
          reject(err);
        }
      });

      document.getElementById("showEventsBtn").style.visibility="visible";
      document.getElementById("revokeBtn").style.visibility="visible";
    })();

    async function getToken(err) {

      if (err.result.error.code == 401 || (err.result.error.code == 403) &&
          (err.result.error.status == "PERMISSION_DENIED")) {

        // The access token is missing, invalid, or expired, prompt for user consent to obtain one.
        await new Promise((resolve, reject) => {
          try {
            // Settle this promise in the response callback for requestAccessToken()
            tokenClient.callback = (resp) => {
              if (resp.error !== undefined) {
                reject(resp);
              }
              // GIS has automatically updated gapi.client with the newly issued access token.
              console.log('gapi.client access token: ' + JSON.stringify(gapi.client.getToken()));
              resolve(resp);
            };
            tokenClient.requestAccessToken();
          } catch (err) {
            console.log(err)
          }
        });
      } else {
        // Errors unrelated to authorization: server errors, exceeding quota, bad requests, and so on.
        throw new Error(err);
      }
    }

    function showEvents() {

      // Try to fetch a list of Calendar events. If a valid access token is needed,
      // prompt to obtain one and then retry the original request.
      gapi.client.calendar.events.list({ 'calendarId': 'primary' })
      .then(calendarAPIResponse => console.log(JSON.stringify(calendarAPIResponse)))
      .catch(err  => getToken(err))  // for authorization errors obtain an access token
      .then(retry => gapi.client.calendar.events.list({ 'calendarId': 'primary' }))
      .then(calendarAPIResponse => console.log(JSON.stringify(calendarAPIResponse)))
      .catch(err  => console.log(err)); // cancelled by user, timeout, etc.
    }

    function revokeToken() {
      let cred = gapi.client.getToken();
      if (cred !== null) {
        google.accounts.oauth2.revoke(cred.access_token, () => {console.log('Revoked: ' + cred.access_token)});
        gapi.client.setToken('');
      }
    }

  </script>

  <script async defer src="https://apis.google.com/js/api.js" onload="gapiLoadOkay()" onerror="gapiLoadFail(event)"></script>
  <script async defer src="https://accounts.google.com/gsi/client" onload="gisLoadOkay()" onerror="gisLoadFail(event)"></script>

</body>
</html>

Devolución de llamada de GAPI

En este ejemplo se muestra cómo agregar la biblioteca de Google Identity Service con la token de inicio, quita el módulo gapi.auth2 y llama a una API con el Biblioteca cliente de las APIs de Google para JavaScript.

Las variables se usan para aplicar el orden de carga de la biblioteca. Se realizan llamadas a GAPI. desde la devolución de llamada después de que se devuelve un token de acceso válido.

Se espera que los usuarios presionen el botón Mostrar calendario cuando se abre la página por primera vez y otra vez cuando quieren actualizar la información de Calendario.

<!DOCTYPE html>
<html>
<head>
  <script async defer src="https://apis.google.com/js/api.js" onload="gapiLoad()"></script>
  <script async defer src="https://accounts.google.com/gsi/client" onload="gisInit()"></script>
</head>
<body>
  <h1>GAPI with GIS callbacks</h1>
  <button id="showEventsBtn" onclick="showEvents();">Show Calendar</button><br><br>
  <button id="revokeBtn" onclick="revokeToken();">Revoke access token</button>
  <script>
    let tokenClient;
    let gapiInited;
    let gisInited;

    document.getElementById("showEventsBtn").style.visibility="hidden";
    document.getElementById("revokeBtn").style.visibility="hidden";

    function checkBeforeStart() {
       if (gapiInited && gisInited){
          // Start only when both gapi and gis are initialized.
          document.getElementById("showEventsBtn").style.visibility="visible";
          document.getElementById("revokeBtn").style.visibility="visible";
       }
    }

    function gapiInit() {
      gapi.client.init({
        // NOTE: OAuth2 'scope' and 'client_id' parameters have moved to initTokenClient().
      })
      .then(function() {  // Load the Calendar API discovery document.
        gapi.client.load('https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest');
        gapiInited = true;
        checkBeforeStart();
      });
    }

    function gapiLoad() {
        gapi.load('client', gapiInit)
    }

    function gisInit() {
     tokenClient = google.accounts.oauth2.initTokenClient({
                client_id: 'YOUR_CLIENT_ID',
                scope: 'https://www.googleapis.com/auth/calendar.readonly',
                callback: '',  // defined at request time
            });
      gisInited = true;
      checkBeforeStart();
    }

    function showEvents() {

      tokenClient.callback = (resp) => {
        if (resp.error !== undefined) {
          throw(resp);
        }
        // GIS has automatically updated gapi.client with the newly issued access token.
        console.log('gapi.client access token: ' + JSON.stringify(gapi.client.getToken()));

        gapi.client.calendar.events.list({ 'calendarId': 'primary' })
        .then(calendarAPIResponse => console.log(JSON.stringify(calendarAPIResponse)))
        .catch(err => console.log(err));

        document.getElementById("showEventsBtn").innerText = "Refresh Calendar";
      }

      // Conditionally ask users to select the Google Account they'd like to use,
      // and explicitly obtain their consent to fetch their Calendar.
      // NOTE: To request an access token a user gesture is necessary.
      if (gapi.client.getToken() === null) {
        // Prompt the user to select a Google Account and asked for consent to share their data
        // when establishing a new session.
        tokenClient.requestAccessToken({prompt: 'consent'});
      } else {
        // Skip display of account chooser and consent dialog for an existing session.
        tokenClient.requestAccessToken({prompt: ''});
      }
    }

    function revokeToken() {
      let cred = gapi.client.getToken();
      if (cred !== null) {
        google.accounts.oauth2.revoke(cred.access_token, () => {console.log('Revoked: ' + cred.access_token)});
        gapi.client.setToken('');
        document.getElementById("showEventsBtn").innerText = "Show Calendar";
      }
    }
  </script>
</body>
</html>

Ejemplos de flujo de código de autorización

La UX de la ventana emergente de la biblioteca de Google Identity Service puede usar un redireccionamiento de URL a devolver un código de autorización directamente al extremo del token de backend, o un El controlador de devolución de llamada de JavaScript que se ejecuta en el navegador del usuario que actúa como proxy en respuesta a tu plataforma. En cualquier caso, tu plataforma backend se completará el flujo de OAuth 2.0 para obtener un token de actualización y acceso válido.

Método anterior

Apps web del servidor

Acceso con Google para apps del servidor que se ejecutan en la plataforma de backend mediante un redireccionamiento a Google para obtener el consentimiento del usuario.

<!DOCTYPE html>
<html>
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
    <script src="https://apis.google.com/js/client:platform.js?onload=start" async defer></script>
    <script>
      function start() {
        gapi.load('auth2', function() {
          auth2 = gapi.auth2.init({
            client_id: 'YOUR_CLIENT_ID',
            api_key: 'YOUR_API_KEY',
            discovery_docs: ['https://www.googleapis.com/discovery/v1/apis/translate/v2/rest'],
            // Scopes to request in addition to 'profile' and 'email'
            scope: 'https://www.googleapis.com/auth/cloud-translation',
          });
        });
      }
      function signInCallback(authResult) {
        if (authResult['code']) {
          console.log("sending AJAX request");
          // Send authorization code obtained from Google to backend platform
          $.ajax({
            type: 'POST',
            url: 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URL',
            // Always include an X-Requested-With header to protect against CSRF attacks.
            headers: {
              'X-Requested-With': 'XMLHttpRequest'
            },
            contentType: 'application/octet-stream; charset=utf-8',
            success: function(result) {
              console.log(result);
            },
            processData: false,
            data: authResult['code']
          });
        } else {
          console.log('error: failed to obtain authorization code')
        }
      }
    </script>
  </head>
  <body>
    <button id="signinButton">Sign In With Google</button>
    <script>
      $('#signinButton').click(function() {
        // Obtain an authorization code from Google
        auth2.grantOfflineAccess().then(signInCallback);
      });
    </script>
  </body>
</html>

HTTP/REST con redireccionamiento

Usar OAuth 2.0 para aplicaciones de servidor web a fin de enviar código de autorización del navegador del usuario a tu plataforma de backend. El consentimiento del usuario se encarga de redireccionar el navegador del usuario a Google.

/\*
 \* Create form to request access token from Google's OAuth 2.0 server.
 \*/
function oauthSignIn() {
  // Google's OAuth 2.0 endpoint for requesting an access token
  var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';
  // Create &lt;form> element to submit parameters to OAuth 2.0 endpoint.
  var form = document.createElement('form');
  form.setAttribute('method', 'GET'); // Send as a GET request.
  form.setAttribute('action', oauth2Endpoint);
  // Parameters to pass to OAuth 2.0 endpoint.
  var params = {'client\_id': 'YOUR_CLIENT_ID',
                'redirect\_uri': 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URL',
                'response\_type': 'token',
                'scope': 'https://www.googleapis.com/auth/drive.metadata.readonly',
                'include\_granted\_scopes': 'true',
                'state': 'pass-through value'};
  // Add form parameters as hidden input values.
  for (var p in params) {
    var input = document.createElement('input');
    input.setAttribute('type', 'hidden');
    input.setAttribute('name', p);
    input.setAttribute('value', params[p]);
    form.appendChild(input);
  }

  // Add form to page and submit it to open the OAuth 2.0 endpoint.
  document.body.appendChild(form);
  form.submit();
}

Método nuevo

UX de GIS Popup

En este ejemplo, solo se muestra la biblioteca JavaScript de Google Identity Service con el modelo de código de autorización, un cuadro de diálogo emergente para solicitar el consentimiento del usuario y para recibir el código de autorización de Google. Sí para ilustrar la cantidad mínima de pasos necesarios para configurar una obtener el consentimiento y enviar un código de autorización a tu backend plataforma.

<!DOCTYPE html>
<html>
  <head>
    <script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
  </head>
  <body>
    <script>
      var client;
      function initClient() {
        client = google.accounts.oauth2.initCodeClient({
          client_id: 'YOUR_CLIENT_ID',
          scope: 'https://www.googleapis.com/auth/calendar.readonly',
          ux_mode: 'popup',
          callback: (response) => {
            var code_receiver_uri = 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URI',
            // Send auth code to your backend platform
            const xhr = new XMLHttpRequest();
            xhr.open('POST', code_receiver_uri, true);
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
            xhr.onload = function() {
              console.log('Signed in as: ' + xhr.responseText);
            };
            xhr.send('code=' + response.code);
            // After receipt, the code is exchanged for an access token and
            // refresh token, and the platform then updates this web app
            // running in user's browser with the requested calendar info.
          },
        });
      }
      function getAuthCode() {
        // Request authorization code and obtain user consent
        client.requestCode();
      }
    </script>
    <button onclick="getAuthCode();">Load Your Calendar</button>
  </body>
</html>

UX de redireccionamiento de GIS

El modelo de código de autorización admite los modos de UX de ventana emergente y redireccionamiento a enviar un código de autorización por usuario al extremo alojado por su plataforma. El modo de UX de redireccionamiento se muestra aquí:

<!DOCTYPE html>
<html>
  <head>
    <script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
  </head>
  <body>
    <script>
      var client;
      function initClient() {
        client = google.accounts.oauth2.initCodeClient({
          client_id: 'YOUR_CLIENT_ID',
          scope: 'https://www.googleapis.com/auth/calendar.readonly \
                  https://www.googleapis.com/auth/photoslibrary.readonly',
          ux_mode: 'redirect',
          redirect_uri: 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URI'
        });
      }
      // Request an access token
      function getAuthCode() {
        // Request authorization code and obtain user consent
        client.requestCode();
      }
    </script>
    <button onclick="getAuthCode();">Load Your Calendar</button>
  </body>
</html>

Bibliotecas de JavaScript

Google Identity Services es una única biblioteca de JavaScript que se usa para las una autenticación y autorización que consolidan y reemplazan las funciones y que se encuentra en varias bibliotecas y módulos diferentes:

Estas son las acciones que se deben realizar cuando migres a los servicios de identidad:

Biblioteca de JS existente Nueva biblioteca de JS Notas
apis.google.com/js/api.js accounts.google.com/gsi/client Se agregó una nueva biblioteca y se sigue el flujo implícito.
apis.google.com/js/client.js accounts.google.com/gsi/client Se agregó una biblioteca nueva y el flujo de código de autorización.

Referencia rápida de la biblioteca

Comparación de objetos y métodos entre el código JavaScript antiguo de Acceso con Google de Google Cloud y la nueva biblioteca de Google Identity Services, y Notas con información adicional y las acciones que se deben realizar durante la migración.

Antiguo Nuevo Notas
GoogleAuth y métodos asociados:
GoogleAuth.attachClickHandler() Quitar
GoogleAuth.currentUser.get() Quitar
GoogleAuth.currentUser.listen() Quitar
GoogleAuth.disconnect() google.accounts.oauth2.revoke Reemplaza lo antiguo por lo nuevo. Es posible que la revocación también se realice en https://myaccount.google.com/permissions
GoogleAuth.grantOfflineAccess() Quítalo y sigue el flujo de código de autorización.
GoogleAuth.isSignedIn.get() Quitar
GoogleAuth.isSignedIn.listen() Quitar
GoogleAuth.signIn() Quitar
GoogleAuth.signOut() Quitar
GoogleAuth.then() Quitar
GoogleUser y los métodos asociados:
GoogleUser.disconnect() google.accounts.id.revoke Reemplaza lo antiguo por lo nuevo. Es posible que la revocación también se realice en https://myaccount.google.com/permissions
GoogleUser.getAuthResponse() requestCode() or requestAccessToken() Reemplazar anterior por uno nuevo
GoogleUser.getBasicProfile() Quitar. En su lugar, usa un token de ID. Consulta Cómo migrar desde el Acceso con Google.
GoogleUser.getGrantedScopes() hasGrantedAnyScope() Reemplazar anterior por uno nuevo
GoogleUser.getHostedDomain() Quitar
GoogleUser.getId() Quitar
GoogleUser.grantOfflineAccess() Quítalo y sigue el flujo de código de autorización.
GoogleUser.grant() Quitar
GoogleUser.hasGrantedScopes() hasGrantedAnyScope() Reemplazar anterior por uno nuevo
GoogleUser.isSignedIn() Quitar
GoogleUser.reloadAuthResponse() requestAccessToken() Quita el antiguo y llama al nuevo para reemplazar el token de acceso vencido o revocado.
gapi.auth2 y métodos asociados:
Objeto gapi.auth2.AuthorizeConfig TokenClientConfig o CodeClientConfig Reemplazar anterior por uno nuevo
Objeto gapi.auth2.AuthorizeResponse Quitar
Objeto gapi.auth2.AuthResponse Quitar
gapi.auth2.authorize() requestCode() or requestAccessToken() Reemplazar anterior por uno nuevo
gapi.auth2.ClientConfig() TokenClientConfig o CodeClientConfig Reemplazar anterior por uno nuevo
gapi.auth2.getAuthInstance() Quitar
gapi.auth2.init() initTokenClient() or initCodeClient() Reemplazar anterior por uno nuevo
Objeto gapi.auth2.OfflineAccessOptions Quitar
Objeto gapi.auth2.SignInOptions Quitar
gapi.signin2 y los métodos asociados:
gapi.signin2.render() Quitar. La carga de HTML DOM del g_id_signin o la llamada de JS a google.accounts.id.renderButton activa el acceso del usuario a una Cuenta de Google.

Credenciales de ejemplo

Credenciales existentes

La biblioteca de la plataforma de Acceso con Google, la biblioteca cliente de las APIs de Google para JavaScript o llamadas directas a los extremos de Google Auth 2.0 un token de acceso de OAuth 2.0 y un token de ID de OpenID Connect en un solo respuesta.

Respuesta de ejemplo que contiene access_token y id_token:

  {
    "token_type": "Bearer",
    "access_token": "ya29.A0ARrdaM-SmArZaCIh68qXsZSzyeU-8mxhQERHrP2EXtxpUuZ-3oW8IW7a6D2J6lRnZrRj8S6-ZcIl5XVEqnqxq5fuMeDDH_6MZgQ5dgP7moY-yTiKR5kdPm-LkuPM-mOtUsylWPd1wpRmvw_AGOZ1UUCa6UD5Hg",
    "scope": "https://www.googleapis.com/auth/calendar.readonly",
    "login_hint": "AJDLj6I2d1RH77cgpe__DdEree1zxHjZJr4Q7yOisoumTZUmo5W2ZmVFHyAomUYzLkrluG-hqt4RnNxrPhArd5y6p8kzO0t8xIfMAe6yhztt6v2E-_Bb4Ec3GLFKikHSXNh5bI-gPrsI",
    "expires_in": 3599,
    "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjkzNDFhYmM0MDkyYjZmYzAzOGU0MDNjOTEwMjJkZDNlNDQ1MzliNTYiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiYXpwIjoiNTM4MzQ0NjUzMjU1LTc1OGM1aDVpc2M0NXZnazI3ZDhoOGRlYWJvdnBnNnRvLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiYXVkIjoiNTM4MzQ0NjUzMjU1LTc1OGM1aDVpc2M0NXZnazI3ZDhoOGRlYWJvdnBnNnRvLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwic3ViIjoiMTE3NzI2NDMxNjUxOTQzNjk4NjAwIiwiaGQiOiJnb29nbGUuY29tIiwiZW1haWwiOiJkYWJyaWFuQGdvb2dsZS5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6IkJBSW55TjN2MS1ZejNLQnJUMVo0ckEiLCJuYW1lIjoiQnJpYW4gRGF1Z2hlcnR5IiwicGljdHVyZSI6Imh0dHBzOi8vbGgzLmdvb2dsZXVzZXJjb250ZW50LmNvbS9hLS9BT2gxNEdnenAyTXNGRGZvbVdMX3VDemRYUWNzeVM3ZGtxTE5ybk90S0QzVXNRPXM5Ni1jIiwiZ2l2ZW5fbmFtZSI6IkJyaWFuIiwiZmFtaWx5X25hbWUiOiJEYXVnaGVydHkiLCJsb2NhbGUiOiJlbiIsImlhdCI6MTYzODk5MTYzOCwiZXhwIjoxNjM4OTk1MjM4LCJqdGkiOiI5YmRkZjE1YWFiNzE2ZDhjYmJmNDYwMmM1YWM3YzViN2VhMDQ5OTA5In0.K3EA-3Adw5HA7O8nJVCsX1HmGWxWzYk3P7ViVBb4H4BoT2-HIgxKlx1mi6jSxIUJGEekjw9MC-nL1B9Asgv1vXTMgoGaNna0UoEHYitySI23E5jaMkExkTSLtxI-ih2tJrA2ggfA9Ekj-JFiMc6MuJnwcfBTlsYWRcZOYVw3QpdTZ_VYfhUu-yERAElZCjaAyEXLtVQegRe-ymScra3r9S92TA33ylMb3WDTlfmDpWL0CDdDzby2asXYpl6GQ7SdSj64s49Yw6mdGELZn5WoJqG7Zr2KwIGXJuSxEo-wGbzxNK-mKAiABcFpYP4KHPEUgYyz3n9Vqn2Tfrgp-g65BQ",
    "session_state": {
      "extraQueryParams": {
        "authuser": "0"
      }
    },
    "first_issued_at": 1638991637982,
    "expires_at": 1638995236982,
    "idpId": "google"
  }

Credencial de servicios de identidad de Google

La biblioteca de Google Identity Services muestra lo siguiente:

  • un token de acceso cuando se usa para autorización:

    {
      "access_token": "ya29.A0ARrdaM_LWSO-uckLj7IJVNSfnUityT0Xj-UCCrGxFQdxmLiWuAosnAKMVQ2Z0LLqeZdeJii3TgULp6hR_PJxnInBOl8UoUwWoqsrGQ7-swxgy97E8_hnzfhrOWyQBmH6zs0_sUCzwzhEr_FAVqf92sZZHphr0g",
      "token_type": "Bearer",
      "expires_in": 3599,
      "scope": "https://www.googleapis.com/auth/calendar.readonly"
    }
    
  • o un token de ID cuando se usa para autenticación:

    {
      "clientId": "538344653255-758c5h5isc45vgk27d8h8deabovpg6to.apps.googleusercontent.com",
      "credential": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImMxODkyZWI0OWQ3ZWY5YWRmOGIyZTE0YzA1Y2EwZDAzMjcxNGEyMzciLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJuYmYiOjE2MzkxNTcyNjQsImF1ZCI6IjUzODM0NDY1MzI1NS03NThjNWg1aXNjNDV2Z2syN2Q4aDhkZWFib3ZwZzZ0by5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsInN1YiI6IjExNzcyNjQzMTY1MTk0MzY5ODYwMCIsIm5vbmNlIjoiZm9vYmFyIiwiaGQiOiJnb29nbGUuY29tIiwiZW1haWwiOiJkYWJyaWFuQGdvb2dsZS5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXpwIjoiNTM4MzQ0NjUzMjU1LTc1OGM1aDVpc2M0NXZnazI3ZDhoOGRlYWJvdnBnNnRvLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwibmFtZSI6IkJyaWFuIERhdWdoZXJ0eSIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS0vQU9oMTRHZ3pwMk1zRkRmb21XTF91Q3pkWFFjc3lTN2RrcUxOcm5PdEtEM1VzUT1zOTYtYyIsImdpdmVuX25hbWUiOiJCcmlhbiIsImZhbWlseV9uYW1lIjoiRGF1Z2hlcnR5IiwiaWF0IjoxNjM5MTU3NTY0LCJleHAiOjE2MzkxNjExNjQsImp0aSI6IjRiOTVkYjAyZjU4NDczMmUxZGJkOTY2NWJiMWYzY2VhYzgyMmI0NjUifQ.Cr-AgMsLFeLurnqyGpw0hSomjOCU4S3cU669Hyi4VsbqnAV11zc_z73o6ahe9Nqc26kPVCNRGSqYrDZPfRyTnV6g1PIgc4Zvl-JBuy6O9HhClAK1HhMwh1FpgeYwXqrng1tifmuotuLQnZAiQJM73Gl-J_6s86Buo_1AIx5YAKCucYDUYYdXBIHLxrbALsA5W6pZCqqkMbqpTWteix-G5Q5T8LNsfqIu_uMBUGceqZWFJALhS9ieaDqoxhIqpx_89QAr1YlGu_UO6R6FYl0wDT-nzjyeF5tonSs3FHN0iNIiR3AMOHZu7KUwZaUdHg4eYkU-sQ01QNY_11keHROCRQ",
      "select_by": "user"
    }
    

Respuesta de token no válida

Ejemplo de respuesta de Google cuando se intenta realizar una solicitud a la API con un token de acceso vencido, revocado o no válido:

Encabezados de respuesta HTTP

  www-authenticate: Bearer realm="https://accounts.google.com/", error="invalid_token"

Cuerpo de la respuesta

  {
    "error": {
      "code": 401,
      "message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
      "errors": [
        {
          "message": "Invalid Credentials",
          "domain": "global",
          "reason": "authError",
          "location": "Authorization",
          "locationType": "header"
        }
      ],
      "status": "UNAUTHENTICATED"
    }
  }