OAuth 2.0 para aplicativos da Web do lado do cliente

Este documento explica como implementar a autorização do OAuth 2.0 para acessar APIs do Google de um aplicativo da Web JavaScript. O OAuth 2.0 permite que os usuários compartilhem dados específicos com um aplicativo, mantendo a privacidade dos nomes de usuários, senhas e outras informações. Por exemplo, um aplicativo pode usar o OAuth 2.0 para receber permissão dos usuários para armazenar arquivos nos drives do Google.

Esse fluxo do OAuth 2.0 é chamado de fluxo de concessão implícito. Ela foi projetada para aplicativos que acessam APIs apenas enquanto o usuário está presente no aplicativo. Esses aplicativos não podem armazenar informações confidenciais.

Nesse fluxo, seu app abre um URL do Google que usa parâmetros de consulta para identificar o app e o tipo de acesso de API exigido. É possível abrir o URL na janela atual do navegador ou em um pop-up. O usuário pode se autenticar com o Google e conceder as permissões solicitadas. Em seguida, o Google redireciona o usuário para o app. O redirecionamento inclui um token de acesso, que o app verifica e usa para fazer solicitações de API.

Pré-requisitos

Ativar as APIs do projeto

Qualquer aplicativo que chame APIs do Google precisa ativar essas APIs no API Console.

Para ativar uma API para um projeto, faça o seguinte:

  1. Open the API Library no Google API Console.
  2. If prompted, select a project, or create a new one.
  3. A API Library lista todas as APIs disponíveis agrupadas por família de produtos e popularidade. Se a API que você quer ativar não estiver visível na lista, use a pesquisa para encontrá-la ou clique em Ver tudo na família de produtos à qual ela pertence.
  4. Selecione aquela que você quer habilitar e clique no botão Ativar.
  5. If prompted, enable billing.
  6. If prompted, read and accept the API's Terms of Service.

Criar credenciais de autorização

Qualquer aplicativo que usa o OAuth 2.0 para acessar as APIs do Google precisa ter credenciais de autorização que identifiquem o aplicativo para o servidor OAuth 2.0 do Google. As etapas a seguir explicam como criar credenciais para o projeto. Seus aplicativos podem usar as credenciais para acessar as APIs que você ativou nesse projeto.

  1. Go to the Credentials page.
  2. Clique em Criar credenciais > ID do cliente OAuth.
  3. Selecione o tipo de aplicativo Aplicativo da Web.
  4. Preencha o formulário. Aplicativos que usam JavaScript para fazer solicitações de API do Google autorizadas precisam especificar origens JavaScript autorizadas. As origens identificam os domínios de que seu aplicativo pode enviar solicitações ao servidor OAuth 2.0. Essas origens precisam aderir às regras de validação do Google.

Identificar escopos de acesso

Os escopos permitem que o aplicativo solicite apenas acesso aos recursos necessários, além de permitir que os usuários controlem o nível de acesso que concedem ao aplicativo. Assim, pode haver uma relação inversa entre o número de escopos solicitados e a probabilidade de consentimento do usuário.

Antes de começar a implementar a autorização OAuth 2.0, recomendamos que você identifique os escopos que seu app precisará de permissão para acessar.

O documento Escopos da API OAuth 2.0 contém uma lista completa de escopos que você pode usar para acessar as APIs do Google.

Como conseguir tokens de acesso do OAuth 2.0

As etapas a seguir mostram como seu aplicativo interage com o servidor OAuth 2.0 do Google para receber o consentimento de um usuário para executar uma solicitação de API em nome do usuário. O aplicativo precisa ter esse consentimento para que possa executar uma solicitação da API do Google que exija autorização do usuário.

Etapa 1: configurar o objeto cliente

Se você estiver usando a biblioteca de cliente de APIs do Google para JavaScript para lidar com o fluxo do OAuth 2.0, a primeira etapa é configurar os objetos gapi.auth2 e gapi.client. Esses objetos permitem que o aplicativo receba autorização do usuário e faça solicitações de API autorizadas.

O objeto cliente identifica os escopos que seu aplicativo está solicitando permissão para acessar. Esses valores informam a tela de consentimento que o Google exibe ao usuário.

Biblioteca de cliente JS

A biblioteca de cliente JavaScript simplifica vários aspectos do processo de autorização:

  1. Ele cria o URL de redirecionamento para o servidor de autorização do Google e fornece um método para direcionar o usuário para esse URL.
  2. Ele trata o redirecionamento desse servidor de volta para seu aplicativo.
  3. Valida o token de acesso retornado pelo servidor de autorização.
  4. Ele armazena o token de acesso que o servidor de autorização envia ao aplicativo e o recupera quando o aplicativo faz chamadas de API autorizadas posteriormente.

