Como usar o OAuth 2.0 para aplicativos de servidor da Web

Este documento explica como os aplicativos de servidor da Web usam as bibliotecas de cliente das APIs do Google ou o Endpoints do OAuth 2.0 para implementar a autorização do OAuth 2.0 para acessar nas APIs do Google.

O OAuth 2.0 permite que os usuários compartilhem dados específicos com um aplicativo, mantendo nomes de usuário, senhas e outras informações privadas. Por exemplo, um aplicativo pode usar OAuth 2.0 para obter permissão de armazenar arquivos no Google Drive.

Este fluxo de OAuth 2.0 é especificamente para a autorização de usuários. Ele é projetado para aplicativos que pode armazenar informações confidenciais e manter o estado. Um servidor da Web devidamente autorizado pode acessar uma API enquanto o usuário interage com o aplicativo ou após o usuário saiu do aplicativo.

Frequentemente, os aplicativos de servidor da Web também usam contas de serviço para autorizar solicitações de API, especialmente ao chamar APIs do Cloud para acessar são dados baseados em projeto, em vez de dados específicos do usuário. Os aplicativos de servidor da Web podem usar serviços contas em conjunto com a autorização do usuário.

Bibliotecas de cliente

Os exemplos específicos de linguagem nesta página usam Bibliotecas de cliente das APIs do Google para implementar Autorização do OAuth 2.0. Para executar os exemplos de código, primeiro instale a para sua linguagem.

Quando você usa uma biblioteca de cliente das APIs do Google para lidar com o fluxo do OAuth 2.0 do seu aplicativo, o cliente executa muitas ações que o aplicativo precisaria processar por conta própria. Para exemplo, ele determina quando o aplicativo pode usar ou atualizar tokens de acesso armazenados, bem como quando o aplicativo precisa solicitar o consentimento novamente. A biblioteca-cliente também gera URLs e ajuda a implementar gerenciadores de redirecionamento que trocam códigos de autorização por tokens de acesso.

As bibliotecas de cliente da API do Google para aplicativos do lado do servidor estão disponíveis para as seguintes linguagens:

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. API Library lista todas as APIs disponíveis agrupadas por produto família e popularidade. Se a API que você quer ativar não aparecer na lista, use a pesquisa para encontrá-la ou clique em Ver tudo na família de produtos a que 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 use o OAuth 2.0 para acessar as APIs do Google deve ter credenciais de autorização que identificam o aplicativo para o servidor OAuth 2.0 do Google. As etapas a seguir explicam como criar credenciais para seu 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 e clique em Criar. Aplicativos que usam linguagens e frameworks como PHP, Java, Python, Ruby e .NET, devem especificar URIs de redirecionamento autorizados. O URIs de redirecionamento são os pontos de extremidade para os quais o servidor OAuth 2.0 pode enviar respostas. Esses de destino precisam aderir às regras de validação do Google.

    Para testes, você pode especificar URIs que se referem à máquina local, como http://localhost:8080: Com isso em mente, observe que todos neste documento usam http://localhost:8080 como o URI de redirecionamento.

    Recomendamos projetar os endpoints de autenticação do app para que para que seu aplicativo não exponha códigos de autorização para outros recursos na página.

Depois de criar suas credenciais, faça o download do arquivo client_secret.json na API ConsoleArmazene com segurança o arquivo em um local que só que o aplicativo pode acessar.

Identificar escopos de acesso

Os escopos permitem que seu aplicativo solicite acesso apenas aos recursos necessários permitindo que os usuários controlem a quantidade de acesso que eles concedem ao aplicativo. Portanto, há pode ser uma relação inversa entre o número de escopos solicitados e a probabilidade de obter o consentimento do usuário.

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

Também recomendamos que seu aplicativo solicite acesso a escopos de autorização por meio de uma processo de autorização incremental, em que o aplicativo solicita acesso aos dados do usuário no contexto. Essa prática recomendada ajuda os usuários a entender mais facilmente por que seu aplicativo precisa do acesso que está solicitando.

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

Requisitos específicos do idioma

Para executar qualquer um dos exemplos de código deste documento, você precisa ter uma Conta do Google, acesso ao Internet e um navegador da Web. Se você estiver usando uma das bibliotecas de cliente da API, consulte também as abaixo dos requisitos específicos do idioma.

PHP

Para executar os exemplos de código PHP neste documento, você precisará de:

  • PHP 5.6 ou mais recente com a interface de linha de comando (CLI) e a extensão JSON instaladas.
  • A ferramenta de gerenciamento de dependências Composer.
  • Biblioteca de cliente de APIs do Google para PHP:

    composer require google/apiclient:^2.10

Python

Para executar os exemplos de código Python neste documento, você precisará de:

  • Python 2.6 ou superior
  • a ferramenta de gerenciamento de pacotes PIP;
  • A biblioteca cliente de APIs do Google para Python:
    pip install --upgrade google-api-python-client
  • Os métodos google-auth, google-auth-oauthlib e google-auth-httplib2 para autorização do usuário.
    pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2
  • O framework de aplicativo da Web Flask Python.
    pip install --upgrade flask
  • A biblioteca HTTP requests.
    pip install --upgrade requests

Ruby

Para executar os exemplos de código do Ruby neste documento, você precisará de:

  • Ruby 2.6 ou superior
  • A biblioteca do Google Auth para Ruby:

    gem install googleauth
  • O framework de aplicativo da Web Sinatra Ruby.

    gem install sinatra

Node.js

Para executar os exemplos de código Node.js neste documento, você precisará de:

  • O LTS de manutenção, o LTS ativo ou a versão atual do Node.js.
  • O cliente Node.js das APIs do Google:

    npm install googleapis crypto express express-session

HTTP/REST

Não é necessário instalar nenhuma biblioteca para chamar diretamente o objeto OAuth 2.0 endpoints.

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 dele. Seu aplicativo precisa ter consentimento antes de executar uma solicitação de API do Google que exija a autorização do usuário.

A lista abaixo resume rapidamente essas etapas:

  1. Seu aplicativo identifica as permissões necessárias.
  2. Seu aplicativo redireciona o usuário para o Google junto com a lista de solicitações permissões.
  3. O usuário decide se quer conceder as permissões ao aplicativo.
  4. Seu aplicativo descobre o que o usuário decidiu.
  5. Se o usuário concedeu as permissões solicitadas, o aplicativo recupera os tokens necessários para fazer solicitações de API em nome do usuário.

Etapa 1: definir parâmetros de autorização

A primeira etapa é criar a solicitação de autorização. Essa solicitação define parâmetros que identificar seu aplicativo e definir as permissões que o usuário deverá conceder ao seu aplicativo.

  • Se você usa uma biblioteca de cliente do Google para autenticação e autorização do OAuth 2.0, pode cria e configura um objeto que define esses parâmetros.
  • Se você chamar o endpoint do OAuth 2.0 do Google diretamente, vai gerar um URL e definir o parâmetros no URL.

As guias abaixo definem os parâmetros de autorização compatíveis para aplicativos de servidor da Web. O os exemplos de linguagens específicas também mostram como usar uma biblioteca de cliente ou de autorização para configura um objeto que define esses parâmetros.

PHP

O snippet de código abaixo cria um objeto Google\Client(), que define a na solicitação de autorização.

Esse objeto usa as informações do seu arquivo client_secret.json para identificar suas para o aplicativo. Consulte Como criar credenciais de autorização para obter mais informações sobre no arquivo. O objeto também identifica os escopos para os quais seu aplicativo está solicitando permissão para acessar e o URL para o endpoint de autenticação do seu aplicativo, que vai processar a resposta do o servidor OAuth 2.0 do Google. Por fim, o código define os access_type e Parâmetros include_granted_scopes.

