Descripción general
Para obtener un token de acceso por usuario para llamar a las APIs de Google, Google ofrece varias bibliotecas de JavaScript:
- Biblioteca de la plataforma de Acceso con Google
- Biblioteca cliente de las API de Google para JavaScript
En esta guía, se proporcionan instrucciones para migrar de estas bibliotecas a la biblioteca de Google Identity Services.
Si sigues esta guía, harás lo siguiente:
- reemplazar la biblioteca de Platform obsoleta por la biblioteca de servicios de identidad
- Si usas la biblioteca cliente de la API, quita el módulo
gapi.auth2
obsoleto, sus métodos y objetos, y reemplázalos por equivalentes de Identity Services.
Para obtener una descripción de lo que cambió en la biblioteca de JavaScript de Identity Services, lee la descripción general y cómo funciona la autorización de usuarios para revisar los términos y conceptos clave.
Si buscas autenticación para el registro y acceso de usuarios, consulta Cómo migrar desde el Acceso con Google.
Identifica tu flujo de autorización
Existen dos flujos de autorización de usuarios posibles: implícito y código de autorización.
Revisa tu app web para identificar el tipo de flujo de autorización que se usa en ese momento.
Indicaciones que tu app web usa el flujo implícito:
- Tu aplicación web se basa puramente en el navegador, sin una plataforma de backend.
- El usuario debe estar presente para llamar a las APIs de Google. Tu app solo usa tokens de acceso y no requiere tokens de actualización.
- Tu aplicación web carga
apis.google.com/js/api.js
. - Tu implementación se basa en OAuth 2.0 para aplicaciones web del cliente.
- Tu app usa los módulos
gapi.client
ogapi.auth2
que se encuentran en la biblioteca cliente de la API de Google para JavaScript.
Indicaciones que tu app web está usando 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 necesidad de 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 continuar con tu flujo existente o adoptar uno diferente se adapta mejor a tus necesidades.
Consulta Elige un flujo de autorización para comprender las diferencias y compensaciones clave entre los dos flujos.
En la mayoría de los casos, se recomienda el flujo de código de autorización, ya que ofrece el nivel más alto de seguridad del usuario. La implementación de este flujo también permite que tu plataforma agregue nuevas funciones sin conexión con mayor facilidad, como la recuperación de actualizaciones para notificar a los usuarios sobre cambios notables en su calendario, fotos, suscripciones, etcétera.
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
En los ejemplos de flujo implícito, se muestran las aplicaciones web antes y después de la migración a los servicios de identidad.
Flujo de código de autorización
Un código de autorización por usuario emitido por Google se entrega a tu plataforma de backend, en la que luego se intercambia por un token de acceso y un token de actualización.
En Ejemplos de flujo de código de autorización, se muestran apps web antes y después de la migración a los servicios de identidad.
A lo largo de esta guía, sigue las instrucciones en negrita que aparecen en las funciones Agregar, Quitar, Actualizar o Reemplazar.
Cambios en la app web en el navegador
En esta sección, se revisan los cambios que realizarás en tu app web en el navegador cuando realices la migración a la biblioteca JavaScript de los servicios de identidad de Google.
Identifica el código afectado y realiza pruebas
Una cookie de depuración puede ayudar a ubicar el código afectado y probar el comportamiento posterior a la baja.
En apps grandes o complejas, puede ser difícil encontrar todo el código afectado por la baja del módulo gapi.auth2
. Para registrar en la consola el uso existente de la funcionalidad que pronto se considerará obsoleta, establece el valor de la cookie G_AUTH2_MIGRATION
en informational
. De manera opcional, puedes agregar dos puntos seguidos de un valor de clave para acceder también al almacenamiento de sesión. Después de acceder
y recibir las credenciales, revisa o envía los registros recopilados a un backend para su análisis
posterior. Por ejemplo, informational:showauth2use
guarda el origen y la URL en una clave de almacenamiento de sesión llamada showauth2use
.
Para verificar el comportamiento de la app cuando el módulo gapi.auth2
ya no esté cargado, establece el valor de la cookie G_AUTH2_MIGRATION
en enforced
. Esto permite probar el comportamiento posterior a la baja antes de la fecha de aplicación.
Valores posibles de la cookie G_AUTH2_MIGRATION
:
enforced
No cargues el módulogapi.auth2
.informational
Registra el uso de la funcionalidad obsoleta en la consola de JS. También registra el almacenamiento de la sesión cuando se establece un nombre de clave opcional:informational:key-name
.
Para minimizar el impacto en el usuario, se recomienda que primero configures esta cookie de forma local durante el desarrollo y las pruebas, antes de usarla en entornos de producción.
Bibliotecas y módulos
El módulo gapi.auth2
administra la autenticación del usuario para el acceso y el flujo implícito para la autorización. Reemplaza este módulo obsoleto y sus objetos y métodos con la biblioteca de Google Identity Services.
Agrega la biblioteca de servicios de identidad a tu aplicación 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 biblioteca cliente de la API de Google para JavaScript y aprovechar la creación automática de métodos JS que admiten llamadas desde un documento de descubrimiento, el procesamiento por lotes de varias llamadas a la API y la funcionalidad de administración de CORS.
Galletas
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 la autenticación del usuario usa las cookies y Cómo Google usa las cookies para el uso de cookies por parte de otros productos y servicios de Google.
Credenciales
Los servicios de identidad de Google separan la autenticación y 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 muestra por separado del token de acceso que se usa para la autorización.
Para ver estos cambios, consulta Credenciales de ejemplo.
Flujo implícito
Separa la autenticación y la autorización del usuario mediante la eliminación del control de perfiles de usuario de los flujos de autorización.
Quita estas referencias de clientes de JavaScript en Acceso con Google:
Métodos
GoogleUser.getBasicProfile()
GoogleUser.getId()
Flujo de código de autorización
Los servicios de identidad separan las credenciales en el navegador en un token de ID y un token de acceso. Este cambio no se aplica a las credenciales obtenidas mediante llamadas directas a los extremos de Google OAuth 2.0 desde tu plataforma de backend o a través de bibliotecas que se ejecutan en un servidor seguro en tu plataforma, como el cliente Node.js de las API de Google.
Estado de sesión
Anteriormente, el Acceso con Google te ayudaba a administrar el estado de acceso de los usuarios por medio de:
- Controladores de devolución de llamada para supervisar el estado de la sesión del usuario.
- Objetos de escucha para eventos y cambios en el estado de acceso en la Cuenta de Google de un usuario
Eres responsable de administrar el estado de acceso y las sesiones de usuario de tu app web.
Quita estas referencias de clientes de JavaScript en 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 a fin de inicializar un cliente de token para el flujo de código implícito o de autorización.
Quita estas referencias de clientes de JavaScript en 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()
para configurar tu app web. Para ello, sigue el ejemplo de inicializar un cliente de token.
Reemplaza referencias de clientes de JavaScript en Acceso con Google por Servicios de identidad de Google:
Objetos:
gapi.auth2.AuthorizeConfig
conTokenClientConfig
Métodos:
gapi.auth2.init()
congoogle.accounts.oauth2.initTokenClient()
Parámetros:
gapi.auth2.AuthorizeConfig.login_hint
conTokenClientConfig.login_hint
.gapi.auth2.GoogleUser.getHostedDomain()
conTokenClientConfig.hd
.
Flujo de código de autorización
Agrega un objeto CodeClientConfig
y una llamada initCodeClient()
para configurar tu app web. Para ello, sigue el ejemplo de inicializar un cliente de código.
Cuando cambies del flujo implícito al de autorización, haz lo siguiente:
Quita referencias de clientes de JavaScript en 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 hacer clic en un botón, genera una solicitud que da como resultado un token de acceso que se muestra directamente al navegador del usuario con el flujo implícito, o a tu plataforma de backend después de intercambiar un código de autorización por usuario por 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 accede y tiene una sesión activa con Google. En el modo implícito, se requiere un gesto del usuario para solicitar un token de acceso, incluso si hubo una solicitud anterior.
Reemplaza referencias de cliente de JavaScript en Acceso con Google por Servicios de identidad de Google:
Métodos:
gapi.auth2.authorize()
conTokenClient.requestAccessToken()
GoogleUser.reloadAuthResponse()
conTokenClient.requestAccessToken()
Agrega un vínculo o botón para llamar a requestAccessToken()
a fin de iniciar el flujo de UX emergente y solicitar un token de acceso, o bien obtener un token nuevo cuando 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()
. - Admite la autorización incremental con
requestAccessToken
yOverridableTokenClientConfig
a fin de separar una solicitud para muchos alcances en varias solicitudes más pequeñas. - Solicita un token nuevo cuando el existente venza o se revoque.
Trabajar con varios alcances puede requerir cambios estructurales en tu base de código para solicitar acceso a los alcances solo a medida que sean necesarios y no de una sola vez. Esto se conoce como autorización incremental. Cada solicitud debe contener la menor cantidad posible de alcances y, en el mejor de los casos, un solo alcance. Consulta cómo controlar el consentimiento del usuario para obtener más información sobre cómo actualizar la app a fin de obtener autorización incremental.
Cuando un token de acceso vence, el módulo gapi.auth2
obtiene automáticamente un token de acceso nuevo y válido para tu app web. A fin de mejorar la seguridad del usuario, este proceso automático de actualización de tokens no es compatible con la biblioteca de Google Identity Services. Se debe actualizar la app web para detectar un token de acceso vencido y solicitar uno nuevo. Consulta la sección sobre administración de tokens que se encuentra más abajo 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 un código de autorización a Google. Para ver un ejemplo, consulta Activa el flujo de código de OAuth 2.0.
Consulta la sección de control de tokens a continuación para obtener más información sobre cómo responder a un token de acceso vencido o revocado.
Control de tokens
Add para detectar llamadas a la API de Google con errores cuando se usa un token de acceso vencido o revocado, y para solicitar un token de acceso válido nuevo
Las APIs de Google muestran un código de estado HTTP de mensaje de error 401 Unauthorized
y invalid_token
cuando se usa un token de acceso vencido o revocado. Para ver un ejemplo, consulta Respuesta de token no válida.
Tokens vencidos
Los tokens de acceso son de corta duración y, a menudo, son válidos solo durante unos minutos.
Revocación de tokens
El propietario de una Cuenta de Google puede revocar su consentimiento otorgado anteriormente en cualquier momento en cualquier momento. Si lo haces, se invalidarán los tokens de acceso y de actualización existentes. La revocación se puede activar desde tu plataforma con revoke()
o mediante una Cuenta de Google.
Reemplaza referencias de cliente de JavaScript en Acceso con Google por Servicios de identidad de Google:
Métodos:
getAuthInstance().disconnect()
congoogle.accounts.oauth2.revoke()
GoogleUser.disconnect()
congoogle.accounts.oauth2.revoke()
Llama a revoke
cuando un usuario borre su cuenta en tu plataforma o quiera quitar su consentimiento para compartir datos con tu app.
Mensaje de consentimiento del usuario
Google muestra un cuadro de diálogo de consentimiento al usuario cuando tu app web o plataforma de backend solicita un token de acceso. Consulta ejemplos de diálogos de consentimiento que Google muestra a los usuarios.
Antes de emitir un token de acceso a tu app, se requiere una sesión de Google existente y activa para solicitar el consentimiento del usuario y registrar el resultado. Es posible que el usuario deba acceder a una Cuenta de Google si aún no se estableció una sesión existente.
Acceso de usuarios
Los usuarios pueden acceder a una Cuenta de Google en una pestaña separada del navegador o de forma nativa a través de un navegador o sistema operativo. Te recomendamos que agregues Acceder con Google a tu sitio para establecer una sesión activa entre una Cuenta de Google y el navegador cuando el usuario abre tu app por primera vez. Esto ofrece los siguientes beneficios:
- Minimiza la cantidad de veces que un usuario debe acceder. La solicitud de un token de acceso inicia el proceso de acceso a la Cuenta de Google si aún no existe una sesión activa.
- Usa directamente el campo credential del token de ID JWT como el valor del parámetro
login_hint
en los objetosCodeClientConfig
oTokenClientConfig
.email
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 para minimizar las cuentas duplicadas en ella.
- Cuando se crea una cuenta local nueva, tus flujos de diálogo y de registro se pueden separar claramente de los diálogos y flujos de autenticación del usuario, lo que reduce la cantidad de pasos necesarios y mejora el porcentaje de abandono.
Después de acceder, y antes de emitir un token de acceso, los usuarios deben dar su consentimiento para tu aplicación para los permisos solicitados.
Respuesta de token y consentimiento
Después del consentimiento, se muestra un token de acceso junto con una lista de permisos aprobados o rechazados por el usuario.
Los permisos detallados permiten a los usuarios aprobar o rechazar permisos individuales. Cuando solicitas acceso a varios permisos, cada uno se otorga o rechaza de forma independiente de los otros permisos. En función de la elección del usuario, tu app habilita de forma selectiva características y funcionalidades que dependen de un alcance individual.
Flujo implícito
Reemplaza referencias de clientes de JavaScript en Acceso con Google por Servicios de identidad de Google:
Objetos:
gapi.auth2.AuthorizeResponse
conTokenClient.TokenResponse
gapi.auth2.AuthResponse
conTokenClient.TokenResponse
Métodos:
GoogleUser.hasGrantedScopes()
congoogle.accounts.oauth2.hasGrantedAllScopes()
GoogleUser.getGrantedScopes()
congoogle.accounts.oauth2.hasGrantedAllScopes()
Quita referencias de clientes de JavaScript en Acceso con Google:
Métodos:
GoogleUser.getAuthResponse()
Actualiza tu aplicación 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 plataforma de backend siguiendo las instrucciones en manejo de códigos de autenticación.
Actualiza tu plataforma a fin de seguir los pasos descritos en la guía Cómo usar un modelo de código para validar la solicitud y obtener un token de acceso y un token de actualización.
Actualiza tu plataforma a fin de habilitar o inhabilitar de forma selectiva características y funcionalidades según los permisos individuales que el usuario haya aprobado. Para ello, sigue las instrucciones de autorización incremental y examina los permisos de acceso otorgados por el usuario.
Ejemplos de flujo implícito
El método tradicional
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 el consentimiento del usuario.
El módulo gapi.auth2
se carga y usa automáticamente en gapi.client.init()
, por lo que queda 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 cliente que se ejecuta en el navegador mediante un 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 cliente que se ejecuta en el navegador y usa redireccionamientos a Google para el consentimiento del usuario
En este ejemplo, se muestran las llamadas directas a los extremos de OAuth 2.0 de Google desde el navegador del usuario y no se usa el módulo gapi.auth2
ni una biblioteca de JavaScript.
<!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>
La nueva forma
Solo GIS
En este ejemplo, solo se muestra la biblioteca JavaScript de Google Identity Service usando el modelo de token y el diálogo emergente para el consentimiento del usuario. Se proporciona a fin de ilustrar la cantidad mínima de pasos necesarios para configurar un 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/await
En este ejemplo, se muestra cómo agregar la biblioteca de Google Identity Service con el modelo de token, quitar el módulo gapi.auth2
y llamar a una API con la biblioteca cliente de la API de Google para JavaScript.
Se usan promesas, asíncrono y await para aplicar el orden de carga de la biblioteca y para detectar errores de autorización y volver a intentarlo. Se realiza una llamada a la API solo después de que un token de acceso válido está disponible.
Se espera que los usuarios presionen el botón “Mostrar calendario” cuando falta el token de acceso cuando se carga la página por primera vez o más tarde, cuando el token de acceso expiró.
<!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 el modelo de token, quitar el módulo gapi.auth2
y llamar a una API con la biblioteca cliente de la API de Google para JavaScript.
Las variables se usan para aplicar el orden de carga de la biblioteca. Las llamadas a la GAPI se realizan desde la devolución de llamada después de que se muestra un token de acceso válido.
Se espera que los usuarios presionen el botón Mostrar calendario cuando se carga la página por primera vez y nuevamente cuando deseen actualizar la información del 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 flujos de código de autorización
La UX emergente de la biblioteca de Google Identity Service puede usar un redireccionamiento de URL para mostrar un código de autorización directamente a tu extremo de token de backend o un controlador de devolución de llamada de JavaScript que se ejecuta en el navegador del usuario y que procesa la respuesta a tu plataforma. En cualquier caso, tu plataforma de backend completará el flujo de OAuth 2.0 para obtener un token de acceso y actualización válido.
El método tradicional
Apps web del servidor
Acceso con Google para apps del servidor que se ejecutan en una plataforma de backend mediante un redireccionamiento a Google para 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
Usa OAuth 2.0 para aplicaciones de servidor web a fin de enviar código de autorización desde el navegador del usuario a tu plataforma de backend. El consentimiento del usuario se controla mediante el redireccionamiento del 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 <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();
}
La nueva forma
UX de ventanas emergentes de GIS
En este ejemplo, solo se muestra la biblioteca JavaScript de Google Identity Service con el modelo de código de autorización, un diálogo emergente para el consentimiento del usuario y el controlador de devolución de llamada para recibir el código de autorización de Google. Se proporciona a fin de ilustrar la cantidad mínima de pasos necesarios para configurar un cliente, obtener el consentimiento y enviar un código de autorización a tu plataforma de backend.
<!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 GIS
El modelo de código de autorización admite los modos de UX de redireccionamiento y ventana emergente para enviar un código de autorización por usuario al extremo alojado en tu 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
Los servicios de identidad de Google son una única biblioteca de JavaScript que se usa para la autenticación y autorización de usuarios que consolida y reemplaza las funciones y funcionalidades que se encuentran en varias bibliotecas y módulos diferentes:
- Cliente de JavaScript de Acceso con Google y
- Biblioteca cliente de las API de Google para JavaScript.
Acciones que debes realizar cuando migras a Identity Services:
Biblioteca de JS existente | Nueva biblioteca de JS | Notas |
---|---|---|
apis.google.com/js/api.js |
accounts.google.com/gsi/client |
Agregar una nueva biblioteca y seguir el flujo implícito |
apis.google.com/js/client.js |
accounts.google.com/gsi/client |
Agrega 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 la biblioteca anterior de cliente JavaScript de Acceso con Google y la biblioteca nueva de Servicios de identidad de Google y Notas con información adicional y acciones que se deben realizar durante la migración
Antiguas | Nuevo | Notas |
---|---|---|
GoogleAuth y los métodos asociados: | ||
GoogleAuth.adjuntClickHandler() | Quitar | |
GoogleAuth.currentUser.get() | Quitar | |
GoogleAuth.currentUser.listen() | Quitar | |
GoogleAuth.disconnect() | google.accounts.oauth2.revoke. | Reemplaza la versión anterior por la nueva. La revocación también puede ocurrir en https://myaccount.google.com/permissions |
GoogleAuth.grantOfflineAccess() | Quítala 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 la versión anterior por la nueva. La revocación también puede ocurrir en https://myaccount.google.com/permissions |
UsuariodeGoogle.getAuthResponse() | requestCode() o requestAccessToken() | Reemplazar lo anterior por lo nuevo |
UsuariodeGoogle.getBasicProfile() | Quitar. En su lugar, usa el token de ID; consulta Cómo migrar desde el Acceso con Google. | |
GoogleUser.getGrantedScopes() | hasGrantedAnyScope() | Reemplazar lo anterior por lo nuevo |
UsuariodeGoogle.getHostedDomain() | Quitar | |
UsuariodeGoogle.getId() | Quitar | |
GoogleUser.grantOfflineAccess() | Quítala y sigue el flujo de código de autorización. | |
GoogleUser.grant() | Quitar | |
GoogleUser.hasGrantedScopes() | hasGrantedAnyScope() | Reemplazar lo anterior por lo nuevo |
UsuariodeGoogle.isSignedIn() | Quitar | |
GoogleUser.reloadAuthResponse() | requestAccessToken() | Quita el anterior, llama a “new” para reemplazar el token de acceso vencido o revocado. |
gapi.auth2 y los métodos asociados: | ||
Objeto gapi.auth2.AuthorizeConfig | TokenClientConfig o CodeClientConfig | Reemplazar lo anterior por lo nuevo |
Objeto gapi.auth2.AuthorizeResponse | Quitar | |
Objeto gapi.auth2.AuthResponse | Quitar | |
gapi.auth2.authorize() | requestCode() o requestAccessToken() | Reemplazar lo anterior por lo nuevo |
gapi.auth2.ClientConfig() | TokenClientConfig o CodeClientConfig | Reemplazar lo anterior por lo nuevo |
gapi.auth2.getAuthInstance() | Quitar | |
gapi.auth2.init(). | initTokenClient() o initCodeClient() | Reemplazar lo anterior por lo nuevo |
Objeto gapi.auth2.OfflineAccessOptions | Quitar | |
Objeto gapi.auth2.SignInOptions | Quitar | |
Objeto gapi.signin2 y métodos asociados: | ||
gapi.signin2.render() | Quitar. La carga del DOM HTML del elemento g_id_signin o la llamada 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 la API de Google para JavaScript o las llamadas directas a los extremos de Google Auth 2.0 muestran un token de acceso de OAuth 2.0 y un token de ID de OpenID Connect en una sola respuesta.
Ejemplo de respuesta 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 Google Identity Services
La biblioteca de Google Identity Services muestra lo siguiente:
un token de acceso cuando se utiliza para la 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 la 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"
}
}