O snippet de código abaixo é um trecho do exemplo completo mostrado mais adiante neste documento. Esse código inicializa o objeto gapi.client, que o aplicativo usaria posteriormente para fazer chamadas de API. Quando esse objeto é criado, o objeto gapi.auth2, que seu aplicativo usa para verificar e monitorar o status de autorização do usuário, também é inicializado.

A chamada para gapi.client.init especifica os seguintes campos:

  • Os valores apiKey e clientId especificam as credenciais de autorização do seu aplicativo. Conforme discutido na seção Como criar credenciais de autorização, esses valores podem ser obtidos na API Console. O clientId será necessário se o aplicativo fizer solicitações de API autorizadas. Aplicativos que fazem apenas solicitações não autorizadas só podem especificar uma chave de API.
  • O campo scope especifica uma lista delimitada por espaço de escopos de acesso que correspondem aos recursos que seu aplicativo pode acessar em nome do usuário. Esses valores informam a tela de consentimento que o Google exibe ao usuário.

    Recomendamos que seu aplicativo solicite acesso a escopos de autorização sempre que possível. Ao solicitar acesso aos dados do usuário em contexto, por meio da autorização incremental, você ajuda os usuários a entenderem mais facilmente por que o aplicativo precisa do acesso que ele está solicitando.

  • O campo discoveryDocs identifica uma lista de documentos de descoberta da API usados pelo aplicativo. Um documento de descoberta descreve a superfície de uma API, incluindo os esquemas de recursos. A biblioteca cliente de JavaScript usa essas informações para gerar métodos que os aplicativos podem usar. Neste exemplo, o código recupera o documento de descoberta da versão 3 da API Google Drive.

Depois que a chamada gapi.client.init for concluída, o código definirá a variável GoogleAuth para identificar o objeto do Google Auth. Por fim, o código define um listener que chama uma função quando o status de login do usuário muda. Essa função não é definida no snippet.