Por exemplo, este código solicita acesso somente leitura off-line à Google Drive:

$client = new Google\Client();

// Required, call the setAuthConfig function to load authorization credentials from
// client_secret.json file.
$client->setAuthConfig('client_secret.json');

// Required, to set the scope value, call the addScope function
$client->addScope(Google\Service\Drive::DRIVE_METADATA_READONLY);

// Required, call the setRedirectUri function to specify a valid redirect URI for the
// provided client_id
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');

// Recommended, offline access will give you both an access and refresh token so that
// your app can refresh the access token without user interaction.
$client->setAccessType('offline');

// Recommended, call the setState function. Using a state value can increase your assurance that
// an incoming connection is the result of an authentication request.
$client->setState($sample_passthrough_value);

// Optional, if your application knows which user is trying to authenticate, it can use this
// parameter to provide a hint to the Google Authentication Server.
$client->setLoginHint('hint@example.com');

// Optional, call the setPrompt function to set "consent" will prompt the user for consent
$client->setPrompt('consent');

// Optional, call the setIncludeGrantedScopes function with true to enable incremental
// authorization
$client->setIncludeGrantedScopes(true);

Python

O snippet de código a seguir usa o módulo google-auth-oauthlib.flow para criar a solicitação de autorização.

O código constrói um objeto Flow, que identifica seu aplicativo usando do arquivo client_secret.json que você baixou depois criar credenciais de autorização. Esse objeto também identifica o escopos que seu aplicativo está solicitando permissão de acesso e o URL para o escopo endpoint de autenticação, que lidará com a resposta do servidor OAuth 2.0 do Google. Por fim, o código define os parâmetros opcionais access_type e include_granted_scopes.

Por exemplo, este código solicita acesso somente leitura off-line à Google Drive:

import google.oauth2.credentials
import google_auth_oauthlib.flow

# Required, call the from_client_secrets_file method to retrieve the client ID from a
# client_secret.json file. The client ID (from that file) and access scopes are required. (You can
# also use the from_client_config method, which passes the client configuration as it originally
# appeared in a client secrets file but doesn't access the file itself.)
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'])

# Required, indicate where the API server will redirect the user after the user completes
# the authorization flow. The redirect URI is required. The value must exactly
# match one of the authorized redirect URIs for the OAuth 2.0 client, which you
# configured in the API Console. If this value doesn't match an authorized URI,
# you will get a 'redirect_uri_mismatch' error.
flow.redirect_uri = 'https://www.example.com/oauth2callback'

# Generate URL for request to Google's OAuth 2.0 server.
# Use kwargs to set optional request parameters.
authorization_url, state = flow.authorization_url(
    # Recommended, enable offline access so that you can refresh an access token without
    # re-prompting the user for permission. Recommended for web server apps.
    access_type='offline',
    # Optional, enable incremental authorization. Recommended as a best practice.
    include_granted_scopes='true',
    # Optional, if your application knows which user is trying to authenticate, it can use this
    # parameter to provide a hint to the Google Authentication Server.
    login_hint='hint@example.com',
    # Optional, set prompt to 'consent' will prompt the user for consent
    prompt='consent')

Ruby

Use o arquivo client_secrets.json que você criou para configurar um objeto cliente em seu para o aplicativo. Ao configurar um objeto cliente, você especifica os escopos de que seu aplicativo precisa acesso, bem como o URL para o endpoint de autenticação do seu aplicativo, que vai lidar com a resposta do servidor OAuth 2.0.

Por exemplo, este código solicita acesso somente leitura off-line à Google Drive:

require 'google/apis/drive_v3'
require "googleauth"
require 'googleauth/stores/redis_token_store'

client_id = Google::Auth::ClientId.from_file('/path/to/client_secret.json')
scope = 'https://www.googleapis.com/auth/drive.metadata.readonly'
token_store = Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new)
authorizer = Google::Auth::WebUserAuthorizer.new(client_id, scope, token_store, '/oauth2callback')

O aplicativo usa o objeto cliente para executar operações do OAuth 2.0, como gerar URLs de solicitação de autorização e aplicação de tokens de acesso a solicitações HTTP.

Node.js

O snippet de código a seguir cria um objeto google.auth.OAuth2, que define a na solicitação de autorização.

Esse objeto usa as informações de seu arquivo client_secret.json para identificar seu aplicativo. Para solicita permissões a um usuário para recuperar um token de acesso, você o redireciona para uma página de consentimento. Para criar um URL da página de consentimento:

const {google} = require('googleapis');
const crypto = require('crypto');
const express = require('express');
const session = require('express-session');

/**
 * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI
 * from the client_secret.json file. To get these credentials for your application, visit
 * https://console.cloud.google.com/apis/credentials.
 */
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for read-only Drive activity.
const scopes = [
  'https://www.googleapis.com/auth/drive.metadata.readonly'
];

// Generate a secure random state value.
const state = crypto.randomBytes(32).toString('hex');

// Store state in the session
req.session.state = state;

