Visão geral
Para receber um token de acesso por usuário para chamar as APIs, o Google oferece várias bibliotecas JavaScript:
Neste guia, fornecemos instruções para migrar dessas bibliotecas para a biblioteca dos Serviços de Identificação do Google.
Ao seguir este guia, você vai:
- substituir a biblioteca da Plataforma descontinuada pela biblioteca do Identity Services;
- Se você estiver usando a biblioteca de cliente da API, remova o módulo descontinuado
gapi.auth2
, os métodos e objetos dele, substituindo-os por equivalentes do Identity Services.
Para uma descrição do que mudou com a biblioteca JavaScript do Identity Services, leia a visão geral e como funciona a autorização do usuário para revisar os principais termos e conceitos.
Se você estiver procurando autenticação para o login e o login do usuário, consulte Migrar do Login do Google.
Identifique seu fluxo de autorização
Há dois fluxos de autorização do usuário possíveis: código implícito e de autorização.
Revise seu app da Web para identificar o tipo de fluxo de autorização que está sendo usado no momento.
Indicações do seu app da Web que estão usando o fluxo implícito:
- Seu app da Web é baseado apenas no navegador, sem plataforma de back-end.
- O usuário precisa estar presente para chamar APIs do Google, o app usa apenas tokens de acesso e não requer tokens de atualização.
- Seu app da Web carrega
apis.google.com/js/api.js
. - A implementação é baseada no OAuth 2.0 para aplicativos da Web do lado do cliente.
- Seu app usa os módulos
gapi.client
ougapi.auth2
encontrados na biblioteca de cliente da API do Google para JavaScript.
Indicações do seu app da Web que estão usando o fluxo de código de autorização:
Sua implementação é baseada em:
O app é executado no navegador do usuário e na plataforma de back-end.
Sua plataforma de back-end hospeda um endpoint de código de autorização.
Sua plataforma de back-end chama APIs do Google em nome dos usuários sem que eles estejam presentes, também conhecido como modo off-line.
Os tokens de atualização são gerenciados e armazenados pela sua plataforma de back-end.
Em alguns casos, sua base de código pode oferecer suporte aos dois fluxos.
Escolher um fluxo de autorização
Antes de iniciar a migração, você precisa determinar se continuar com o fluxo existente ou adotar um fluxo diferente atende melhor às suas necessidades.
Consulte Como escolher um fluxo de autorização para entender as principais diferenças e vantagens e desvantagens entre os dois fluxos.
Na maioria dos casos, o fluxo de código de autorização é recomendado, porque oferece o nível mais alto de segurança do usuário. A implementação desse fluxo também permite que sua plataforma adicione novas funcionalidades off-line com mais facilidade, como buscar atualizações para notificar os usuários sobre mudanças importantes na agenda, nas fotos, nas assinaturas e assim por diante.
Escolha um fluxo de autorização usando os seletores abaixo.
Fluxo implícito
Receber um token de acesso para uso no navegador enquanto o usuário estiver presente.
Os exemplos de fluxo implícito mostram apps da Web antes e depois da migração para o Identity Services.
Fluxo do código de autorização
Um código de autorização por usuário emitido pelo Google é entregue à sua plataforma de back-end, em que ele é trocado por um token de acesso e um token de atualização.
Os exemplos de fluxo de código de autorização mostram apps da Web antes e depois da migração para o Identity Services.
Ao longo deste guia, siga as instruções listadas em negrito para Adicionar, Remover, Atualizar ou Substituir a funcionalidade existente.
Mudanças no app da Web no navegador
Esta seção analisa as mudanças que você fará no app da Web do navegador ao migrar para a biblioteca JavaScript do Google Identity Services.
Como identificar códigos e testes afetados
Um cookie de depuração pode ajudar a localizar o código afetado e testar o comportamento após a descontinuação.
Em apps grandes ou complexos, pode ser difícil encontrar todo o código afetado pela
descontinuação do módulo gapi.auth2
. Para registrar o uso atual de uma funcionalidade obsoleta no console, defina o valor do cookie G_AUTH2_MIGRATION
como informational
. Se quiser, adicione dois pontos seguidos
de uma chave-valor para fazer o registro no
armazenamento da sessão.
Após fazer login e receber as credenciais, revise ou envie os registros coletados para um
back-end para análise posterior. Por exemplo, informational:showauth2use
salva
a origem e o URL em uma chave de armazenamento de sessão chamada showauth2use
.
Para verificar o comportamento do app quando o módulo gapi.auth2
não estiver mais carregado,
defina o valor do cookie G_AUTH2_MIGRATION
como enforced
. Isso permite testar o comportamento pós-suspensão antes da data de aplicação.
Possíveis valores de cookie G_AUTH2_MIGRATION
:
enforced
não carrega o módulogapi.auth2
.informational
registrar o uso de uma funcionalidade descontinuada no Console do JS; Além disso, registre no armazenamento de sessão quando um nome de chave opcional for definido:informational:key-name
.
Para minimizar o impacto ao usuário, é recomendável definir esse cookie localmente durante o desenvolvimento e teste, antes de usá-lo em ambientes de produção.
Bibliotecas e módulos
O módulo gapi.auth2
gerencia a autenticação do usuário para login e o
fluxo implícito para autorização, substitua este módulo descontinuado e os
objetos e métodos dele pela biblioteca do Google Identity Services.
Adicione a biblioteca do Identity Services ao seu app da Web incluindo-a no documento:
<script src="https://accounts.google.com/gsi/client" async defer></script>
Remova as instâncias de carregamento do módulo auth2
usando gapi.load('auth2', function)
.
A biblioteca dos Serviços de Identificação do Google substitui o uso do módulo gapi.auth2
.
Continue usando o módulo gapi.client
da
Biblioteca de cliente da API do Google para JavaScript
e aproveite a criação automática de métodos JS chamáveis de
um documento de descoberta, o agrupamento de várias chamadas de API e a funcionalidade de gerenciamento
de CORS.
Cookies
A autorização do usuário não exige o uso de cookies.
Consulte Como migrar do Login do Google para ver detalhes sobre como a autenticação do usuário utiliza cookies e Como o Google usa cookies para usar outros produtos e serviços do Google.
Credenciais
Os serviços de identidade do Google separam a autenticação e a autorização de usuários em duas operações distintas, e as credenciais do usuário são separadas: o token de ID usado para identificar um usuário é retornado separadamente do token de acesso usado para autorização.
Para ver essas mudanças, consulte exemplos de credenciais.
Fluxo implícito
Separe a autenticação e a autorização do usuário removendo o gerenciamento de perfis de usuários dos fluxos de autorização.
Remova estas referências do cliente JavaScript de Login do Google:
Métodos
GoogleUser.getBasicProfile()
GoogleUser.getId()
Fluxo do código de autorização
Os serviços do Identity separam credenciais no navegador em tokens de ID e de acesso. Essa alteração não se aplica a credenciais recebidas por chamadas diretas de endpoints do Google OAuth 2.0 da sua plataforma de back-end ou por bibliotecas executadas em um servidor seguro na plataforma, como o Cliente Node.js das APIs do Google.
Estado da sessão
Anteriormente, o Login do Google ajudava a gerenciar o status de login do usuário usando:
- Gerenciadores de callback para Como monitorar o estado da sessão do usuário.
- Listeners para eventos e alterações no status de login da Conta do Google de um usuário.
Você é responsável por gerenciar o estado de login e as sessões do usuário no seu app da Web.
Remova estas referências do cliente JavaScript de Login do 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()
Configuração do cliente
Atualize seu app da Web para inicializar um cliente de token para o fluxo de código implícito ou de autorização.
Remova estas referências do cliente JavaScript de Login do Google:
Objetos:
gapi.auth2.ClientConfig
gapi.auth2.OfflineAccessOptions
Métodos:
gapi.auth2.getAuthInstance()
GoogleUser.grant()
Fluxo implícito
Adicione um objeto TokenClientConfig
e uma chamada de initTokenClient()
para
configurar seu app da Web, seguindo o exemplo em
inicializar um cliente de token.
Substitua referências do cliente JavaScript do Login do Google pelos Serviços de Identificação do Google:
Objetos:
gapi.auth2.AuthorizeConfig
comTokenClientConfig
Métodos:
gapi.auth2.init()
comgoogle.accounts.oauth2.initTokenClient()
Parâmetros:
gapi.auth2.AuthorizeConfig.login_hint
comTokenClientConfig.hint
.gapi.auth2.GoogleUser.getHostedDomain()
comTokenClientConfig.hosted_domain
.
Fluxo do código de autorização
Adicione um objeto CodeClientConfig
e uma chamada de initCodeClient()
para configurar
seu app da Web, seguindo o exemplo em
Como inicializar um cliente de código.
Ao mudar do fluxo de código implícito para o de autorização, faça o seguinte:
Remover Referências do cliente JavaScript do Login do Google
Objetos:
gapi.auth2.AuthorizeConfig
Métodos:
gapi.auth2.init()
Parâmetros:
gapi.auth2.AuthorizeConfig.login_hint
gapi.auth2.GoogleUser.getHostedDomain()
Solicitação de token
Um gesto do usuário, como um clique em um botão, gera uma solicitação que resulta no retorno de um token de acesso diretamente para o navegador do usuário com o fluxo implícito ou para a plataforma de back-end após a troca de um código de autorização por usuário para um token de acesso e um token de atualização.
Fluxo implícito
Os tokens de acesso podem ser recebidos e usados no navegador enquanto o usuário estiver conectado e tiver uma sessão ativa com o Google. No modo implícito, um gesto do usuário é necessário para solicitar um token de acesso, mesmo que haja uma solicitação anterior.
Substitua referências do cliente JavaScript do Login do Google: pelos Serviços de Identificação do Google:
Métodos:
gapi.auth2.authorize()
comTokenClient.requestAccessToken()
GoogleUser.reloadAuthResponse()
comTokenClient.requestAccessToken()
Adicione um link ou botão para chamar requestAccessToken()
e inicie o
fluxo de UX pop-up para solicitar um token de acesso ou para receber um novo token quando o
token existente expirar.
Atualize sua base de código para:
- Acione o fluxo de token do OAuth 2.0
com
requestAccessToken()
. - Ofereça suporte à autorização incremental usando
requestAccessToken
eOverridableTokenClientConfig
para separar uma solicitação de muitos escopos em várias solicitações menores. - Solicite um novo token quando o token atual expirar ou for revogado.
Trabalhar com vários escopos pode exigir alterações estruturais na sua base de código para solicitar acesso a eles apenas quando necessário, e não de uma só vez. Isso é conhecido como autorização incremental. Cada solicitação precisa conter o menor número possível de escopos e, de preferência, um único escopo. Veja como processar o consentimento do usuário para mais informações sobre como atualizar seu app para autorização incremental.
Quando um token de acesso expira, o módulo gapi.auth2
recebe automaticamente
um novo token de acesso válido para seu app da Web. Para melhorar a segurança do usuário,
esse processo de atualização automática de token não é compatível com a biblioteca do Google
Identity Services. Seu app da Web precisa ser atualizado para detectar um token de acesso
expirado e solicitar um novo. Consulte a seção "Gerenciamento de tokens" abaixo para mais informações.
Fluxo do código de autorização
Adicione um link ou botão para chamar requestCode()
e solicitar um código de autorização do Google. Veja um exemplo em
Fluxo de código do acionador do OAuth 2.0.
Consulte a seção "Gerenciamento de tokens" abaixo para saber mais sobre como responder a um token de acesso expirado ou revogado.
Gerenciamento de tokens
Adicionar processamento de erros para detectar chamadas com falha da API do Google quando um token de acesso expirado ou revogado é usado e para solicitar um novo token de acesso válido.
Um código de status HTTP da mensagem de erro 401 Unauthorized
e invalid_token
é retornado pelas APIs do Google quando um token de acesso expirado ou revogado é usado. Veja um
exemplo em
Resposta de token inválida.
Tokens expirados
Os tokens de acesso são curtos e geralmente são válidos por apenas alguns minutos.
Revogação de token
O proprietário da Conta do Google pode revogar o consentimento dado a qualquer momento.
Isso invalida os tokens de acesso existentes e os tokens de atualização. A revogação pode ser acionada na sua plataforma usando revoke()
ou com uma Conta do Google.
Substitua referências do cliente JavaScript do Login do Google: pelos Serviços de Identificação do Google:
Métodos:
getAuthInstance().disconnect()
comgoogle.accounts.oauth2.revoke()
GoogleUser.disconnect()
comgoogle.accounts.oauth2.revoke()
Chame revoke
quando um usuário excluir a conta na sua plataforma ou quiser remover o consentimento
para compartilhar dados com seu app.
Solicitação de consentimento do usuário
O Google exibe uma caixa de diálogo de consentimento ao usuário quando o app da Web ou a plataforma de back-end solicita um token de acesso. Veja exemplos de caixas de diálogo de consentimento exibidas pelo Google para os usuários.
Antes de emitir um token de acesso para o app, é necessária uma sessão do Google ativa e ativa para solicitar o consentimento do usuário e registrar o resultado. O usuário poderá precisar fazer login em uma Conta do Google se uma sessão existente ainda não tiver sido estabelecida.
Login do usuário
Os usuários podem estar conectados a uma Conta do Google em uma guia separada do navegador ou de forma nativa em um navegador ou sistema operacional. Recomendamos adicionar o Login com o Google ao seu site para estabelecer uma sessão ativa entre uma Conta do Google e o navegador quando o usuário abrir o app pela primeira vez. Isso oferece estes benefícios:
- Minimiza o número de vezes que um usuário precisa fazer login, solicitando um token de acesso, para iniciar o processo de login na Conta do Google se ainda não existir uma sessão ativa.
- Use diretamente o campo
credential
email
do token de ID do JWT como o valor do parâmetrohint
em objetosCodeClientConfig
ouTokenClientConfig
. Isso é útil principalmente se a plataforma não tem um sistema de gerenciamento de contas de usuário. - Pesquise e associe uma Conta do Google a uma conta de usuário local na sua plataforma, ajudando a minimizar contas duplicadas.
- Quando uma nova conta local é criada, as caixas de diálogo e o fluxo de inscrição podem ser separados claramente das caixas de diálogo e fluxos de autenticação do usuário, reduzindo o número de etapas necessárias e melhorando a taxa de desistência.
Após o login e antes da emissão de um token de acesso, os usuários precisam dar consentimento para o aplicativo nos escopos solicitados.
Resposta de token e consentimento
Depois do consentimento, um token de acesso é retornado com uma lista de escopos aprovados ou rejeitados pelo usuário.
Com as permissões granulares, os usuários podem aprovar ou negar escopos individuais. Ao solicitar acesso a vários escopos, cada um é concedido ou rejeitado independentemente dos outros escopos. Com base na escolha do usuário, o app ativa seletivamente os recursos e funcionalidades que dependem de um escopo individual.
Fluxo implícito
Substitua referências do cliente JavaScript do Login do Google pelos Serviços de Identificação do Google:
Objetos:
gapi.auth2.AuthorizeResponse
comTokenClient.TokenResponse
gapi.auth2.AuthResponse
comTokenClient.TokenResponse
Métodos:
GoogleUser.hasGrantedScopes()
comgoogle.accounts.oauth2.hasGrantedAllScopes()
GoogleUser.getGrantedScopes()
comgoogle.accounts.oauth2.hasGrantedAllScopes()
Remova referências do cliente JavaScript do Login do Google:
Métodos:
GoogleUser.getAuthResponse()
Atualize seu app da Web com hasGrantedAllScopes()
e
hasGrantedAnyScope()
seguindo este
exemplo de
permissões granulares.
Fluxo do código de autorização
Atualize ou adicione um endpoint de código de autorização à plataforma de back-end seguindo as instruções no gerenciamento de código de autenticação.
Atualize a plataforma para seguir as etapas descritas no guia Usar modelo de código a fim de validar a solicitação e receber um token de acesso e de atualização.
Atualize a plataforma para ativar ou desativar seletivamente os recursos e funcionalidades com base nos escopos individuais que o usuário aprovou, seguindo as instruções de autorização incremental e examine os escopos de acesso concedidos pelo usuário.
Exemplos de fluxo implícito
O jeito antigo
Biblioteca de cliente GAPI
Exemplo da biblioteca de cliente da API do Google para JavaScript em execução no navegador usando uma caixa de diálogo pop-up para consentimento do usuário.
O módulo gapi.auth2
é carregado e usado automaticamente por
gapi.client.init()
e, portanto, fica 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 de cliente JS
OAuth 2.0 para aplicativos da Web do lado do cliente executados em um navegador com uma caixa de diálogo pop-up para consentimento do usuário.
O módulo gapi.auth2
é carregado manualmente.
<!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>
Endpoints do OAuth 2.0
OAuth 2.0 para aplicativos da Web do lado do cliente executados no navegador com redirecionamentos para o consentimento do usuário.
Este exemplo mostra chamadas diretas para os endpoints do OAuth 2.0 do Google pelo navegador do usuário e não usa o módulo gapi.auth2
ou uma biblioteca 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>
Nova forma
Somente GIS
Este exemplo mostra apenas a biblioteca JavaScript do Google Identity Service usando o modelo de token e a caixa de diálogo pop-up para o consentimento do usuário. Ele é fornecido para ilustrar o número mínimo de etapas necessárias para configurar um cliente, solicitar e receber um token de acesso e chamar uma API do 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 async/await
Este exemplo mostra como adicionar a biblioteca do Google Identity Service
usando o modelo de token,
remover o módulo gapi.auth2
e chamar uma API usando a
Biblioteca de cliente da API do Google para JavaScript.
As promessas, assíncronas e de espera, são usadas para aplicar a ordem de carregamento da biblioteca e detectar e repetir erros de autorização. Uma chamada de API só é feita depois que um token de acesso válido está disponível.
Espera-se que os usuários pressionem o botão "Mostrar agenda" quando o token de acesso estiver ausente quando a página for carregada pela primeira vez ou depois que o token de acesso expirar.
<!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>
Callback do GAPI
Este exemplo mostra como adicionar a biblioteca do Google Identity Service
usando o modelo de token,
remover o módulo gapi.auth2
e chamar uma API usando a
Biblioteca de cliente da API do Google para JavaScript.
As variáveis são usadas para aplicar a ordem de carregamento da biblioteca. As chamadas de GAPI são feitas de dentro do callback depois que um token de acesso válido é retornado.
Os usuários precisam pressionar o botão "Mostrar agenda" quando a página é carregada pela primeira vez e novamente quando querem atualizar as informações da agenda.
<!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>
Exemplos de fluxo de código de autorização
A UX pop-up da biblioteca do Google Identity Service pode usar um redirecionamento de URL para retornar um código de autorização diretamente ao endpoint do token de back-end ou um gerenciador de callback JavaScript em execução no navegador do usuário que encaminha a resposta à sua plataforma. Em ambos os casos, a plataforma de back-end concluirá o fluxo do OAuth 2.0 para receber um token válido de atualização e acesso.
O jeito antigo
Apps da Web do lado do servidor
Login do Google para apps do lado do servidor executados em uma plataforma de back-end usando um redirecionamento para o Google para consentimento do usuário.
<!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 com redirecionamento
Como usar o OAuth 2.0 para aplicativos de servidor da Web para enviar o código de autorização do navegador do usuário à sua plataforma de back-end. O consentimento do usuário é processado redirecionando o navegador do usuário para o 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();
}
Nova forma
UX de pop-up SIG
Este exemplo mostra somente a biblioteca JavaScript do Google Identity Service usando o modelo de código de autorização uma caixa de diálogo pop-up para o consentimento do usuário e o gerenciador de callback receberem o código de autorização do Google. Ele é fornecido para ilustrar o número mínimo de etapas necessárias para configurar um cliente, receber consentimento e enviar um código de autorização para sua plataforma de back-end.
<!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 redirecionamento de SIG
O modelo de código de autorização oferece suporte aos modos de UX de redirecionamento e redirecionamento para enviar um código de autorização por usuário ao endpoint hospedado pela sua plataforma. O modo de UX de redirecionamento é mostrado aqui:
<!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 JavaScript
O Google Identity Services é uma biblioteca JavaScript usada para autenticação e autorização de usuários que consolida e substitui recursos e funcionalidades encontrados em várias bibliotecas e módulos diferentes:
Ações a serem tomadas ao migrar para o Identity Services:
Biblioteca JS existente | Nova biblioteca JS | Observações |
---|---|---|
apis.google.com/js/api.js |
accounts.google.com/gsi/client |
Adicione uma nova biblioteca e siga o fluxo implícito. |
apis.google.com/js/client.js |
accounts.google.com/gsi/client |
Adicione uma nova biblioteca e o fluxo do código de autorização. |
Referência rápida da biblioteca
Comparação de métodos e objetos entre a biblioteca de cliente antigo Cliente JavaScript do Login do Google e a biblioteca Novo Serviços de Identificação do Google e Observações com mais informações e ações a serem tomadas durante a migração.
Antigo | Novo | Observações |
---|---|---|
GoogleAuth e métodos associados: | ||
GoogleAuth.AttachClickHandler() | Remover | |
GoogleAuth.currentUser.get(). | Remover | |
GoogleAuth.currentUser.listen(). | Remover | |
GoogleAuth.disconnect(). | google.accounts.oauth2.revoke (link em inglês) | Substituir antigo por novo. Revogação também em https://myaccount.google.com/permissions |
GoogleAuth.grantofflineAccess() | Remova o fluxo de código de autorização. | |
GoogleAuth.isSignedIn.get(). | Remover | |
GoogleAuth.isSignedIn.listen(). | Remover | |
GoogleAuth.signIn(). | Remover | |
GoogleAuth.signOut(). | Remover | |
GoogleAuth.then() | Remover | |
GoogleUser e métodos associados: | ||
GoogleUser.disconnect(). | google.accounts.id.revoke (link em inglês) | Substituir antigo por novo. Revogação também em https://myaccount.google.com/permissions |
GoogleUser.getAuthResponse() | requestCode() ou requestAccessToken() | Substituir antigo por novos |
GoogleUser.getBasicProfile(). | Remover. Use o token de ID em Migrar do Login do Google. | |
GoogleUser.getGrantedScopes(). | hasGrantedAnyScope() | Substituir antigo por novos |
GoogleUser.getHostedDomain(). | Remover | |
GoogleUser.getId() | Remover | |
GoogleUser.grantofflineAccess() | Remova o fluxo de código de autorização. | |
GoogleUser.grant(). | Remover | |
GoogleUser.hasGrantedScopes(). | hasGrantedAnyScope() | Substituir antigo por novos |
GoogleUser.isSignedIn(). | Remover | |
GoogleUser.reloadAuthResponse() | requestAccessToken() | Remova o antigo, chame novo para substituir o token de acesso expirado ou revogado. |
objeto gapi.auth2 e os métodos associados: | ||
Objeto gapi.auth2.AuthorizeConfig | TokenClientConfig ou CodeClientConfig | Substituir antigo por novos |
Objeto gapi.auth2.AuthorizeResponse | Remover | |
Objeto gapi.auth2.AuthResponse | Remover | |
gapi.auth2.authorized(). | requestCode() ou requestAccessToken() | Substituir antigo por novos |
gapi.auth2.ClientConfig(). | TokenClientConfig ou CodeClientConfig | Substituir antigo por novos |
gapi.auth2.getAuthInstance(). | Remover | |
gapi.auth2.init(). | initTokenClient() ou initCodeClient() | Substituir antigo por novos |
Objeto gapi.auth2.offlineAccessOptions | Remover | |
Objeto gapi.auth2.SignInOptions | Remover | |
objeto gapi.signin2 e os métodos associados: | ||
gapi.signin2.render(). | Remover. O carregamento do DOM HTML do elemento g_id_signin ou da chamada de JS para google.accounts.id.renderButton aciona o login do usuário em uma Conta do Google. |
Exemplos de credenciais
Credenciais atuais
A biblioteca da Plataforma de Login do Google, a biblioteca de cliente da API do Google para JavaScript ou chamadas diretas para endpoints do Google Auth 2.0 retornam um token de acesso OAuth 2.0 e um token de ID do OpenID Connect em uma única resposta.
Exemplo de resposta que contém access_token
e 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 do Google Identity Services
A biblioteca do Google Identity Services retorna:
- um token de acesso quando usado para autorização:
{
"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"
}
- ou um token de ID, quando usado para autenticação:
{
"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"
}
Resposta de token inválida
Exemplo de resposta do Google ao tentar fazer uma solicitação de API usando um token de acesso expirado, revogado ou inválido:
Cabeçalhos de resposta HTTP
www-authenticate: Bearer realm="https://accounts.google.com/", error="invalid_token"
Corpo da resposta
{
"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"
}
}