var GoogleAuth; // Google Auth object.
function initClient() {
  gapi.client.init({
      'apiKey': 'YOUR_API_KEY',
      'clientId': 'YOUR_CLIENT_ID',
      'scope': 'https://www.googleapis.com/auth/drive.metadata.readonly',
      'discoveryDocs': ['https://www.googleapis.com/discovery/v1/apis/drive/v3/rest']
  }).then(function () {
      GoogleAuth = gapi.auth2.getAuthInstance();

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

Endpoints do OAuth 2.0

Se você estiver acessando diretamente os endpoints do OAuth 2.0, avance para a próxima etapa.

Etapa 2: redirecionar para o servidor OAuth 2.0 do Google

Para solicitar permissão de acesso aos dados de um usuário, redirecione-o para o servidor OAuth 2.0 do Google.

Biblioteca de cliente JS

Chame o método GoogleAuth.signIn() para direcionar o usuário ao servidor de autorização do Google.

GoogleAuth.signIn();

Na prática, seu aplicativo pode definir um valor booleano para determinar se você quer chamar o método signIn() antes de tentar fazer uma chamada de API.

O snippet de código abaixo demonstra como iniciar o fluxo de autorização do usuário. Observe o seguinte sobre o snippet:

  • O objeto GoogleAuth mencionado no código é igual à variável global definida no snippet de código na etapa 1.

  • A função updateSigninStatus é um listener que detecta alterações no status de autorização do usuário. O papel dele como listener também foi definido no snippet de código na etapa 1:
    GoogleAuth.isSignedIn.listen(updateSigninStatus);
  • O snippet define duas variáveis globais adicionais:

    • isAuthorized é uma variável booleana que indica se o usuário já fez login. Esse valor pode ser definido quando o app é carregado e atualizado quando o usuário faz login ou sai dele.

      Nesse snippet, a função sendAuthorizedApiRequest verifica o valor da variável para determinar se o app deve tentar uma solicitação de API que exija autorização ou solicitar que o usuário autorize o app.

    • currentApiRequest é um objeto que armazena detalhes sobre a última solicitação de API que o usuário tentou. O valor do objeto é definido quando o app chama a função sendAuthorizedApiRequest.

      Se o usuário tiver autorizado o app, a solicitação vai ser executada imediatamente. Caso contrário, a função redireciona o usuário para fazer login. Depois que o usuário faz login, a função updateSignInStatus chama sendAuthorizedApiRequest, transmitindo a mesma solicitação que foi feita antes do início do fluxo de autorização.

var isAuthorized;
var currentApiRequest;

/**
 * Store the request details. Then check to determine whether the user
 * has authorized the application.
 *   - If the user has granted access, make the API request.
 *   - If the user has not granted access, initiate the sign-in flow.
 */
function sendAuthorizedApiRequest(requestDetails) {
  currentApiRequest = requestDetails;
  if (isAuthorized) {
    // Make API request
    // gapi.client.request(requestDetails)

    // Reset currentApiRequest variable.
    currentApiRequest = {};
  } else {
    GoogleAuth.signIn();
  }
}

/**
 * Listener called when user completes auth flow. If the currentApiRequest
 * variable is set, then the user was prompted to authorize the application
 * before the request executed. In that case, proceed with that API request.
 */
function updateSigninStatus(isSignedIn) {
  if (isSignedIn) {
    isAuthorized = true;
    if (currentApiRequest) {
      sendAuthorizedApiRequest(currentApiRequest);
    }
  } else {
    isAuthorized = false;
  }
}

Endpoints do OAuth 2.0

Gere um URL para solicitar acesso ao endpoint do OAuth 2.0 do Google em https://accounts.google.com/o/oauth2/v2/auth. Esse endpoint pode ser acessado por HTTPS. Conexões HTTP simples são recusadas.

O servidor de autorização do Google é compatível com os seguintes parâmetros de string de consulta para aplicativos do servidor da Web:

Parâmetros
client_id Obrigatório

O ID do cliente do aplicativo. Esse valor pode ser encontrado no API Console Credentials page.

redirect_uri Obrigatório

Determina para onde o servidor de API redireciona o usuário depois que ele conclui o fluxo de autorização. O valor precisa corresponder exatamente a um dos URIs de redirecionamento autorizados para o cliente OAuth 2.0, que você configurou no Credentials pagedo API Console. Se esse valor não corresponder a um URI de redirecionamento autorizado para o client_id fornecido, você vai receber um erro redirect_uri_mismatch.

O esquema, o caso e a barra à direita ("/") ou http precisam corresponder.

response_type Obrigatório

Os aplicativos JavaScript precisam definir o valor do parâmetro como token. Esse valor instrui o servidor de autorização do Google a retornar o token de acesso como um par name=value no identificador de fragmento do URI (#) para o qual o usuário será redirecionado depois de concluir o processo de autorização.

scope Obrigatório

Uma lista de escopos delimitada por espaços que identificam os recursos que seu aplicativo pode acessar em nome do usuário. Esses valores informam a tela de consentimento que o Google exibe ao usuário.

Os escopos permitem que o aplicativo solicite apenas acesso aos recursos necessários, além de permitir que os usuários controlem o nível de acesso que concedem ao aplicativo. Portanto, há uma relação inversa entre o número de escopos solicitados e a probabilidade de receber o consentimento do usuário.

Recomendamos que seu aplicativo solicite acesso a escopos de autorização sempre que possível. Ao solicitar acesso aos dados do usuário no contexto, usando a autorização incremental, você ajuda os usuários a entender mais facilmente por que seu app precisa do acesso que ele está solicitando.

state Recomendável

Especifica qualquer valor de string que seu aplicativo usa para manter o estado entre a solicitação de autorização e a resposta do servidor de autorização. O servidor retorna o valor exato que você envia como um par name=value no identificador do fragmento de URL (#) do redirect_uri depois que o usuário consente ou nega a solicitação de acesso do aplicativo.

Esse parâmetro pode ser usado para várias finalidades, como direcionar o usuário ao recurso correto no aplicativo, enviar valores de uso único e atenuar a falsificação de solicitações entre sites. Como o redirect_uri pode ser suposto, o uso de um valor state pode aumentar a garantia de que uma conexão de entrada é o resultado de uma solicitação de autenticação. Se você gerar uma string aleatória ou codificar o hash de um cookie ou outro valor que captura o estado do cliente, será possível validar a resposta para garantir também que a solicitação e a resposta sejam originadas no mesmo navegador, fornecendo proteção contra ataques, como falsificação de solicitação entre sites. Consulte a documentação do OpenID Connect para ver um exemplo de como criar e confirmar um token state.

include_granted_scopes Opcional

Permite que os aplicativos usem autorização incremental para solicitar acesso a mais escopos no contexto. Se você definir o valor desse parâmetro como true e a solicitação de autorização for concedida, o novo token de acesso também cobrirá todos os escopos aos quais o usuário concedeu o acesso do aplicativo anteriormente. Consulte a seção autorização incremental para ver exemplos.

login_hint Opcional

Se o aplicativo souber qual usuário está tentando autenticar, ele poderá usar esse parâmetro para fornecer uma dica para o servidor de autenticação do Google. O servidor usa a dica para simplificar o fluxo de login preenchendo o campo de e-mail no formulário de login ou selecionando a sessão de login múltiplo adequada.

Defina o valor do parâmetro como um endereço de e-mail ou identificador sub, que é equivalente ao ID do Google do usuário.

prompt Opcional

Uma lista de solicitações delimitadas por espaços e com diferenciação entre maiúsculas e minúsculas para apresentar ao usuário. Se você não especificar esse parâmetro, o usuário só receberá uma solicitação na primeira vez que o projeto solicitar acesso. Consulte Solicitar nova autorização para mais informações.

Os valores possíveis são:

none Não exiba telas de autenticação ou consentimento. Não pode ser especificado com outros valores.
consent Solicite o consentimento do usuário.
select_account Solicitar que o usuário selecione uma conta

Exemplo de redirecionamento para o servidor de autorização do Google

Veja abaixo um exemplo de URL, com quebras de linha e espaços para facilitar a leitura.

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly&
 include_granted_scopes=true&
 response_type=token&
 state=state_parameter_passthrough_value&
 redirect_uri=https%3A//oauth2.example.com/code&
 client_id=client_id

Depois de criar o URL da solicitação, redirecione o usuário para ele.

Exemplo de código JavaScript

O snippet de JavaScript a seguir mostra como iniciar o fluxo de autorização em JavaScript sem usar a biblioteca de cliente de APIs do Google para JavaScript. Como esse endpoint do OAuth 2.0 não aceita compartilhamento de recursos entre origens (CORS), o snippet cria um formulário que abre a solicitação para esse endpoint.

/*
 * 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_REDIRECT_URI',
                '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();
}

Etapa 3: o Google solicita o consentimento do usuário

Nesta etapa, o usuário decide se quer conceder o acesso solicitado ao app. Nesta etapa, o Google exibe uma janela de consentimento que mostra o nome do seu aplicativo e os serviços da API do Google que estão solicitando permissão de acesso com as credenciais de autorização do usuário, além de um resumo dos escopos de acesso a serem concedidos. O usuário pode consentir em conceder acesso a um ou mais escopos solicitados pelo aplicativo ou recusar a solicitação.

O aplicativo não precisa fazer nada enquanto aguarda a resposta do servidor OAuth 2.0 do Google, indicando se algum acesso foi concedido. Essa resposta é explicada na etapa a seguir.

Erros

As solicitações para o endpoint de autorização do OAuth 2.0 do Google podem exibir mensagens de erro para o usuário, em vez dos fluxos de autenticação e autorização esperados. Veja abaixo os códigos de erro comuns e as sugestões de resolução.

admin_policy_enforced

A Conta do Google não autoriza um ou mais escopos solicitados devido às políticas do administrador do Google Workspace. Consulte o artigo de ajuda do administrador do Google Workspace Controlar quais apps internos e de terceiros acessam os dados do Google Workspace para mais informações sobre como um administrador pode restringir o acesso a todos os escopos ou aos escopos confidenciais e restritos até que o acesso seja explicitamente concedido ao ID do cliente OAuth.

disallowed_useragent

O endpoint de autorização é exibido em um user agent incorporado não permitido pelas políticas do OAuth 2.0 do Google.

Android

Os desenvolvedores Android podem encontrar essa mensagem de erro ao abrir solicitações de autorização em android.webkit.WebView. Em vez disso, os desenvolvedores precisam usar bibliotecas do Android, como o Login do Google para Android ou o AppAuth para Android da OpenID Foundation.

Os desenvolvedores da Web podem encontrar esse erro quando um app Android abre um link da Web geral em um user agent incorporado e um usuário navega para o endpoint de autorização do OAuth 2.0 do Google no seu site. Os desenvolvedores precisam permitir que links gerais sejam abertos no gerenciador de links padrão do sistema operacional, que inclui gerenciadores de Links do app Android ou o app de navegação padrão. A biblioteca Guias personalizadas do Android também é uma opção compatível.

iOS

Os desenvolvedores do iOS e do macOS podem encontrar esse erro ao abrir solicitações de autorização em WKWebView. Em vez disso, os desenvolvedores precisam usar bibliotecas do iOS, como o Login do Google para iOS ou o AppAuth para iOS da OpenID Foundation.

Os desenvolvedores da Web podem encontrar esse erro quando um app iOS ou macOS abre um link da Web geral em um user agent incorporado e um usuário navega para o endpoint de autorização do OAuth 2.0 do Google no seu site. Os desenvolvedores precisam permitir que links gerais sejam abertos no gerenciador de links padrão do sistema operacional, que inclui gerenciadores de links universais ou o app de navegação padrão. A biblioteca SFSafariViewController também é uma opção compatível.

org_internal

O ID do cliente OAuth na solicitação faz parte de um projeto que limita o acesso a Contas do Google em uma organização específica do Google Cloud. Para mais informações sobre essa opção de configuração, consulte a seção Tipo de usuário no artigo de ajuda sobre como configurar a tela de permissão OAuth.

invalid_client

A origem da solicitação foi autorizada para este cliente. Consulte origin_mismatch.

invalid_grant

Ao usar a autorização incremental, o token pode ter expirado ou ser invalidado. Autentique o usuário novamente e peça o consentimento dele para receber novos tokens. Se você continuar a ver esse erro, verifique se o aplicativo foi configurado corretamente e se está usando os tokens e parâmetros corretos na solicitação. Caso contrário, a conta de usuário pode ter sido excluída ou desativada.

origin_mismatch

O esquema, o domínio e/ou a porta do JavaScript que originou a solicitação de autorização podem não corresponder a um URI de origem JavaScript autorizado registrado para o ID do cliente OAuth. Revise as origens do JavaScript autorizadas no Google API Console Credentials page.

redirect_uri_mismatch

O redirect_uri transmitido na solicitação de autorização não corresponde a um URI de redirecionamento autorizado para o ID do cliente OAuth. Revise os URIs de redirecionamento autorizados em Google API Console Credentials page.

O esquema, o domínio e/ou a porta do JavaScript que originou a solicitação de autorização podem não corresponder a um URI de origem JavaScript autorizado registrado para o ID do cliente OAuth. Revise as origens do JavaScript autorizadas no Google API Console Credentials page.

O parâmetro redirect_uri pode se referir ao fluxo OAuth fora de banda (OOB, na sigla em inglês) que foi descontinuado e não tem mais suporte. Consulte o guia de migração para atualizar sua integração.

Etapa 4: lidar com a resposta do servidor OAuth 2.0

Biblioteca de cliente JS

A biblioteca de cliente JavaScript processa a resposta do servidor de autorização do Google. Se você definir um listener para monitorar alterações no estado de login do usuário atual, essa função será chamada quando o usuário conceder o acesso solicitado ao aplicativo.

Endpoints do OAuth 2.0

O servidor OAuth 2.0 envia uma resposta ao redirect_uri especificado na solicitação do token de acesso.

Se o usuário aprovar a solicitação, a resposta conterá um token de acesso. Se o usuário não aprovar a solicitação, a resposta conterá uma mensagem de erro. O token de acesso ou a mensagem de erro é retornado no fragmento hash do URI de redirecionamento, como mostrado abaixo:

  • Uma resposta do token de acesso:

    https://oauth2.example.com/callback#access_token=4/P7q7W91&token_type=Bearer&expires_in=3600

    Além do parâmetro access_token, a string de fragmento também contém o parâmetro token_type, que é sempre definido como Bearer, e o parâmetro expires_in, que especifica o ciclo de vida do token em segundos. Se o parâmetro state tiver sido especificado na solicitação de token de acesso, o valor dele também será incluído na resposta.

  • Uma resposta de erro:
    https://oauth2.example.com/callback#error=access_denied

Exemplo de resposta do servidor OAuth 2.0

Para testar esse fluxo, clique no URL de amostra a seguir, que solicita acesso somente leitura para visualizar metadados de arquivos no seu Google Drive:

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly&
 include_granted_scopes=true&
 response_type=token&
 state=state_parameter_passthrough_value&
 redirect_uri=https%3A//oauth2.example.com/code&
 client_id=client_id

Depois de concluir o fluxo do OAuth 2.0, você será redirecionado para http://localhost/oauth2callback. Esse URL produzirá um erro 404 NOT FOUND, a menos que sua máquina local exiba um arquivo nesse endereço. A próxima etapa oferece mais detalhes sobre as informações retornadas no URI quando o usuário é redirecionado ao seu aplicativo.

Como chamar APIs do Google

Biblioteca de cliente JS

Depois que o aplicativo receber um token de acesso, use a biblioteca de cliente JavaScript para fazer solicitações de API em nome do usuário. A biblioteca de cliente gerencia o token de acesso para você, e não é preciso fazer nada especial para enviá-lo na solicitação.

A biblioteca de cliente oferece duas maneiras de chamar métodos de API. Se você carregou um documento de descoberta, a API definirá funções específicas do método. Você também pode usar a função gapi.client.request para chamar um método de API. Os dois snippets a seguir demonstram essas opções para o método about.get da API Drive.

// Example 1: Use method-specific function
var request = gapi.client.drive.about.get({'fields': 'user'});

// Execute the API request.
request.execute(function(response) {
  console.log(response);
});


// Example 2: Use gapi.client.request(args) function
var request = gapi.client.request({
  'method': 'GET',
  'path': '/drive/v3/about',
  'params': {'fields': 'user'}
});
// Execute the API request.
request.execute(function(response) {
  console.log(response);
});

Endpoints do OAuth 2.0

Depois que seu aplicativo recebe um token de acesso, é possível usá-lo para fazer chamadas para uma API do Google em nome de uma determinada conta de usuário se os escopos de acesso exigidos pela API tiverem sido concedidos. Para fazer isso, inclua o token de acesso em uma solicitação para a API incluindo um parâmetro de consulta access_token ou um valor Bearer de cabeçalho HTTP Authorization. Quando possível, o cabeçalho HTTP é preferível, porque as strings de consulta tendem a ser visíveis nos registros do servidor. Na maioria dos casos, você pode usar uma biblioteca de cliente para configurar as chamadas para APIs do Google, por exemplo, ao chamar a API Drive Files.

É possível testar todas as APIs do Google e ver os escopos delas no OAuth 2.0 Playground.

Exemplos de HTTP GET

Uma chamada para o endpoint drive.files (a API Drive Files) usando o cabeçalho HTTP Authorization: Bearer pode ser semelhante a esta. Você precisa especificar seu próprio token de acesso:

GET /drive/v2/files HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer access_token

Esta é uma chamada para a mesma API para o usuário autenticado usando o parâmetro de string de consulta access_token:

GET https://www.googleapis.com/drive/v2/files?access_token=access_token

Exemplos de curl

É possível testar esses comandos com o aplicativo de linha de comando curl. Veja um exemplo que usa a opção de cabeçalho HTTP (preferencial):

curl -H "Authorization: Bearer access_token" https://www.googleapis.com/drive/v2/files

Ou, alternativamente, a opção de parâmetro da string de consulta:

curl https://www.googleapis.com/drive/v2/files?access_token=access_token

Exemplo de código JavaScript

O snippet de código abaixo demonstra como usar o compartilhamento de recursos entre origens (CORS, na sigla em inglês) para enviar uma solicitação a uma API do Google. Este exemplo não usa a biblioteca cliente de APIs do Google para JavaScript. No entanto, mesmo que você não esteja usando a biblioteca de cliente, o guia de suporte ao CORS na documentação dessa biblioteca provavelmente ajudará a entender melhor essas solicitações.

Neste snippet de código, a variável access_token representa o token que você recebeu para fazer solicitações de API em nome do usuário autorizado. O exemplo completo demonstra como armazenar esse token no armazenamento local do navegador e recuperá-lo ao fazer uma solicitação de API.

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) {
  console.log(xhr.response);
};
xhr.send(null);

Exemplo completo

Biblioteca de cliente JS

Exemplo de código de demonstração

Esta seção contém uma demonstração funcional do exemplo de código a seguir para demonstrar o comportamento do código em um app real. Depois de autorizar o app, ele será listado entre os apps conectados à sua Conta do Google. O aplicativo é chamado de Demonstração do OAuth 2.0 para documentos da API do Google. Da mesma forma, se você revogar o acesso e atualizar a página, o app não será mais listado.

Esse app solicita acesso ao escopo https://www.googleapis.com/auth/drive.metadata.readonly. O acesso é solicitado apenas a demonstrar como iniciar o fluxo do OAuth 2.0 em um aplicativo JavaScript. Este aplicativo não faz solicitações de API.

Exemplo de código JavaScript

Como mostrado acima, essa amostra de código é destinada a uma página (um app) que carrega a biblioteca de cliente das APIs do Google para JavaScript e inicia o fluxo do OAuth 2.0. A página exibe uma destas opções:

  • Um botão que permite que o usuário faça login no app. Se o usuário não tiver autorizado o app, o app iniciará o fluxo do OAuth 2.0.
  • Dois botões que permitem que o usuário saia do app ou revogue o acesso concedido anteriormente. Se sair do app, você não revogou o acesso concedido ao app. Você vai precisar fazer login novamente para que o app possa fazer outras solicitações autorizadas em seu nome, mas não será necessário conceder acesso novamente na próxima vez que usar o app. No entanto, se você revogar o acesso, será necessário conceder o acesso novamente.

Também é possível revogar o acesso ao app na página Permissões da Conta do Google. O app está listado como OAuth 2.0 Demo for Google API Docs.

<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>

Endpoints do OAuth 2.0

Este exemplo de código demonstra como concluir o fluxo do OAuth 2.0 em JavaScript sem usar a biblioteca de cliente das APIs do Google para JavaScript. O código é de uma página HTML que exibe um botão para testar uma solicitação de API. Ao clicar no botão, o código verifica se a página armazenou um token de acesso à API no armazenamento local do navegador. Nesse caso, ele executa a solicitação de API. Caso contrário, ele iniciará o fluxo do OAuth 2.0.

Para o fluxo do OAuth 2.0, a página segue estas etapas:

  1. Ele direciona o usuário para o servidor OAuth 2.0 do Google, que solicita acesso ao escopo https://www.googleapis.com/auth/drive.metadata.readonly.
  2. Depois de conceder (ou negar) acesso a um ou mais escopos solicitados, o usuário é redirecionado para a página original, que analisa o token de acesso na string do identificador de fragmento.
  3. A página usa o token de acesso para fazer a solicitação de API de amostra.

    A solicitação da API chama o método about.get da API Drive para recuperar informações sobre a conta do Google Drive do usuário autorizado.

  4. Se a solicitação for executada com sucesso, a resposta da API será registrada no console de depuração do navegador.

É possível revogar o acesso ao app na página Permissões da Conta do Google. O app será listado como OAuth 2.0 Demo for Google API Docs.

Para executar esse código localmente, é necessário definir valores para as variáveis YOUR_CLIENT_ID e YOUR_REDIRECT_URI que correspondem às suas credenciais de autorização. A variável YOUR_REDIRECT_URI precisa ser definida como o mesmo URL em que a página está sendo exibida. O valor precisa corresponder exatamente a um dos URIs de redirecionamento autorizados para o cliente OAuth 2.0, que você configurou no API Console Credentials page. Se esse valor não corresponder a um URI autorizado, você vai receber um erro redirect_uri_mismatch. Seu projeto também precisa ter ativado a API apropriada para essa solicitação.

<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>

Regras de validação da origem JavaScript

O Google aplica as regras de validação abaixo às origens JavaScript para ajudar os desenvolvedores a proteger os aplicativos. As origens do JavaScript precisam seguir estas regras. Consulte a seção 3 do RFC 3986 para ver a definição de domínio, host e esquema, mencionada abaixo.

Regras de validação
Esquema

As origens do JavaScript precisam usar o esquema HTTPS, não HTTP simples. Os URIs do host local (incluindo URIs de endereço IP do host local) estão isentos dessa regra.

Host

Os hosts não podem ser endereços IP brutos. Os endereços IP do host local estão isentos dessa regra.

Domínio
  • Os TLDs do host (domínios de nível superior) precisam pertencer à lista pública de sufixos.
  • Os domínios de host não podem ser “googleusercontent.com”.
  • As origens do JavaScript não podem conter domínios de encurtador de URL (por exemplo, goo.gl), a menos que o app seja proprietário do domínio.
  • Informações do usuário

    As origens do JavaScript não podem conter o subcomponente userinfo.

    Caminho

    Origens do JavaScript não podem conter o componente de caminho.

    Consulta

    As origens do JavaScript não podem conter o componente de consulta.

    Fragmentos

    As origens do JavaScript não podem conter o componente do fragmento.

    Personagens As origens do JavaScript não podem conter determinados caracteres, incluindo os seguintes:
    • Caracteres curinga ('*')
    • Caracteres ASCII não imprimíveis
    • Codificações de porcentagem inválidas (qualquer codificação de porcentagem que não segue a forma de codificação de URL de um sinal de porcentagem seguida por dois dígitos hexadecimais)
    • Caracteres nulos (um caractere NULL codificado, por exemplo, %00, %C0%80)

    Autorização incremental

    No protocolo OAuth 2.0, seu app solicita autorização para acessar recursos, que são identificados por escopos. Considerar uma prática recomendada de experiência do usuário solicitar autorização de recursos sempre que você precisar. Para ativar essa prática, o servidor de autorização do Google oferece suporte à autorização incremental. Esse recurso permite solicitar escopos conforme necessário e, se o usuário conceder permissão para o novo escopo, retorna um código de autorização que pode ser trocado por um token contendo todos os escopos concedidos ao usuário no projeto.

    Por exemplo, um app que permite que as pessoas criem mixes de música e criem mixes pode precisar de poucos recursos no momento do login, talvez nada mais do que o nome da pessoa que faz login. No entanto, para salvar um mix concluído, é preciso ter acesso ao Google Drive. A maioria das pessoas acharia natural se só tivessem acesso ao Google Drive no momento em que o app realmente precisasse disso.

    Nesse caso, no momento do login, o app pode solicitar os escopos openid e profile para fazer login básico e, depois, solicitar o escopo https://www.googleapis.com/auth/drive.file no momento da primeira solicitação para salvar uma combinação.

    As regras a seguir se aplicam a um token de acesso obtido com uma autorização incremental:

    • O token pode ser usado para acessar recursos correspondentes a qualquer um dos escopos incorporados na nova autorização combinada.
    • Quando você usa o token de atualização para a autorização combinada a fim de conseguir um token de acesso, esse token representa a autorização combinada e pode ser usado para qualquer um dos valores scope incluídos na resposta.
    • A autorização combinada inclui todos os escopos que o usuário concedeu ao projeto da API, mesmo que os benefícios tenham sido solicitados de clientes diferentes. Por exemplo, se um usuário concedeu acesso a um escopo usando o cliente de computador de um aplicativo e, em seguida, concedeu outro escopo para o mesmo aplicativo usando um cliente de dispositivos móveis, a autorização combinada incluirá os dois escopos.
    • Se você revogar um token que representa uma autorização combinada, o acesso a todos os escopos da autorização em nome do usuário associado será revogado simultaneamente.

    As amostras de código abaixo mostram como adicionar escopos a um token de acesso existente. Essa abordagem permite que o app não precise gerenciar vários tokens de acesso.

    Biblioteca de cliente JS

    Para adicionar escopos a um token de acesso atual, chame o método GoogleUser.grant(options). O objeto options identifica os escopos adicionais a que você quer conceder acesso.

    // Space-separated list of additional scope(s) you are requesting access to.
    // This code adds read-only access to the user's calendars via the Calendar API.
    var NEW_SCOPES = 'https://www.googleapis.com/auth/calendar.readonly';
    
    // Retrieve the GoogleUser object for the current user.
    var GoogleUser = GoogleAuth.currentUser.get();
    GoogleUser.grant({'scope': NEW_SCOPES});

    Endpoints do OAuth 2.0

    Para adicionar escopos a um token de acesso atual, inclua o parâmetro include_granted_scopes na solicitação ao servidor OAuth 2.0 do Google.

    O snippet de código a seguir demonstra como fazer isso. O snippet pressupõe que você tenha armazenado os escopos dos tokens de acesso no armazenamento local do navegador. O código de exemplo completo armazena uma lista de escopos para os quais o token de acesso é válido ao definir a propriedade oauth2-test-params.scope no armazenamento local do navegador.

    O snippet compara os escopos do token de acesso válidos e aqueles que você quer usar em uma consulta específica. Se o token de acesso não abrange esse escopo, o fluxo do OAuth 2.0 é iniciado. Aqui, a função oauth2SignIn é a mesma que foi fornecida na etapa 2, fornecida mais tarde no exemplo completo.

    var SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly';
    var params = JSON.parse(localStorage.getItem('oauth2-test-params'));
    
    var current_scope_granted = false;
    if (params.hasOwnProperty('scope')) {
      var scopes = params['scope'].split(' ');
      for (var s = 0; s < scopes.length; s++) {
        if (SCOPE == scopes[s]) {
          current_scope_granted = true;
        }
      }
    }
    
    if (!current_scope_granted) {
      oauth2SignIn(); // This function is defined elsewhere in this document.
    } else {
      // Since you already have access, you can proceed with the API request.
    }

    Como revogar um token

    Em alguns casos, o usuário pode querer revogar o acesso dado a um aplicativo. Um usuário pode revogar o acesso acessando as Configurações da conta. Consulte a seção Remover o acesso do site ou app dos sites e apps de terceiros com acesso à sua conta para mais informações.

    Também é possível que um aplicativo revogue de forma programática o acesso concedido a ele. A revogação programática é importante nos casos em que um usuário cancela a inscrição, remove um aplicativo ou os recursos da API exigidos por um aplicativo mudaram significativamente. Em outras palavras, parte do processo de remoção pode incluir uma solicitação de API para garantir que as permissões concedidas anteriormente ao aplicativo sejam removidas.

    Biblioteca de cliente JS

    Para revogar programaticamente um token, chame GoogleAuth.disconnect():

    GoogleAuth.disconnect();

    Endpoints do OAuth 2.0

    Para revogar programaticamente um token, o aplicativo faz uma solicitação para https://oauth2.googleapis.com/revoke e inclui o token como um parâmetro:

    curl -d -X -POST --header "Content-type:application/x-www-form-urlencoded" \
            https://oauth2.googleapis.com/revoke?token={token}

    O token pode ser de acesso ou de atualização. Se for um token de acesso e tiver um token de atualização correspondente, o token de atualização também será revogado.

    Se a revogação for processada, o código de status HTTP da resposta será 200. Para condições de erro, um código de status HTTP 400 é retornado junto com um código de erro.

    O snippet de JavaScript a seguir mostra como revogar um token em JavaScript sem usar a biblioteca de cliente de APIs do Google para JavaScript. Como o endpoint do OAuth 2.0 do Google para revogar tokens não é compatível com o compartilhamento de recursos entre origens (CORS), o código cria um formulário e o envia para o endpoint em vez de usar o método XMLHttpRequest() para postar a solicitação.

    function revokeAccess(accessToken) {
      // Google's OAuth 2.0 endpoint for revoking access tokens.
      var revokeTokenEndpoint = 'https://oauth2.googleapis.com/revoke';
    
      // Create <form> element to use to POST data to the OAuth 2.0 endpoint.
      var form = document.createElement('form');
      form.setAttribute('method', 'post');
      form.setAttribute('action', revokeTokenEndpoint);
    
      // Add access token to the form so it is set as value of 'token' parameter.
      // This corresponds to the sample curl request, where the URL is:
      //      https://oauth2.googleapis.com/revoke?token={token}
      var tokenField = document.createElement('input');
      tokenField.setAttribute('type', 'hidden');
      tokenField.setAttribute('name', 'token');
      tokenField.setAttribute('value', accessToken);
      form.appendChild(tokenField);
    
      // Add form to page and submit it to actually revoke the token.
      document.body.appendChild(form);
      form.submit();
    }