// Generate a url that asks permissions for the Drive activity scope
const authorizationUrl = oauth2Client.generateAuthUrl({
  // 'online' (default) or 'offline' (gets refresh_token)
  access_type: 'offline',
  /** Pass in the scopes array defined above.
    * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
  scope: scopes,
  // Enable incremental authorization. Recommended as a best practice.
  include_granted_scopes: true,
  // Include the state parameter to reduce the risk of CSRF attacks.
  state: state
});

Observação importante: o refresh_token só é retornado na primeira autorização. Mais detalhes aqui.

HTTP/REST

O endpoint OAuth 2.0 do Google está em https://accounts.google.com/o/oauth2/v2/auth. Isso endpoint só é acessível por HTTPS. Conexões HTTP simples são recusadas.

O servidor de autorização do Google aceita os seguintes parâmetros de string de consulta para aplicativos de servidor:

Parâmetros
client_id Obrigatório

O ID do cliente do aplicativo. É possível encontrar esse valor API Console Credentials page.

redirect_uri Obrigatório

Determina para onde o servidor da API redireciona o usuário depois que ele conclui a fluxo de autorização. O valor deve 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 de redirecionamento autorizado para o client_id fornecido, você receberá redirect_uri_mismatch erro.

Observe que o esquema, a capitalização e a barra final http ou https ("/") precisam ser correspondentes.

response_type Obrigatório

Determina se o endpoint do Google OAuth 2.0 retorna um código de autorização.

Defina o valor do parâmetro como code para aplicativos de servidor da Web.

scope Obrigatório

Um delimitado por espaço lista de escopos que identificam os recursos que seu aplicativo pode acessar na 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 acesso apenas aos recursos necessários além de permitir que os usuários controlem a quantidade de acesso que eles concedem aos seus para o aplicativo. Desse modo, há uma relação inversa entre o número de escopos solicitados e a probabilidade de obter o consentimento do usuário.

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

access_type Recomendado

Indica se o aplicativo pode atualizar tokens de acesso quando o usuário não está presente no navegador. Os valores de parâmetro válidos são online, que é o padrão e offline.

Defina o valor como offline se o aplicativo precisar atualizar os tokens de acesso quando o usuário não está presente no navegador. Esse é o método de atualizar o acesso são descritos posteriormente neste documento. Esse valor indica ao serviço de autorização do Google de rede retorne um token de atualização e um token de acesso na primeira vez que seu o aplicativo troca um código de autorização por tokens.

state Recomendado

Especifica qualquer valor de string que seu aplicativo usa para manter o estado entre suas 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 Componente de consulta do URL (?) do redirect_uri, depois que o usuário consentir ou negar as solicitação de acesso.

Esse parâmetro pode ser usado para várias finalidades, como direcionar o usuário para o o recurso correto no aplicativo, enviando valores de uso único e reduzindo solicitações entre sites. falsificação. Como seu redirect_uri pode ser adivinhado, usando um state pode aumentar sua segurança 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 capture o estado do cliente, é possível validar a resposta para garantir também que a solicitação e a resposta tenham sido originadas no mesmo navegador, fornecendo proteção contra ataques como solicitação entre sites falsificação. Consulte a OpenID Connect (em inglês) documentação para conferir um exemplo de como criar e confirmar um token state.

include_granted_scopes Opcional

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

login_hint Opcional

Caso seu aplicativo saiba qual usuário está tentando autenticar, ele pode usar esse parâmetro para fornecer uma dica ao servidor de autenticação do Google. O servidor usa a dica para simplificar o fluxo de login preenchendo automaticamente o campo de e-mail no formulário de login ou selecionar a sessão de login múltiplo apropriada.

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 comandos para apresentar ao usuário, delimitada por espaços e que diferencia maiúsculas de minúsculas. Se você não especifique esse parâmetro, o usuário receberá a solicitação apenas na primeira vez que seu projeto solicita acesso. Consulte Solicitar novo consentimento para mais informações.

Os valores possíveis são:

none Não mostre nenhuma tela de autenticação ou consentimento. Não deve ser especificado com e outros valores.
consent Solicite o consentimento do usuário.
select_account Peça que o usuário selecione uma conta.

Etapa 2: redirecionar para o servidor OAuth 2.0 do Google

Redirecionar o usuário ao servidor OAuth 2.0 do Google para iniciar a autenticação e o o processo de autorização. Normalmente, isso ocorre quando seu aplicativo precisa acessar pela primeira vez os dados do usuário. No caso de autorização incremental, esse também ocorre quando o aplicativo precisa acessar recursos adicionais pela primeira vez ainda não tem permissão para acessar.

PHP

  1. Gere um URL para solicitar acesso ao servidor OAuth 2.0 do Google:
    $auth_url = $client->createAuthUrl();
  2. Redirecione o usuário para $auth_url:
    header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));

Python

Este exemplo mostra como redirecionar o usuário para o URL de autorização usando a Web Flask framework de aplicativo:

return flask.redirect(authorization_url)

Ruby

  1. Gere um URL para solicitar acesso ao servidor OAuth 2.0 do Google:
    auth_uri = authorizer.get_authorization_url(login_hint: user_id, request: request)
  2. Redirecione o usuário para auth_uri.

Node.js

  1. Usar o URL gerado authorizationUrl da Etapa 1 generateAuthUrl para solicitar acesso ao servidor OAuth 2.0 do Google.
  2. Redirecione o usuário para authorizationUrl.
    res.redirect(authorizationUrl);

HTTP/REST

Sample redirect to Google's authorization server

An example URL is shown below, with line breaks and spaces for readability.

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly&
 access_type=offline&
 include_granted_scopes=true&
 response_type=code&
 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.

O servidor OAuth 2.0 do Google autentica o usuário e recebe o consentimento para sua para acessar os escopos solicitados. A resposta é enviada de volta para o aplicativo usando o URL de redirecionamento especificado.

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

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

O aplicativo não precisa fazer nada nessa etapa, já que aguarda a resposta Servidor OAuth 2.0 do Google indicando se algum acesso foi concedido. Essa resposta é explicada em próxima etapa.

Erros

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

admin_policy_enforced

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

disallowed_useragent

O endpoint de autorização é exibido dentro de um user agent incorporado não permitido pelo Políticas do OAuth 2.0.

Android

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

Os desenvolvedores Web podem encontrar esse erro quando um app Android abre um link geral da Web em uma user agent incorporado e um usuário navegar até o endpoint de autorização OAuth 2.0 do Google seu site. Os desenvolvedores devem permitir que links gerais sejam abertos no gerenciador de links padrão do do Google, o que inclui Links do app Android ou o app de navegador padrão. O Guias personalizadas do Android também é uma opção com suporte.

iOS

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

Os desenvolvedores Web podem encontrar esse erro quando um app para iOS ou macOS abre um link geral da Web em um user agent incorporado e um usuário navegar até o endpoint de autorização do OAuth 2.0 do Google seu site. Os desenvolvedores devem permitir que links gerais sejam abertos no gerenciador de links padrão do do Google, o que inclui Links universais ou o app de navegador padrão. O SFSafariViewController também é uma opção com suporte.

org_internal

O ID do cliente OAuth da solicitação faz parte de um projeto que limita o acesso às Contas do Google em um específicas Organização do Google Cloud. Para mais informações sobre essa opção de configuração, consulte a Tipo de usuário no artigo de ajuda "Como configurar a tela de permissão OAuth".

invalid_client

A chave secreta do cliente OAuth está incorreta. Analise o Cliente OAuth configuração, incluindo o ID do cliente e a chave secreta usados para essa solicitação.

invalid_grant

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

redirect_uri_mismatch

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

O parâmetro redirect_uri pode se referir ao fluxo OAuth fora de banda (OOB) que tem foi descontinuada e não tem mais suporte. Consulte a guia de migração para atualizar seu integração total.

invalid_request

Havia algo errado com a solicitação que você fez. Isso pode ocorrer por vários motivos:

  • A solicitação não foi formatada corretamente
  • Faltaram parâmetros obrigatórios na solicitação
  • A solicitação usa um método de autorização incompatível com o Google. Verificar o OAuth usa um método de integração recomendado

Etapa 4: gerenciar a resposta do servidor OAuth 2.0

O servidor OAuth 2.0 responde à solicitação de acesso do aplicativo usando o URL especificado na solicitação.

Se o usuário aprovar a solicitação de acesso, a resposta conterá um código de autorização. Se o usuário não aprovar a solicitação, a resposta conterá uma mensagem de erro. O o código de autorização ou a mensagem de erro retornada ao servidor da Web aparece na consulta , conforme mostrado abaixo:

Uma resposta de erro:

https://oauth2.example.com/auth?error=access_denied

Uma resposta do código de autorização:

https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7

Exemplo de resposta do servidor OAuth 2.0

É possível testar esse fluxo clicando no exemplo de URL a seguir, que solicita acesso somente leitura para visualizar metadados de arquivos no Google Drive:

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly&
 access_type=offline&
 include_granted_scopes=true&
 response_type=code&
 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, o que provavelmente produzirá um 404 NOT FOUND, a menos que sua máquina local veicule um arquivo nesse endereço. O a próxima etapa fornece mais detalhes sobre as informações retornadas no URI quando o usuário redirecionadas de volta para seu aplicativo.

Etapa 5: trocar o código de autorização para atualização e acesso tokens

Depois que o servidor da Web receber o código de autorização, ele poderá trocá-lo para um token de acesso.

PHP

Para trocar um código de autorização por um token de acesso, use o authenticate :

$client->authenticate($_GET['code']);

Recupere o token de acesso com o método getAccessToken:

$access_token = $client->getAccessToken();

Python

Na página de callback, use a biblioteca google-auth para verificar a autorização. do servidor de anúncios. Em seguida, use o método flow.fetch_token para trocar a autorização na resposta para um token de acesso:

state = flask.session['state']
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'],
    state=state)
flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

authorization_response = flask.request.url
flow.fetch_token(authorization_response=authorization_response)

# Store the credentials in the session.
# ACTION ITEM for developers:
#     Store user's access and refresh tokens in your data store if
#     incorporating this code into your real app.
credentials = flow.credentials
flask.session['credentials'] = {
    'token': credentials.token,
    'refresh_token': credentials.refresh_token,
    'token_uri': credentials.token_uri,
    'client_id': credentials.client_id,
    'client_secret': credentials.client_secret,
    'scopes': credentials.scopes}

Ruby

Na página de callback, use a biblioteca googleauth para verificar o servidor de autorização resposta. Use o método authorizer.handle_auth_callback_deferred para salvar a código de autorização e redirecionará de volta para o URL que solicitou originalmente a autorização. Isso adia a troca do código, ocultando temporariamente os resultados na sessão do usuário.

  target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request)
  redirect target_url

Node.js

Para trocar um código de autorização por um token de acesso, use o getToken :

const url = require('url');

// Receive the callback from Google's OAuth 2.0 server.
app.get('/oauth2callback', async (req, res) => {
  let q = url.parse(req.url, true).query;

  if (q.error) { // An error response e.g. error=access_denied
    console.log('Error:' + q.error);
  } else if (q.state !== req.session.state) { //check state value
    console.log('State mismatch. Possible CSRF attack');
    res.end('State mismatch. Possible CSRF attack');
  } else { // Get access and refresh tokens (if access_type is offline)

    let { tokens } = await oauth2Client.getToken(q.code);
    oauth2Client.setCredentials(tokens);
});

HTTP/REST

Para trocar um código de autorização por um token de acesso, chame o método https://oauth2.googleapis.com/token e defina os seguintes parâmetros:

Campos
client_id O ID do cliente extraído do API Console Credentials page.
client_secret A chave secreta do cliente recebida do API Console Credentials page.
code O código de autorização retornado da solicitação inicial.
grant_type Conforme definido no OAuth 2.0 especificação, o valor desse campo precisa ser definido como authorization_code.
redirect_uri Um dos URIs de redirecionamento listados para seu projeto no API Console Credentials page para o conjunto client_id

O snippet a seguir mostra um exemplo de solicitação:

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=your_client_id&
client_secret=your_client_secret&
redirect_uri=https%3A//oauth2.example.com/code&
grant_type=authorization_code

O Google responde a essa solicitação retornando um objeto JSON que contém um e um token de atualização. O token de atualização só será retornado se o aplicativo definir a access_type como offline na solicitação inicial ao servidor de autorização.

A resposta contém os seguintes campos:

Campos
access_token O token que seu aplicativo envia para autorizar uma solicitação de API do Google.
expires_in A vida útil restante do token de acesso em segundos.
refresh_token Um token que pode ser usado para receber um novo token de acesso. Os tokens de atualização são válidos até o usuário revoga o acesso. Novamente, esse campo só estará presente nesta resposta se você definir o access_type como offline na solicitação inicial ao servidor de autorização do Google.
scope Os escopos de acesso concedidos pelo access_token expressos como uma lista de strings delimitadas por espaço e que diferenciam maiúsculas de minúsculas.
token_type O tipo de token retornado. No momento, o valor desse campo é sempre definido como Bearer:

O snippet a seguir mostra um exemplo de resposta:

{
  "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in": 3920,
  "token_type": "Bearer",
  "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
  "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}

Erros

Ao trocar o código de autorização por um token de acesso, você pode encontrar o seguinte em vez da resposta esperada. Códigos de erro comuns e soluções sugeridas são listadas abaixo.

invalid_grant

O código de autorização informado é inválido ou está em um formato incorreto. Solicite um novo código até reiniciar o processo de OAuth para solicitar o consentimento do usuário de novo.

Como chamar APIs do Google

PHP

Use o token de acesso para chamar as APIs do Google seguindo estas etapas:

  1. Se você precisar aplicar um token de acesso a um novo objeto Google\Client — por exemplo, se você armazenou o token de acesso em uma sessão de usuário — use o Método setAccessToken:
    $client->setAccessToken($access_token);
  2. Crie um objeto de serviço para a API que você quer chamar. Você cria um objeto de serviço fornecendo um objeto Google\Client autorizado ao construtor para a API que você quiser ligar. Por exemplo, para chamar a API Drive:
    $drive = new Google\Service\Drive($client);
  3. Faça solicitações ao serviço da API usando o interface fornecida pelo objeto de serviço. Por exemplo, para listar os arquivos no Google Drive do usuário autenticado:
    $files = $drive->files->listFiles(array())->getItems();

Python

Após obter um token de acesso, seu aplicativo pode usá-lo para autorizar solicitações de API em nome de uma determinada conta de usuário ou de serviço. Usar as credenciais de autorização específicas do usuário para criar um objeto de serviço para a API que você quer chamar e depois usar esse objeto para solicitações de API autorizadas.

  1. Crie um objeto de serviço para a API que você quer chamar. Você cria um objeto de serviço chamando o método build da biblioteca googleapiclient.discovery com o o nome e a versão da API e as credenciais do usuário: Por exemplo, para chamar a versão 3 da API Drive:
    from googleapiclient.discovery import build
    
    drive = build('drive', 'v2', credentials=credentials)
  2. Faça solicitações ao serviço da API usando o interface fornecida pelo objeto de serviço. Por exemplo, para listar os arquivos no Google Drive do usuário autenticado:
    files = drive.files().list().execute()

Ruby

Após obter um token de acesso, o seu aplicativo pode usá-lo para fazer solicitações de API em nome de uma determinada conta de usuário ou de serviço. Usar as credenciais de autorização específicas do usuário para criar um objeto de serviço para a API que você quer chamar e depois usar esse objeto para solicitações de API autorizadas.

  1. Crie um objeto de serviço para a API que você quer chamar. Por exemplo, para chamar a versão 3 da API Drive:
    drive = Google::Apis::DriveV3::DriveService.new
  2. Defina as credenciais no serviço:
    drive.authorization = credentials
  3. Faça solicitações ao serviço da API usando o interface fornecida pelo objeto de serviço. Por exemplo, para listar os arquivos no Google Drive do usuário autenticado:
    files = drive.list_files

Alternativamente, a autorização pode ser fornecida em uma base por método, fornecendo o parâmetro options a um método:

files = drive.list_files(options: { authorization: credentials })

Node.js

Depois de receber um token de acesso e defini-lo como o objeto OAuth2, use o objeto para chamar as APIs do Google. Seu aplicativo pode usar esse token para autorizar solicitações de API em nome de uma determinada conta de usuário ou de serviço. Crie um objeto de serviço para a API que você quer chamar.

const { google } = require('googleapis');

// Example of using Google Drive API to list filenames in user's Drive.
const drive = google.drive('v3');
drive.files.list({
  auth: oauth2Client,
  pageSize: 10,
  fields: 'nextPageToken, files(id, name)',
}, (err1, res1) => {
  if (err1) return console.log('The API returned an error: ' + err1);
  const files = res1.data.files;
  if (files.length) {
    console.log('Files:');
    files.map((file) => {
      console.log(`${file.name} (${file.id})`);
    });
  } else {
    console.log('No files found.');
  }
});

HTTP/REST

Depois que o aplicativo obtém um token de acesso, você pode usá-lo para fazer chamadas a um serviço em nome de um determinado 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 à API incluindo uma consulta access_token ou um valor Bearer do 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 casos, você pode usar uma biblioteca de cliente para configurar suas chamadas para as APIs do Google (por exemplo, quando chamando a API Drive Files).

Você pode experimentar todas as APIs do Google e visualizar seus escopos em OAuth 2.0 Playground.

Exemplos GET HTTP

Uma chamada ao drive.files endpoint (a API Drive Files) usando a API HTTP Authorization: Bearer pode ser semelhante ao seguinte. É necessário 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 com o access_token parâmetro da string de consulta:

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. Este é 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 do parâmetro da string de consulta:

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

Exemplo completo

O exemplo a seguir imprime uma lista de arquivos no formato JSON no Google Drive de um usuário após a o usuário faz a autenticação e autoriza o acesso do aplicativo aos metadados do Google Drive do usuário.

PHP

Para executar esse exemplo:

  1. No API Console, adicione o URL da máquina local ao lista de URLs de redirecionamento. Por exemplo, adicione http://localhost:8080.
  2. Crie um novo diretório e mude para ele. Por exemplo:
    mkdir ~/php-oauth2-example
    cd ~/php-oauth2-example
  3. Instale o cliente da API do Google Biblioteca para PHP usando o Composer:
    composer require google/apiclient:^2.10
  4. Criar os arquivos index.php e oauth2callback.php com o conteúdo a seguir.
  5. Execute o exemplo com um servidor da Web configurado para exibir PHP. Se você usar o PHP 5.6 ou mais recente, pode usar o servidor da Web de teste integrado do PHP:
    php -S localhost:8080 ~/php-oauth2-example

index.php

<?php
require_once __DIR__.'/vendor/autoload.php';

session_start();

$client = new Google\Client();
$client->setAuthConfig('client_secrets.json');
$client->addScope(Google\Service\Drive::DRIVE_METADATA_READONLY);

if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
  $client->setAccessToken($_SESSION['access_token']);
  $drive = new Google\Service\Drive($client);
  $files = $drive->files->listFiles(array())->getItems();
  echo json_encode($files);
} else {
  $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

oauth2callback.php

<?php
require_once __DIR__.'/vendor/autoload.php';

session_start();

$client = new Google\Client();
$client->setAuthConfigFile('client_secrets.json');
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');
$client->addScope(Google\Service\Drive::DRIVE_METADATA_READONLY);

if (! isset($_GET['code'])) {
  // Generate and set state value
  $state = bin2hex(random_bytes(16));
  $client->setState($state);
  $_SESSION['state'] = $state;

  $auth_url = $client->createAuthUrl();
  header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
  // Check the state value
  if (!isset($_GET['state']) || $_GET['state'] !== $_SESSION['state']) {
    die('State mismatch. Possible CSRF attack.');
  }
  $client->authenticate($_GET['code']);
  $_SESSION['access_token'] = $client->getAccessToken();
  $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

Python

Neste exemplo, usamos o framework Flask. Ela executa um aplicativo da Web em http://localhost:8080 que permite testar o OAuth 2.0 fluxo Se você acessar esse URL, verá quatro links:

  • Testar uma solicitação de API:esse link aponta para uma página que tenta executar uma API de exemplo. solicitação. Se necessário, ele inicia o fluxo de autorização. Se tudo der certo, a página vai mostrar resposta da API.
  • Testar o fluxo de autenticação diretamente: esse link aponta para uma página que tenta enviar o usuário pelo fluxo de autorização. O app pede permissão para enviar solicitações de API autorizadas em nome do usuário.
  • Revogar credenciais atuais: esse link leva a uma página que revoga permissões concedidas pelo usuário ao aplicativo.
  • Limpar credenciais da sessão do Flask:esse link limpa as credenciais de autorização que estão armazenadas na sessão do Flask. Isso permite que você veja o que aconteceria se um usuário que já tivesse que recebeu permissão ao seu app tentou executar uma solicitação de API em uma nova sessão. Também permite você vê a resposta da API que seu aplicativo receberia se um usuário tivesse revogado as permissões concedidas ao seu e ele ainda tentou autorizar uma solicitação com um token de acesso revogado.
# -*- coding: utf-8 -*-

import os
import flask
import requests

import google.oauth2.credentials
import google_auth_oauthlib.flow
import googleapiclient.discovery

# This variable specifies the name of a file that contains the OAuth 2.0
# information for this application, including its client_id and client_secret.
CLIENT_SECRETS_FILE = "client_secret.json"

# This OAuth 2.0 access scope allows for full read/write access to the
# authenticated user's account and requires requests to use an SSL connection.
SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly']
API_SERVICE_NAME = 'drive'
API_VERSION = 'v2'

app = flask.Flask(__name__)
# Note: A secret key is included in the sample so that it works.
# If you use this code in your application, replace this with a truly secret
# key. See https://flask.palletsprojects.com/quickstart/#sessions.
app.secret_key = 'REPLACE ME - this value is here as a placeholder.'


@app.route('/')
def index():
  return print_index_table()


@app.route('/test')
def test_api_request():
  if 'credentials' not in flask.session:
    return flask.redirect('authorize')

  # Load credentials from the session.
  credentials = google.oauth2.credentials.Credentials(
      **flask.session['credentials'])

  drive = googleapiclient.discovery.build(
      API_SERVICE_NAME, API_VERSION, credentials=credentials)

  files = drive.files().list().execute()

  # Save credentials back to session in case access token was refreshed.
  # ACTION ITEM: In a production app, you likely want to save these
  #              credentials in a persistent database instead.
  flask.session['credentials'] = credentials_to_dict(credentials)

  return flask.jsonify(**files)


@app.route('/authorize')
def authorize():
  # Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps.
  flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
      CLIENT_SECRETS_FILE, scopes=SCOPES)

  # The URI created here must exactly match one of the authorized redirect URIs
  # for the OAuth 2.0 client, which you configured in the API Console. If this
  # value doesn't match an authorized URI, you will get a 'redirect_uri_mismatch'
  # error.
  flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

  authorization_url, state = flow.authorization_url(
      # Enable offline access so that you can refresh an access token without
      # re-prompting the user for permission. Recommended for web server apps.
      access_type='offline',
      # Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes='true')

  # Store the state so the callback can verify the auth server response.
  flask.session['state'] = state

  return flask.redirect(authorization_url)


@app.route('/oauth2callback')
def oauth2callback():
  # Specify the state when creating the flow in the callback so that it can
  # verified in the authorization server response.
  state = flask.session['state']

  flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
      CLIENT_SECRETS_FILE, scopes=SCOPES, state=state)
  flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

  # Use the authorization server's response to fetch the OAuth 2.0 tokens.
  authorization_response = flask.request.url
  flow.fetch_token(authorization_response=authorization_response)

  # Store credentials in the session.
  # ACTION ITEM: In a production app, you likely want to save these
  #              credentials in a persistent database instead.
  credentials = flow.credentials
  flask.session['credentials'] = credentials_to_dict(credentials)

  return flask.redirect(flask.url_for('test_api_request'))


@app.route('/revoke')
def revoke():
  if 'credentials' not in flask.session:
    return ('You need to <a href="/authorize">authorize</a> before ' +
            'testing the code to revoke credentials.')

  credentials = google.oauth2.credentials.Credentials(
    **flask.session['credentials'])

  revoke = requests.post('https://oauth2.googleapis.com/revoke',
      params={'token': credentials.token},
      headers = {'content-type': 'application/x-www-form-urlencoded'})

  status_code = getattr(revoke, 'status_code')
  if status_code == 200:
    return('Credentials successfully revoked.' + print_index_table())
  else:
    return('An error occurred.' + print_index_table())


@app.route('/clear')
def clear_credentials():
  if 'credentials' in flask.session:
    del flask.session['credentials']
  return ('Credentials have been cleared.<br><br>' +
          print_index_table())


def credentials_to_dict(credentials):
  return {'token': credentials.token,
          'refresh_token': credentials.refresh_token,
          'token_uri': credentials.token_uri,
          'client_id': credentials.client_id,
          'client_secret': credentials.client_secret,
          'scopes': credentials.scopes}

def print_index_table():
  return ('<table>' +
          '<tr><td><a href="/test">Test an API request</a></td>' +
          '<td>Submit an API request and see a formatted JSON response. ' +
          '    Go through the authorization flow if there are no stored ' +
          '    credentials for the user.</td></tr>' +
          '<tr><td><a href="/authorize">Test the auth flow directly</a></td>' +
          '<td>Go directly to the authorization flow. If there are stored ' +
          '    credentials, you still might not be prompted to reauthorize ' +
          '    the application.</td></tr>' +
          '<tr><td><a href="/revoke">Revoke current credentials</a></td>' +
          '<td>Revoke the access token associated with the current user ' +
          '    session. After revoking credentials, if you go to the test ' +
          '    page, you should see an <code>invalid_grant</code> error.' +
          '</td></tr>' +
          '<tr><td><a href="/clear">Clear Flask session credentials</a></td>' +
          '<td>Clear the access token currently stored in the user session. ' +
          '    After clearing the token, if you <a href="/test">test the ' +
          '    API request</a> again, you should go back to the auth flow.' +
          '</td></tr></table>')


if __name__ == '__main__':
  # When running locally, disable OAuthlib's HTTPs verification.
  # ACTION ITEM for developers:
  #     When running in production *do not* leave this option enabled.
  os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'

  # Specify a hostname and port that are set as a valid redirect URI
  # for your API project in the Google API Console.
  app.run('localhost', 8080, debug=True)

Ruby

Neste exemplo, usamos o framework Sinatra (em inglês).

require 'google/apis/drive_v3'
require 'sinatra'
require 'googleauth'
require 'googleauth/stores/redis_token_store'

configure do
  enable :sessions

  set :client_id, Google::Auth::ClientId.from_file('/path/to/client_secret.json')
  set :scope, Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY
  set :token_store, Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new)
  set :authorizer, Google::Auth::WebUserAuthorizer.new(settings.client_id, settings.scope, settings.token_store, '/oauth2callback')
end

get '/' do
  user_id = settings.client_id.id
  credentials = settings.authorizer.get_credentials(user_id, request)
  if credentials.nil?
    redirect settings.authorizer.get_authorization_url(login_hint: user_id, request: request)
  end
  drive = Google::Apis::DriveV3::DriveService.new
  files = drive.list_files(options: { authorization: credentials })
  "<pre>#{JSON.pretty_generate(files.to_h)}</pre>"
end

get '/oauth2callback' do
  target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request)
  redirect target_url
end

Node.js

Para executar esse exemplo:

  1. No API Console, adicione o URL do máquina local à lista de URLs de redirecionamento. Por exemplo, adicione http://localhost.
  2. Verifique se você tem o LTS de manutenção, o LTS ativo ou a versão atual do Node.js instalado.
  3. Crie um novo diretório e mude para ele. Por exemplo:
    mkdir ~/nodejs-oauth2-example
    cd ~/nodejs-oauth2-example
  4. Install the Google API Client Library for Node.js using npm:
    npm install googleapis
  5. Crie os arquivos main.js com o conteúdo abaixo.
  6. Execute o exemplo:
    node .\main.js

main.js

const http = require('http');
const https = require('https');
const url = require('url');
const { google } = require('googleapis');
const crypto = require('crypto');
const express = require('express');
const session = require('express-session');

/**
 * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI.
 * To get these credentials for your application, visit
 * https://console.cloud.google.com/apis/credentials.
 */
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for read-only Drive activity.
const scopes = [
  'https://www.googleapis.com/auth/drive.metadata.readonly'
];
/* Global variable that stores user credential in this code example.
 * ACTION ITEM for developers:
 *   Store user's refresh token in your data store if
 *   incorporating this code into your real app.
 *   For more information on handling refresh tokens,
 *   see https://github.com/googleapis/google-api-nodejs-client#handling-refresh-tokens
 */
let userCredential = null;

async function main() {
  const app = express();

  app.use(session({
    secret: 'your_secure_secret_key', // Replace with a strong secret
    resave: false,
    saveUninitialized: false,
  }));

  // Example on redirecting user to Google's OAuth 2.0 server.
  app.get('/', async (req, res) => {
    // Generate a secure random state value.
    const state = crypto.randomBytes(32).toString('hex');
    // Store state in the session
    req.session.state = state;

    // Generate a url that asks permissions for the Drive activity scope
    const authorizationUrl = oauth2Client.generateAuthUrl({
      // 'online' (default) or 'offline' (gets refresh_token)
      access_type: 'offline',
      /** Pass in the scopes array defined above.
        * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
      scope: scopes,
      // Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes: true,
      // Include the state parameter to reduce the risk of CSRF attacks.
      state: state
    });

    res.redirect(authorizationUrl);
  });

  // Receive the callback from Google's OAuth 2.0 server.
  app.get('/oauth2callback', async (req, res) => {
    // Handle the OAuth 2.0 server response
    let q = url.parse(req.url, true).query;

    if (q.error) { // An error response e.g. error=access_denied
      console.log('Error:' + q.error);
    } else if (q.state !== req.session.state) { //check state value
      console.log('State mismatch. Possible CSRF attack');
      res.end('State mismatch. Possible CSRF attack');
    } else { // Get access and refresh tokens (if access_type is offline)
      let { tokens } = await oauth2Client.getToken(q.code);
      oauth2Client.setCredentials(tokens);

      /** Save credential to the global variable in case access token was refreshed.
        * ACTION ITEM: In a production app, you likely want to save the refresh token
        *              in a secure persistent database instead. */
      userCredential = tokens;

      // Example of using Google Drive API to list filenames in user's Drive.
      const drive = google.drive('v3');
      drive.files.list({
        auth: oauth2Client,
        pageSize: 10,
        fields: 'nextPageToken, files(id, name)',
      }, (err1, res1) => {
        if (err1) return console.log('The API returned an error: ' + err1);
        const files = res1.data.files;
        if (files.length) {
          console.log('Files:');
          files.map((file) => {
            console.log(`${file.name} (${file.id})`);
          });
        } else {
          console.log('No files found.');
        }
      });
    }
  });

  // Example on revoking a token
  app.get('/revoke', async (req, res) => {
    // Build the string for the POST request
    let postData = "token=" + userCredential.access_token;

    // Options for POST request to Google's OAuth 2.0 server to revoke a token
    let postOptions = {
      host: 'oauth2.googleapis.com',
      port: '443',
      path: '/revoke',
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Content-Length': Buffer.byteLength(postData)
      }
    };

    // Set up the request
    const postReq = https.request(postOptions, function (res) {
      res.setEncoding('utf8');
      res.on('data', d => {
        console.log('Response: ' + d);
      });
    });

    postReq.on('error', error => {
      console.log(error)
    });

    // Post the request with data
    postReq.write(postData);
    postReq.end();
  });


  const server = http.createServer(app);
  server.listen(80);
}
main().catch(console.error);

HTTP/REST

Este exemplo em Python usa o framework Flask. e a biblioteca Requests para demonstrar o processo 2.0. Recomendamos o uso da biblioteca de cliente das APIs do Google para Python nesse fluxo. O na guia Python usa a biblioteca de cliente.)

import json

import flask
import requests


app = flask.Flask(__name__)

CLIENT_ID = '123456789.apps.googleusercontent.com'
CLIENT_SECRET = 'abc123'  # Read from a file or environmental variable in a real app
SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly'
REDIRECT_URI = 'http://example.com/oauth2callback'


@app.route('/')
def index():
  if 'credentials' not in flask.session:
    return flask.redirect(flask.url_for('oauth2callback'))
  credentials = json.loads(flask.session['credentials'])
  if credentials['expires_in'] <= 0:
    return flask.redirect(flask.url_for('oauth2callback'))
  else:
    headers = {'Authorization': 'Bearer {}'.format(credentials['access_token'])}
    req_uri = 'https://www.googleapis.com/drive/v2/files'
    r = requests.get(req_uri, headers=headers)
    return r.text


@app.route('/oauth2callback')
def oauth2callback():
  if 'code' not in flask.request.args:
    state = str(uuid.uuid4())
    flask.session['state'] = state
    auth_uri = ('https://accounts.google.com/o/oauth2/v2/auth?response_type=code'
                '&client_id={}&redirect_uri={}&scope={}&state={}').format(CLIENT_ID, REDIRECT_URI,
                                                                          SCOPE, state)
    return flask.redirect(auth_uri)
  else:
    if 'state' not in flask.request.args or flask.request.args['state'] != flask.session['state']:
      return 'State mismatch. Possible CSRF attack.', 400

    auth_code = flask.request.args.get('code')
    data = {'code': auth_code,
            'client_id': CLIENT_ID,
            'client_secret': CLIENT_SECRET,
            'redirect_uri': REDIRECT_URI,
            'grant_type': 'authorization_code'}
    r = requests.post('https://oauth2.googleapis.com/token', data=data)
    flask.session['credentials'] = r.text
    return flask.redirect(flask.url_for('index'))


if __name__ == '__main__':
  import uuid
  app.secret_key = str(uuid.uuid4())
  app.debug = False
  app.run()

Regras de validação do URI de redirecionamento

O Google aplica as seguintes regras de validação para redirecionar URIs a fim de ajudar os desenvolvedores manter os aplicativos seguros. Seus URIs de redirecionamento precisam aderir a essas regras. Consulte Seção 3 do RFC 3986 para os definição de domínio, host, caminho, consulta, esquema e informações do usuário, mencionada abaixo.

Regras de validação
Esquema

Os URIs de redirecionamento precisam usar o esquema HTTPS, não HTTP simples. URIs de host local (incluindo URIs de endereço IP de localhost) 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
  • TLDs de host (Domínios de nível superior) precisa pertencer à lista de sufixos públicos.
  • Os domínios de host não podem ser “googleusercontent.com”.
  • Os URIs de redirecionamento não podem conter domínios encurtadores de URL (por exemplo, goo.gl), a menos que o app é o proprietário do domínio. Além disso, se um aplicativo que possui um domínio mais curto optar por para esse domínio, esse URI de redirecionamento deve conter “/google-callback/” no caminho ou terminam com “/google-callback”.
  • Userinfo (link em inglês)

    Os URIs de redirecionamento não podem conter o subcomponente userinfo.

    Caminho

    Os URIs de redirecionamento não podem conter uma travessia de caminhos (também chamado de backtracking de diretório), que é representado por uma “/..”, um “\..” ou o URL e codificação.

    Consulta

    Os URIs de redirecionamento não podem conter redirecionamentos abertos.

    Fragmentos

    Os URIs de redirecionamento não podem conter o componente de fragmento.

    Personagens Os URIs de redirecionamento não podem conter determinados caracteres, incluindo:
    • Caracteres curinga ('*')
    • Caracteres ASCII não imprimíveis
    • Codificações percentuais inválidas (qualquer codificação de porcentagem que não siga a codificação para URL) forma de um sinal de porcentagem seguido de dois dígitos hexadecimais)
    • Caracteres nulos (um caractere NULL codificado, por exemplo, %00, %C0%80)

    Autorização incremental

    No protocolo OAuth 2.0, o aplicativo solicita autorização para acessar recursos, que são identificados por escopos. Solicitar autorização é uma prática recomendada para a experiência do usuário recursos no momento em que você precisa deles. Para isso, o servidor de autorização do Google dá suporte à autorização incremental. Esse recurso permite solicitar escopos conforme eles são necessários. 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 que contém todos os escopos concedidos pelo usuário ao projeto.

    Por exemplo, um app que permite ouvir músicas e criar mixes pode precisar de poucos recursos no momento do login, talvez nada mais do que o nome da pessoa que está fazendo login. No entanto, salvar um mix concluído exigiria acesso ao Google Drive. A maioria das pessoas iria encontrá-lo se o acesso ao Google Drive fosse solicitado apenas quando o aplicativo precisasse dela.

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

    Para implementar a autorização incremental, conclua o fluxo normal de solicitação de acesso token, mas certifique-se de que a solicitação de autorização inclua escopos concedidos anteriormente. Isso permite que o aplicativo evite gerenciar vários tokens de acesso.

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

    • O token pode ser usado para acessar recursos correspondentes a qualquer um dos escopos incluídos nova autorização combinada.
    • Quando você usa o token de atualização para a autorização combinada para obter um token de acesso, o token de acesso representa a autorização combinada e pode ser usado para qualquer um Valores scope incluídos na resposta.
    • A autorização combinada inclui todos os escopos que o usuário concedeu ao projeto de API, mesmo se as concessões foram solicitadas por clientes diferentes. Por exemplo, se um usuário deu acesso a um escopo usando o cliente de desktop de um aplicativo e, em seguida, concedia outro escopo para o mesmo por um cliente móvel, a autorização combinada incluiria os dois escopos.
    • Se você revogar um token que representa uma autorização combinada, o acesso a todos esses escopos de autorização em nome do usuário associado são revogados simultaneamente.

    Os exemplos de código específicos da linguagem na Etapa 1: definir autorização parâmetros e o URL de redirecionamento HTTP/REST de amostra na Etapa 2: Redirecionar para o servidor OAuth 2.0 do Google usa autorização incremental. Os exemplos de código abaixo também mostram o código que você precisa adicionar para usar a autorização incremental.

    PHP

    $client->setIncludeGrantedScopes(true);

    Python

    Em Python, defina o argumento de palavra-chave include_granted_scopes como true para garantir que uma solicitação de autorização inclua escopos já concedidos. É muito possível que include_granted_scopes não será o único argumento de palavra-chave que você definiu, conforme como mostrado no exemplo abaixo.

    authorization_url, state = flow.authorization_url(
        # Enable offline access so that you can refresh an access token without
        # re-prompting the user for permission. Recommended for web server apps.
        access_type='offline',
        # Enable incremental authorization. Recommended as a best practice.
        include_granted_scopes='true')

    Ruby

    auth_client.update!(
      :additional_parameters => {"include_granted_scopes" => "true"}
    )

    Node.js

    const authorizationUrl = oauth2Client.generateAuthUrl({
      // 'online' (default) or 'offline' (gets refresh_token)
      access_type: 'offline',
      /** Pass in the scopes array defined above.
        * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
      scope: scopes,
      // Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes: true
    });
    

    HTTP/REST

    GET https://accounts.google.com/o/oauth2/v2/auth?
      client_id=your_client_id&
      response_type=code&
      state=state_parameter_passthrough_value&
      scope=https%3A//www.googleapis.com/auth/drive.file&
      redirect_uri=https%3A//oauth2.example.com/code&
      prompt=consent&
      include_granted_scopes=true

    Atualização de um token de acesso (acesso off-line)

    Os tokens de acesso expiram periodicamente e se tornam credenciais inválidas para uma solicitação de API relacionada. Você podem atualizar um token de acesso sem solicitar a permissão do usuário (inclusive quando o usuário é ausente) se você solicitou acesso off-line aos escopos associados ao token.

    • Se você usa uma biblioteca de cliente da API do Google, o objeto do cliente é atualizado. o token de acesso conforme necessário, desde que você configure esse objeto para acesso off-line.
    • Se você não estiver usando uma biblioteca de cliente, defina o HTTP access_type parâmetro de consulta para offline ao redirecionar o usuário para servidor OAuth 2.0 do Google. Nesse caso, o servidor de autorização do Google retorna uma de atualização do token quando você trocar uma autorização code para um token de acesso. Depois, se o token de acesso expirar (ou em qualquer outro momento), você usar um token de atualização para receber um novo token de acesso.

    A solicitação de acesso off-line é um requisito para qualquer aplicativo que precise acessar uma a API quando o usuário não está presente. Por exemplo, um app que executa serviços de backup ou que a execução de ações em horários predeterminados precisa ser capaz de atualizar seu token de acesso quando o o usuário não está presente. O estilo de acesso padrão é chamado online.

    Aplicativos da Web do lado do servidor, aplicativos instalados e dispositivos recebem tokens de atualização durante o processo de autorização. Os tokens de atualização não costumam ser usados no cliente (JavaScript).

    PHP

    Se seu aplicativo precisar de acesso off-line a uma API do Google, defina o tipo de acesso do cliente da API como offline:

    $client->setAccessType("offline");

    Depois que um usuário conceder acesso off-line aos escopos solicitados, você poderá continuar usando a API para acessar as APIs do Google em nome do usuário quando ele estiver off-line. O objeto cliente o token de acesso é atualizado conforme necessário.

    Python

    Em Python, defina o argumento de palavra-chave access_type como offline para garantir que você poderá atualizar o token de acesso sem ter que pedir novamente ao usuário permissão. É muito possível que access_type não seja a única palavra-chave que foi definido, conforme mostrado no exemplo abaixo.

    authorization_url, state = flow.authorization_url(
        # Enable offline access so that you can refresh an access token without
        # re-prompting the user for permission. Recommended for web server apps.
        access_type='offline',
        # Enable incremental authorization. Recommended as a best practice.
        include_granted_scopes='true')

    Depois que um usuário conceder acesso off-line aos escopos solicitados, você poderá continuar usando a API para acessar as APIs do Google em nome do usuário quando ele estiver off-line. O objeto cliente o token de acesso é atualizado conforme necessário.

    Ruby

    Se seu aplicativo precisar de acesso off-line a uma API do Google, defina o tipo de acesso do cliente da API como offline:

    auth_client.update!(
      :additional_parameters => {"access_type" => "offline"}
    )

    Depois que um usuário conceder acesso off-line aos escopos solicitados, você poderá continuar usando a API para acessar as APIs do Google em nome do usuário quando ele estiver off-line. O objeto cliente o token de acesso é atualizado conforme necessário.

    Node.js

    Se seu aplicativo precisar de acesso off-line a uma API do Google, defina o tipo de acesso do cliente da API como offline:

    const authorizationUrl = oauth2Client.generateAuthUrl({
      // 'online' (default) or 'offline' (gets refresh_token)
      access_type: 'offline',
      /** Pass in the scopes array defined above.
        * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
      scope: scopes,
      // Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes: true
    });
    

    Depois que um usuário conceder acesso off-line aos escopos solicitados, você poderá continuar usando a API para acessar as APIs do Google em nome do usuário quando ele estiver off-line. O objeto cliente o token de acesso é atualizado conforme necessário.

    Os tokens de acesso expiram. Esta biblioteca vai usar automaticamente um token de atualização para receber um novo acesso token se ele estiver prestes a expirar. Uma maneira fácil de garantir que você sempre armazene os tokens mais recentes é usar o evento tokens:

    oauth2Client.on('tokens', (tokens) => {
      if (tokens.refresh_token) {
        // store the refresh_token in your secure persistent database
        console.log(tokens.refresh_token);
      }
      console.log(tokens.access_token);
    });

    Esse evento de token só ocorre na primeira autorização, e você precisa configurar seu access_type para offline ao chamar o generateAuthUrl para receber o token de atualização. Se você já concedeu as permissões necessárias ao app sem definir as restrições apropriadas para receber um token de atualização, você precisará Autorize novamente o aplicativo a receber um novo token de atualização.

    Para definir o refresh_token mais tarde, use o método setCredentials:

    oauth2Client.setCredentials({
      refresh_token: `STORED_REFRESH_TOKEN`
    });
    

    Quando o cliente tiver um token de atualização, os tokens de acesso serão adquiridos e atualizados automaticamente na próxima chamada à API.

    HTTP/REST

    Para atualizar um token de acesso, o aplicativo envia um HTTPS POST solicitação ao servidor de autorização do Google (https://oauth2.googleapis.com/token) que inclui os seguintes parâmetros:

    Campos
    client_id O ID do cliente recebido do API Console.
    client_secret A chave secreta do cliente recebida de API Console.
    grant_type Conforme definidas no especificação OAuth 2.0, o valor desse campo precisa ser definido como refresh_token.
    refresh_token O token de atualização retornado da troca de códigos de autorização.

    O snippet a seguir mostra um exemplo de solicitação:

    POST /token HTTP/1.1
    Host: oauth2.googleapis.com
    Content-Type: application/x-www-form-urlencoded
    
    client_id=your_client_id&
    client_secret=your_client_secret&
    refresh_token=refresh_token&
    grant_type=refresh_token

    Contanto que o usuário não tenha revogado o acesso concedido ao aplicativo, o servidor de token retorna um objeto JSON que contém um novo token de acesso. O snippet a seguir mostra um exemplo resposta:

    {
      "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
      "expires_in": 3920,
      "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
      "token_type": "Bearer"
    }

    Há limites para o número de tokens de atualização que serão emitidos. um limite por combinação de cliente/usuário e outra por usuário em todos os clientes. Salvar tokens de atualização no armazenamento a longo prazo e continuarão a usá-los enquanto permanecerem válidos. Se o seu aplicativo solicitar muitos tokens de atualização, poderá atingir esses limites; nesse caso, tokens de atualização mais antigos vão parar de funcionar.

    Revogação de um token

    Em alguns casos, um usuário pode querer revogar o acesso concedido a um aplicativo. Um usuário pode revogar o acesso acessando Configurações da conta. Consulte a Remover seção de acesso a sites ou apps da lista Sites de terceiros e apps com acesso à sua conta documento de suporte para mais informações.

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

    PHP

    Para revogar um token de maneira programática, chame revokeToken():

    $client->revokeToken();

    Python

    Para revogar programaticamente um token, faça uma solicitação para https://oauth2.googleapis.com/revoke, que inclui o token como um parâmetro e define o Cabeçalho Content-Type:

    requests.post('https://oauth2.googleapis.com/revoke',
        params={'token': credentials.token},
        headers = {'content-type': 'application/x-www-form-urlencoded'})

    Ruby

    Para revogar um token de forma programática, faça uma solicitação HTTP para oauth2.revoke endpoint:

    uri = URI('https://oauth2.googleapis.com/revoke')
    response = Net::HTTP.post_form(uri, 'token' => auth_client.access_token)
    

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

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

    Node.js

    Para revogar um token de forma programática, faça uma solicitação HTTPS POST para /revoke endpoint:

    const https = require('https');
    
    // Build the string for the POST request
    let postData = "token=" + userCredential.access_token;
    
    // Options for POST request to Google's OAuth 2.0 server to revoke a token
    let postOptions = {
      host: 'oauth2.googleapis.com',
      port: '443',
      path: '/revoke',
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Content-Length': Buffer.byteLength(postData)
      }
    };
    
    // Set up the request
    const postReq = https.request(postOptions, function (res) {
      res.setEncoding('utf8');
      res.on('data', d => {
        console.log('Response: ' + d);
      });
    });
    
    postReq.on('error', error => {
      console.log(error)
    });
    
    // Post the request with data
    postReq.write(postData);
    postReq.end();
    

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

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

    HTTP/REST

    Para revogar programaticamente um token, seu 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 um token de acesso ou de atualização. Se o token for 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 com sucesso, 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.