Visão geral
Para receber um token de acesso por usuário para chamar as APIs do Google, o Google oferece várias bibliotecas JavaScript:
Neste guia, mostramos como migrar dessas bibliotecas para a biblioteca de Serviços de Identificação do Google.
Ao seguir este guia, você vai:
- substituir a biblioteca da plataforma descontinuada pela biblioteca de Serviços de Identidade; e
- Se você estiver usando a biblioteca de cliente da API, remova o módulo
gapi.auth2descontinuado, os métodos e os objetos dele, substituindo-os por equivalentes do serviço de identidade.
Para uma descrição do que mudou na biblioteca JavaScript dos Serviços de Identidade, leia a visão geral e como funciona a autorização do usuário para analisar os principais termos e conceitos.
Se você estiver procurando autenticação para inscrição e login de usuários, consulte Como migrar do Login do Google.
Identificar o fluxo de autorização
Há dois fluxos possíveis de autorização do usuário: implícito e código de autorização.
Analise seu app da Web para identificar o tipo de fluxo de autorização que está sendo usado.
Indicações de que seu app da Web está usando o fluxo implícito:
- Seu app da Web é baseado exclusivamente no navegador, sem plataforma de back-end.
- O usuário precisa estar presente para chamar as APIs do Google, seu app usa apenas tokens de acesso e não requer tokens de atualização.
- O app da Web carrega
apis.google.com/js/api.js. - Sua implementação é baseada no OAuth 2.0 para aplicativos da Web do lado do cliente.
- Seu app usa os módulos
gapi.clientougapi.auth2encontrados na biblioteca de cliente das APIs do Google para JavaScript.
Indicações de que seu app da Web está usando o fluxo do 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 as APIs do Google em nome dos usuários sem exigir que eles estejam presentes, o que 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 ser compatível com os dois fluxos.
Escolher um fluxo de autorização
Antes de iniciar a migração, determine se continuar com o fluxo atual ou adotar um fluxo diferente atende melhor às suas necessidades.
Leia 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 do 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, como buscar atualizações para notificar os usuários sobre mudanças importantes na agenda, nas fotos e nas assinaturas.
Escolha um fluxo de autorização usando os seletores.
Fluxo implícito
Receba 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 os serviços de identidade.
Fluxo do código de autorização
Um código de autorização por usuário emitido pelo Google é enviado para sua plataforma de back-end, onde é trocado por um token de acesso e um token de atualização.
Os exemplos de fluxo do código de autorização mostram apps da Web antes e depois da migração para os Serviços de Identidade.
Neste guia, siga as instruções em negrito para adicionar, remover, atualizar ou substituir a funcionalidade atual.
Mudanças no seu app da Web no navegador
Esta seção analisa as mudanças que você vai fazer no seu app da Web no navegador ao migrar para a biblioteca JavaScript dos Serviços de Identificação do Google.
Identificar o código afetado e testar
Um cookie de depuração pode ajudar a localizar o código afetado e testar o comportamento pós-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 que será descontinuada em breve no console, defina o valor do cookie G_AUTH2_MIGRATION como informational. Se quiser, adicione dois-pontos seguidos
por um valor de chave para também registrar no armazenamento da sessão. Depois de fazer login
e receber as credenciais, analise 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-descontinuação antes da data de aplicação.
Valores possíveis do cookie G_AUTH2_MIGRATION:
enforcedNão carregue o módulogapi.auth2.informationalRegistre o uso de funcionalidades descontinuadas no console JS. Também registre no armazenamento de sessão quando um nome de chave opcional for definido:informational:key-name.
Para minimizar o impacto para o usuário, recomendamos que você primeiro defina esse cookie localmente durante o desenvolvimento e o 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 esse módulo descontinuado e os objetos e
métodos dele pela biblioteca de Serviços de Identificação do Google.
Adicione a biblioteca do serviço de identidade ao seu app da Web incluindo-a no documento:
<script src="https://accounts.google.com/gsi/client" async defer></script>
Remova todas 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.
Você pode continuar usando o módulo gapi.client da biblioteca de cliente da API do Google para JavaScript com segurança e aproveitar a criação automática de métodos JS chamáveis de um documento de descoberta, o lote 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 Migrar do Login do Google para saber como a autenticação de usuários usa cookies e Como o Google usa cookies para saber como outros produtos e serviços do Google usam cookies.
Credenciais
Os Serviços de Identificação do Google separam a autenticação e a autorização do usuário 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 conferir essas mudanças, consulte credenciais de exemplo.
Fluxo implícito
Separe a autenticação e a autorização do usuário removendo o processamento do perfil de usuário dos fluxos de autorização.
Remova estas referências do cliente JavaScript do Login do Google:
Métodos
GoogleUser.getBasicProfile()GoogleUser.getId()
Fluxo do código de autorização
O serviço de identidade separa as credenciais no navegador em token de ID e token de acesso. Essa mudança não se aplica a credenciais recebidas por chamadas diretas aos endpoints do OAuth 2.0 do Google na sua plataforma de back-end ou por bibliotecas em execução em um servidor seguro na sua plataforma, como o cliente Node.js das APIs do Google.
Estado da sessão
Anteriormente, o Login do Google ajudava você a gerenciar o status de login do usuário usando:
- Gerenciadores de callback para monitorar o estado da sessão do usuário.
- Listeners para eventos e mudanças 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 de usuário do seu app da Web.
Remova estas referências do cliente JavaScript do 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 implícito ou de código de autorização.
Remova estas referências do cliente JavaScript do Login do Google:
Objetos:
gapi.auth2.ClientConfiggapi.auth2.OfflineAccessOptions
Métodos:
gapi.auth2.getAuthInstance()GoogleUser.grant()
Fluxo implícito
Adicione um objeto TokenClientConfig e uma chamada initTokenClient() para
configurar seu app da Web, seguindo o exemplo em Inicializar um cliente de
token.
Substitua as referências do cliente JavaScript do Login do Google pelos Serviços de Identificação do Google:
Objetos:
gapi.auth2.AuthorizeConfigcomTokenClientConfig
Métodos:
gapi.auth2.init()comgoogle.accounts.oauth2.initTokenClient()
Parâmetros:
gapi.auth2.AuthorizeConfig.login_hintcomTokenClientConfig.login_hint.gapi.auth2.GoogleUser.getHostedDomain()comTokenClientConfig.hd.
Fluxo do código de autorização
Adicione um objeto CodeClientConfig e uma chamada initCodeClient() para configurar
seu app da Web, seguindo o exemplo em Inicializar um cliente de código.
Ao mudar do fluxo implícito para o fluxo do código de autorização:
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_hintgapi.auth2.GoogleUser.getHostedDomain()
Solicitação de token
Uma interação, como um clique em um botão, gera uma solicitação que resulta no retorno de um token de acesso diretamente ao navegador do usuário com o fluxo implícito ou à sua plataforma de back-end após a troca de um código de autorização por usuário por 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 está conectado e tem uma sessão ativa com o Google. No modo implícito, uma interação do usuário é necessária para solicitar um token de acesso, mesmo que tenha havido uma solicitação anterior.
Substitua as 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 iniciar o
fluxo de UX pop-up para solicitar um token de acesso ou receber um novo token quando o
atual 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
requestAccessTokeneOverridableTokenClientConfigpara separar uma solicitação de muitos escopos em várias solicitações menores. - Solicite um novo token quando o atual expirar ou for revogado.
Trabalhar com vários escopos pode exigir mudanças estruturais na base de código para solicitar acesso aos escopos apenas quando necessário, em vez de todos de uma vez. Isso é conhecido como autorização incremental. Cada solicitação precisa conter o menor número possível de escopos, de preferência um único escopo. Consulte como lidar com o consentimento do usuário para saber mais 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 dos Serviços de Identidade
do Google. Seu app da Web precisa ser atualizado para detectar um token de acesso expirado e solicitar um novo. Consulte a seção "Processamento de tokens" para saber mais.
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. Para ver um exemplo, consulte Acionar o fluxo de código do OAuth 2.0.
Consulte a seção "Processamento de tokens" para saber mais sobre como responder a um token de acesso expirado ou revogado.
Processamento de tokens
Adicione um tratamento de erros para detectar chamadas de API do Google com falha 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 de 401 Unauthorized e uma mensagem de erro invalid_token são retornados pelas APIs do Google quando um token de acesso expirado ou revogado é usado. Veja um exemplo em Resposta de token inválido.
Tokens expirados
Os tokens de acesso têm curta duração e geralmente são válidos por apenas alguns minutos.
Revogação de token
O proprietário de uma Conta do Google pode revogar o consentimento concedido anteriormente a qualquer momento. Isso
invalidará os tokens de acesso e de atualização atuais. A revogação pode ser
acionada na sua plataforma usando revoke() ou por uma Conta do
Google.
Substitua as 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 pessoais compartilhados com seu app.
Solicitação de consentimento do usuário
O Google mostra 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. Confira exemplos de caixas de diálogo de consentimento mostradas pelo Google aos usuários.
Antes de emitir um token de acesso para seu app, é necessário ter uma sessão ativa do Google para solicitar o consentimento do usuário e registrar o resultado. O usuário pode precisar fazer login em uma Conta do Google se uma sessão 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 por um navegador ou sistema operacional. Recomendamos adicionar o Fazer 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 os seguintes benefícios:
- Minimiza o número de vezes que um usuário precisa fazer login. Solicitar um token de acesso inicia o processo de login da Conta do Google se não houver uma sessão ativa.
- Uso direto do campo credential
emaildo token de ID do JWT como o valor do parâmetrologin_hintem objetosCodeClientConfigouTokenClientConfig. Isso é especialmente útil se a plataforma não tiver 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 claramente separados das caixas de diálogo e dos fluxos de autenticação do usuário, reduzindo o número de etapas necessárias e melhorando a taxa de desistência.
Depois de fazer login e antes que um token de acesso seja emitido, os usuários precisam dar consentimento ao seu aplicativo para os escopos solicitados.
Resposta de token e consentimento
Após o consentimento, um token de acesso é retornado com uma lista de escopos aprovados ou rejeitados pelo usuário.
As permissões granulares permitem que os usuários aprovem ou neguem escopos individuais. Ao solicitar acesso a vários escopos, cada um é concedido ou rejeitado independentemente dos outros. Com base na escolha do usuário, seu app ativa seletivamente recursos e funcionalidades que dependem de um escopo individual.
Fluxo implícito
Substitua as referências do cliente JavaScript do Login do Google pelos Serviços de Identificação do Google:
Objetos:
gapi.auth2.AuthorizeResponsecomTokenClient.TokenResponsegapi.auth2.AuthResponsecomTokenClient.TokenResponse
Métodos:
GoogleUser.hasGrantedScopes()comgoogle.accounts.oauth2.hasGrantedAllScopes()GoogleUser.getGrantedScopes()comgoogle.accounts.oauth2.hasGrantedAllScopes()
Remova as 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 à sua plataforma de back-end seguindo as instruções em Processamento de código de autenticação.
Atualize sua plataforma para seguir as etapas descritas no guia Usar o modelo de código para validar a solicitação e receber um token de acesso e um token de atualização.
Atualize sua plataforma para ativar ou desativar seletivamente recursos e funcionalidades com base nos escopos individuais que o usuário aprovou. Para isso, siga as instruções de autorização incremental e analise os escopos de acesso concedidos pelo usuário.
Exemplos de fluxo implícito
Como era antes
Biblioteca de cliente da GAPI
Exemplo da biblioteca de cliente das APIs do Google para JavaScript em execução no navegador usando uma caixa de diálogo pop-up para o consentimento do usuário.
O módulo gapi.auth2 é carregado e usado automaticamente pelo
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 em execução no navegador usando uma caixa de diálogo pop-up para o 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 Google Cloud 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 em execução no navegador usando redirecionamentos para o servidor de autorização do Google para consentimento do usuário.
Este exemplo mostra chamadas diretas para os endpoints do OAuth 2.0 do Google no navegador do usuário e não usa o módulo gapi.auth2 nem 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 the Google authorization 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 the Google authorization 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>
Como será agora
Somente SIG
Este exemplo mostra apenas a biblioteca JavaScript dos Serviços de Identificação do Google 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 dos Serviços de Identificação do Google usando o
modelo de token, remover o módulo gapi.auth2 e chamar uma API usando a
biblioteca de cliente das APIs do Google para JavaScript.
As promessas, async e await são usadas para aplicar a ordem de carregamento da biblioteca e para capturar e repetir erros de autorização. Uma chamada de API é feita somente depois que um token de acesso válido está disponível.
Os usuários precisam pressionar o botão "Mostrar agenda" quando o token de acesso estiver ausente no primeiro carregamento da página ou depois que o token de acesso expirar.
<!DOCTYPE html>
<html>
<head>
<title>GAPI and GIS Example</title>
<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="gisLoad()"></script>
</head>
<body>
<h1>GAPI Client with GIS Authorization</h1>
<button id="authorizeBtn" style="visibility:hidden;">Authorize and Load Events</button>
<button id="revokeBtn" style="visibility:hidden;">Revoke Access</button>
<div id="content"></div>
<script>
const YOUR_CLIENT_ID = "YOUR_CLIENT_ID";
const YOUR_API_KEY = 'YOUR_API_KEY';
const CALENDAR_SCOPE = 'https://www.googleapis.com/auth/calendar.readonly';
let tokenClient;
let libsLoaded = 0;
function gapiLoad() {
gapi.load('client', initGapiClient);
}
async function initGapiClient() {
try {
await gapi.client.init({ apiKey: YOUR_API_KEY });
await gapi.client.load('https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest');
console.log('GAPI client initialized.');
checkAllLoaded();
} catch (err) {
handleError('GAPI initialization failed:', err);
}
}
function gisLoad() {
try {
tokenClient = google.accounts.oauth2.initTokenClient({
client_id: YOUR_CLIENT_ID,
scope: CALENDAR_SCOPE,
callback: '', // Will be set dynamically
error_callback: handleGisError,
});
console.log('GIS TokenClient initialized.');
checkAllLoaded();
} catch (err) {
handleError('GIS initialization failed:', err);
}
}
function checkAllLoaded() {
libsLoaded++;
if (libsLoaded === 2) {
document.getElementById('authorizeBtn').style.visibility = 'visible';
document.getElementById('revokeBtn').style.visibility = 'visible';
document.getElementById('authorizeBtn').onclick = makeApiCall;
document.getElementById('revokeBtn').onclick = revokeAccess;
console.log('Ready to authorize.');
}
}
function handleGisError(err) {
console.error('GIS Error:', err);
let message = 'An error occurred during authorization.';
if (err && err.type === 'popup_failed_to_open') {
message = 'Failed to open popup. Please disable popup blockers.';
} else if (err && err.type === 'popup_closed') {
message = 'Authorization popup was closed.';
}
document.getElementById('content').textContent = message;
}
function handleError(message, error) {
console.error(message, error);
document.getElementById('content').textContent = `${message} ${error.message || JSON.stringify(error)}`;
}
async function makeApiCall() {
document.getElementById('content').textContent = 'Processing...';
try {
let token = gapi.client.getToken();
if (!token || !token.access_token) {
console.log('No token, fetching one...');
await getToken();
}
console.log('Calling Calendar API...');
const response = await gapi.client.calendar.events.list({ 'calendarId': 'primary' });
displayEvents(response.result);
} catch (err) {
console.error('API call failed:', err);
const errorInfo = err.result && err.result.error;
if (errorInfo && (errorInfo.code === 401 || (errorInfo.code === 403 && errorInfo.status === "PERMISSION_DENIED"))) {
console.log('Auth error on API call, refreshing token...');
try {
await getToken({ prompt: 'consent' }); // Force refresh
const retryResponse = await gapi.client.calendar.events.list({ 'calendarId': 'primary' });
displayEvents(retryResponse.result);
} catch (refreshErr) {
handleError('Failed to refresh token or retry API call:', refreshErr);
}
} else {
handleError('Error loading events:', err.result ? err.result.error : err);
}
}
}
async function getToken(options = { prompt: '' }) {
return new Promise((resolve, reject) => {
if (!tokenClient) return reject(new Error("GIS TokenClient not initialized."));
tokenClient.callback = (tokenResponse) => {
if (tokenResponse.error) {
reject(new Error(`Token Error: ${tokenResponse.error} - ${tokenResponse.error_description}`));
} else {
console.log('Token acquired.');
resolve(tokenResponse);
}
};
tokenClient.requestAccessToken(options);
});
}
function displayEvents(result) {
const events = result.items;
if (events && events.length > 0) {
let eventList = '<h3>Upcoming Events:</h3><ul>' + events.map(event =>
`<li>${event.summary} (${event.start.dateTime || event.start.date})</li>`
).join('') + '</ul>';
document.getElementById('content').innerHTML = eventList;
} else {
document.getElementById('content').textContent = 'No upcoming events found.';
}
}
function revokeAccess() {
const token = gapi.client.getToken();
if (token && token.access_token) {
google.accounts.oauth2.revoke(token.access_token, () => {
console.log('Access revoked.');
document.getElementById('content').textContent = 'Access has been revoked.';
gapi.client.setToken(null);
});
} else {
document.getElementById('content').textContent = 'No token to revoke.';
}
}
</script>
</body>
</html>
Callback da GAPI
Este exemplo mostra como adicionar a biblioteca dos Serviços de Identificação do Google usando o
modelo de token, remover o módulo gapi.auth2 e chamar uma API usando a
biblioteca de cliente das APIs do Google para JavaScript.
As variáveis são usadas para aplicar a ordem de carregamento da biblioteca. As chamadas da GAPI são feitas no callback depois que um token de acesso válido é retornado.
Os usuários devem pressionar o botão "Mostrar agenda" quando a página é carregada pela primeira vez e novamente quando quiserem 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 do código de autorização
A UX pop-up da biblioteca do Serviço de Identidade do Google 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 do JavaScript em execução no navegador do usuário que faz o proxy da resposta para sua plataforma. Em ambos os casos, sua plataforma de back-end vai concluir o fluxo do OAuth 2.0 para receber um token de atualização e de acesso válido.
Como era antes
Apps da Web do lado do servidor
Login do Google para apps do lado do servidor em execução na plataforma de back-end usando um redirecionamento para o Google para o 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 usando redirecionamento
Usar o OAuth 2.0 para aplicativos de servidor da Web para enviar o código de autorização do navegador do usuário para sua plataforma de back-end. O consentimento do usuário é processado redirecionando o navegador do usuário para o servidor de autorização do Google.
/*
* Create form to request access token from the Google authorization 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();
}
Como será agora
UX do pop-up do GIS
Este exemplo mostra apenas a biblioteca JavaScript dos Serviços de Identificação do Google usando o modelo de código de autorização, uma caixa de diálogo pop-up para o consentimento do usuário e um gerenciador de callback para receber 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 o 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 do GIS
O modelo de código de autorização é compatível com os modos de UX de pop-up 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
Os Serviços de Identificação do Google são uma biblioteca JavaScript única 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 realizadas ao migrar para os Serviços de Identidade:
| Biblioteca JS atual | 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 siga o fluxo do código de autorização. |
Referência rápida da biblioteca
Comparação de objetos e métodos entre a antiga biblioteca de cliente JavaScript do Login do Google e a nova biblioteca dos Serviços de Identidade do Google e observações com mais informações e ações a serem realizadas durante a migração.
| Antigo | Novo | Observações |
|---|---|---|
Objeto GoogleAuth e métodos associados: |
||
GoogleAuth.attachClickHandler() |
Remover | |
GoogleAuth.currentUser.get() |
Remover | |
GoogleAuth.currentUser.listen() |
Remover | |
GoogleAuth.disconnect() |
google.accounts.oauth2.revoke |
Substitua o antigo pelo novo. A revogação também pode ser feita em https://myaccount.google.com/permissions. |
GoogleAuth.grantOfflineAccess() |
Remova, siga o fluxo do código de autorização. | |
GoogleAuth.isSignedIn.get() |
Remover | |
GoogleAuth.isSignedIn.listen() |
Remover | |
GoogleAuth.signIn() |
Remover | |
GoogleAuth.signOut() |
Remover | |
GoogleAuth.then() |
Remover | |
Objeto GoogleUser e métodos associados: |
||
GoogleUser.disconnect() |
google.accounts.id.revoke |
Substitua o antigo pelo novo. A revogação também pode ser feita em https://myaccount.google.com/permissions. |
GoogleUser.getAuthResponse() |
requestCode() ou requestAccessToken() |
Substituir o antigo pelo novo |
GoogleUser.getBasicProfile() |
Remover. Use o token de ID. Consulte Como migrar do Login do Google. | |
GoogleUser.getGrantedScopes() |
hasGrantedAnyScope() |
Substituir o antigo pelo novo |
GoogleUser.getHostedDomain() |
Remover | |
GoogleUser.getId() |
Remover | |
GoogleUser.grantOfflineAccess() |
Remova, siga o fluxo do código de autorização. | |
GoogleUser.grant() |
Remover | |
GoogleUser.hasGrantedScopes() |
hasGrantedAnyScope() |
Substituir o antigo pelo novo |
GoogleUser.isSignedIn() |
Remover | |
GoogleUser.reloadAuthResponse() |
requestAccessToken() |
Remova o antigo e chame o novo para substituir o token de acesso expirado ou revogado. |
Objeto gapi.auth2 e métodos associados: |
||
Objeto gapi.auth2.AuthorizeConfig |
TokenClientConfig ou CodeClientConfig |
Substituir o antigo pelo novo |
Objeto gapi.auth2.AuthorizeResponse |
Remover | |
Objeto gapi.auth2.AuthResponse |
Remover | |
gapi.auth2.authorize() |
requestCode() ou requestAccessToken() |
Substituir o antigo pelo novo |
gapi.auth2.ClientConfig() |
TokenClientConfig ou CodeClientConfig |
Substituir o antigo pelo novo |
gapi.auth2.getAuthInstance() |
Remover | |
gapi.auth2.init() |
initTokenClient() ou initCodeClient() |
Substituir o antigo pelo novo |
Objeto gapi.auth2.OfflineAccessOptions |
Remover | |
Objeto gapi.auth2.SignInOptions |
Remover | |
Objeto gapi.signin2 e métodos associados: |
||
gapi.signin2.render() |
Remover. O carregamento do DOM HTML do elemento g_id_signin ou a chamada 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 as chamadas diretas para endpoints do OAuth 2.0 do Google retornam um token de acesso do 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 dos Serviços de Identificação do Google
A biblioteca de Serviços de Identificação do Google 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"
}
}