Neste documento, explicamos como os aplicativos de servidor da Web usam as bibliotecas de cliente das APIs do Google ou os endpoints do OAuth 2.0 do Google para implementar a autorização do OAuth 2.0 e acessar a API YouTube Data.
O OAuth 2.0 permite que os usuários compartilhem dados específicos com um aplicativo, mantendo a privacidade de nomes de usuário, senhas e outras informações. Por exemplo, um aplicativo pode usar o OAuth 2.0 para receber permissão para recuperar os dados do YouTube de um canal.
Esse fluxo do OAuth 2.0 é específico para autorização do usuário. Ele foi projetado para aplicativos que podem armazenar informações confidenciais e manter o estado. Um aplicativo de servidor da Web devidamente autorizado pode acessar uma API enquanto o usuário interage com o aplicativo ou depois que o usuário sai dele.
Os aplicativos de servidor da Web também costumam usar contas de serviço para autorizar solicitações de API, principalmente ao chamar APIs do Cloud para acessar dados baseados em projetos, em vez de dados específicos do usuário. Os aplicativos de servidor da Web podem usar contas de serviço em conjunto com a autorização do usuário.
A API YouTube Live Streaming não é compatível com o fluxo de conta de serviço. Como não é possível
vincular uma conta de serviço a uma conta do YouTube, as tentativas de autorizar solicitações com esse fluxo vão
gerar um erro NoLinkedYouTubeAccount.
Bibliotecas de cliente
Os exemplos específicos para cada linguagem nesta página usam bibliotecas de cliente das APIs do Google para implementar a autorização do OAuth 2.0. Para executar os exemplos de código, primeiro instale a biblioteca de cliente para sua linguagem.
Quando você usa uma biblioteca de cliente de APIs do Google para processar o fluxo do OAuth 2.0 do seu aplicativo, ela realiza muitas ações que o aplicativo precisaria processar por conta própria. Por 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 de cliente também gera URLs de redirecionamento corretos e ajuda a implementar gerenciadores de redirecionamento que trocam códigos de autorização por tokens de acesso.
As bibliotecas de cliente de APIs do Google para aplicativos do lado do servidor estão disponíveis nas seguintes linguagens:
Pré-requisitos
Ativar as APIs do projeto
Qualquer aplicativo que chame as APIs do Google precisa ativá-las no Console de APIs.
Para ativar uma API para um projeto, faça o seguinte:
- Abra a biblioteca de APIs no Console de APIs do Google.
- Se for solicitado, selecione um projeto ou crie um novo.
- Use a página "Biblioteca" para encontrar e ativar a API YouTube Data. Encontre outras APIs que seu aplicativo vai usar e ative-as também.
Criar credenciais de autorização
Qualquer aplicativo que use o OAuth 2.0 para acessar as APIs do Google precisa ter credenciais de autorização que o identifiquem 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 para esse projeto.
- Acesse a página Clientes.
- Clique em Criar cliente.
- Selecione o tipo de aplicativo Aplicativo da Web.
- Preencha o formulário e clique em Criar. Os aplicativos que usam linguagens e frameworks
como PHP, Java, Python, Ruby e .NET precisam especificar URIs de redirecionamento autorizados. Os
URIs de redirecionamento são os endpoints para os quais o servidor OAuth 2.0 pode enviar respostas. Esses
endpoints precisam seguir as regras de validação do Google.
Para testes, é possível especificar URIs que se referem à máquina local, como
http://localhost:8080. Todos os exemplos neste documento usamhttp://localhost:8080como o URI de redirecionamento.Recomendamos que você projete os endpoints de autenticação do seu app para que ele não exponha códigos de autorização a outros recursos na página.
Depois de criar suas credenciais, faça o download do arquivo client_secret.json no Console de APIs. Armazene o arquivo com segurança em um local que só seu aplicativo possa acessar.
Identificar escopos de acesso
Os escopos permitem que o aplicativo solicite acesso apenas aos recursos necessários e que os usuários controlem o nível de acesso concedido ao aplicativo. Assim, pode haver uma relação inversa entre o número de escopos solicitados e a probabilidade de receber 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 seu app precisará de permissão para acessar.
Também recomendamos que seu aplicativo solicite acesso aos escopos de autorização por um 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 entenderem com mais facilidade por que o aplicativo precisa do acesso que está solicitando.
A API YouTube Data v3 usa os seguintes escopos:
| Escopo | Descrição |
|---|---|
https://www. |
Gerenciar sua conta do YouTube |
https://www. |
Ver uma lista dos membros ativos atuais do canal, do nível deles e de quando se tornaram membros |
https://www. |
Ver, editar e excluir permanentemente vídeos, classificações, comentários e legendas do YouTube |
https://www. |
Visualize sua conta do YouTube |
https://www. |
Gerenciar seus vídeos do YouTube |
https://www. |
Ver e gerenciar seus ativos e conteúdos associados no YouTube |
https://www. |
Visualiza as informações particulares do seu canal que são relevantes para o processo de auditoria com um parceiro do YouTube |
O documento Escopos da API OAuth 2.0 contém uma lista completa de escopos que podem ser usados para acessar as APIs do Google.
Requisitos específicos de idioma
Para executar qualquer um dos exemplos de código neste documento, você precisa de uma Conta do Google, acesso à Internet e um navegador da Web. Se você estiver usando uma das bibliotecas de cliente da API, consulte também os requisitos específicos da linguagem nas seções a seguir.
PHP
Para executar os exemplos de código PHP neste documento, você precisa de:
- PHP 8.0 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.
-
A biblioteca de cliente das APIs do Google para PHP:
composer require google/apiclient:^2.15.0
Consulte a biblioteca de cliente das APIs do Google para PHP para mais informações.
Python
Para executar os exemplos de código Python neste documento, você precisa de:
- Python 3.7 ou mais recente
- A ferramenta de gerenciamento de pacotes pip.
- A versão 2.0 da biblioteca de cliente das APIs do Google para Python:
pip install --upgrade google-api-python-client
google-auth,google-auth-oauthlibegoogle-auth-httplib2para autorização do usuário.pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2
- O framework de aplicativos da Web Flask Python.
pip install --upgrade flask
- A biblioteca HTTP
requests.pip install --upgrade requests
Consulte a nota de lançamento da biblioteca de cliente Python da API do Google se não for possível fazer upgrade do Python e do guia de migração associado.
Ruby
Para executar os exemplos de código Ruby neste documento, você vai precisar de:
- Ruby 2.6 ou mais recente
-
A biblioteca de autenticação do Google para Ruby:
gem install googleauth
-
As bibliotecas de cliente para as APIs do Google Drive e Agenda:
gem install google-apis-drive_v3 google-apis-calendar_v3
-
O framework de aplicativos da Web Sinatra Ruby.
gem install sinatra
Node.js
Para executar os exemplos de código do Node.js neste documento, você vai precisar de:
- A versão LTS de manutenção, LTS ativa ou 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 os endpoints do OAuth 2.0.
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 do usuário para realizar uma solicitação de API em nome dele. Seu aplicativo precisa ter esse consentimento antes de executar uma solicitação de API do Google que exija autorização do usuário.
A lista a seguir resume essas etapas:
- O aplicativo identifica as permissões necessárias.
- O aplicativo redireciona o usuário para o Google com a lista de permissões solicitadas.
- O usuário decide se vai conceder as permissões ao aplicativo.
- Seu aplicativo descobre o que o usuário decidiu.
- Se o usuário conceder as permissões solicitadas, o aplicativo vai recuperar os tokens necessários para fazer solicitações de API em nome do usuário.
Etapa 1: definir os parâmetros de autorização
A primeira etapa é criar o pedido de autorização. Essa solicitação define parâmetros que identificam o aplicativo e as permissões que o usuário precisa conceder a ele.
- Se você usar uma biblioteca de cliente do Google para autenticação e autorização do OAuth 2.0, crie e configure um objeto que defina esses parâmetros.
- Se você chamar o endpoint do OAuth 2.0 do Google diretamente, vai gerar um URL e definir os parâmetros nele.
As guias a seguir definem os parâmetros de autorização compatíveis com aplicativos de servidor da Web. Os exemplos específicos de linguagem também mostram como usar uma biblioteca de cliente ou de autorização para configurar um objeto que define esses parâmetros:
PHP
O snippet de código abaixo cria um objeto Google\Client(), que define os
parâmetros na solicitação de autorização.
Esse objeto usa informações do arquivo client_secret.json para identificar seu
aplicativo. Consulte Como criar credenciais de autorização para saber mais sobre
esse arquivo. O objeto também identifica os escopos que seu aplicativo está solicitando permissão para acessar e o URL do endpoint de autenticação do seu aplicativo, que vai processar 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, para solicitar acesso off-line para recuperar os dados do YouTube de um usuário:
use Google\Client; $client = new 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_YouTube::YOUTUBE_FORCE_SSL); // 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 cria um objeto Flow, que identifica seu aplicativo usando
informações do arquivo client_secret.json que você baixou depois de
criar as credenciais de autorização. Esse objeto também identifica os
escopos que o aplicativo está solicitando permissão para acessar e o URL do endpoint de autenticação
do aplicativo, que vai processar 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, para solicitar acesso off-line para recuperar os dados do YouTube de um usuário:
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/youtube.force-ssl', 'https://www.googleapis.com/auth/calendar.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 de cliente no seu aplicativo. Ao configurar um objeto de cliente, você especifica os escopos que o aplicativo precisa acessar, além do URL do endpoint de autenticação do aplicativo, que processará a resposta do servidor OAuth 2.0.
Por exemplo, para solicitar acesso off-line para recuperar os dados do YouTube de um usuário:
require 'googleauth' require 'googleauth/web_user_authorizer' require 'googleauth/stores/redis_token_store' require 'google/apis/youtube_v3' require 'google/apis/calendar_v3' # Required, call the from_file method to retrieve the client ID from a # client_secret.json file. client_id = Google::Auth::ClientId.from_file('/path/to/client_secret.json') # Required, scope value # Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar. scope = ['Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY', 'Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY'] # Required, Authorizers require a storage instance to manage long term persistence of # access and refresh tokens. token_store = Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new) # 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. callback_uri = '/oauth2callback' # 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. authorizer = Google::Auth::WebUserAuthorizer.new(client_id, scope, token_store, callback_uri)
O aplicativo usa o objeto de cliente para realizar operações do OAuth 2.0, como gerar URLs de solicitação de autorização e aplicar tokens de acesso a solicitações HTTP.
Node.js
O snippet de código abaixo cria um objeto google.auth.OAuth2, que define os
parâmetros na solicitação de autorização.
Esse objeto usa informações do arquivo client_secret.json para identificar seu aplicativo. Para pedir permissões de um usuário para recuperar um token de acesso, redirecione-o para uma página de consentimento. Para criar um URL de 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 two non-Sign-In scopes: Read-only Drive activity and Google Calendar. const scopes = [ 'https://www.googleapis.com/auth/youtube.force-ssl', 'https://www.googleapis.com/auth/calendar.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 and Google Calendar 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 é retornado apenas na primeira
autorização. Confira mais detalhes
aqui.
HTTP/REST
O endpoint do OAuth 2.0 do Google está em https://accounts.google.com/o/oauth2/v2/auth. Esse
endpoint só pode ser acessado por HTTPS. As 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 de servidor da Web:
| Parâmetros | |||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
client_id |
Obrigatório
O ID do cliente do aplicativo. Esse valor pode ser encontrado na página Clientes do console do Cloud. |
||||||||||||||||
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 na
página Clientes do Console do Cloud
do cliente. Se esse valor não corresponder a um
URI de redirecionamento autorizado para o O esquema |
||||||||||||||||
response_type |
Obrigatório
Determina se o endpoint do OAuth 2.0 do Google retorna um código de autorização. Defina o valor do parâmetro como |
||||||||||||||||
scope |
Obrigatório
Uma lista de escopos delimitada por espaços que identifica os recursos que seu aplicativo pode acessar em nome do usuário. Esses valores informam a tela de permissão que o Google mostra 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 o nível de acesso concedido ao aplicativo. Assim, há uma relação inversa entre o número de escopos solicitados e a probabilidade de obter o consentimento do usuário. A API YouTube Data v3 usa os seguintes escopos:
O documento Escopos da API OAuth 2.0 fornece uma lista completa de escopos que podem ser usados para acessar as APIs do Google. 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 de acordo com o contexto, usando a autorização incremental, você ajuda os usuários a entender por que o aplicativo precisa do acesso solicitado. |
||||||||||||||||
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 Defina o valor como |
||||||||||||||||
state |
Recomendado
Especifica qualquer valor de string que o 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 É possível usar esse parâmetro para várias finalidades, como direcionar o usuário ao
recurso correto no aplicativo, enviar nonces e reduzir a falsificação de solicitações
entre sites. Como seu |
||||||||||||||||
include_granted_scopes |
Opcional
Permite que os aplicativos usem a autorização incremental para solicitar acesso a outros
escopos no contexto. Se você definir o valor desse parâmetro como |
||||||||||||||||
enable_granular_consent |
Opcional
O valor padrão é Quando o Google ativar as permissões granulares para um aplicativo, esse parâmetro não terá mais efeito. |
||||||||||||||||
login_hint |
Opcional
Se o aplicativo souber qual usuário está tentando se autenticar, ele poderá 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 o campo de e-mail no formulário de login ou selecionando a sessão de login múltiplo apropriada. Defina o valor do parâmetro como um endereço de e-mail ou identificador |
||||||||||||||||
prompt |
Opcional
Uma lista de solicitações delimitada por espaços e que diferencia maiúsculas de minúsculas para apresentar ao usuário. Se você não especificar esse parâmetro, o usuário será solicitado apenas na primeira vez que o projeto solicitar acesso. Consulte Como solicitar um novo consentimento para mais informações. Os valores possíveis são:
|
||||||||||||||||
Etapa 2: redirecionar para o servidor OAuth 2.0 do Google
Redirecione o usuário para o servidor OAuth 2.0 do Google para iniciar o processo de autenticação e autorização. Normalmente, isso ocorre quando o aplicativo precisa acessar os dados do usuário pela primeira vez. No caso da autorização incremental, essa etapa também ocorre quando o aplicativo precisa acessar recursos adicionais que ele não tem permissão para acessar.
PHP
- Gere um URL para solicitar acesso do servidor OAuth 2.0 do Google:
$auth_url = $client->createAuthUrl(); - 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 o framework de aplicativo da Web Flask:
return flask.redirect(authorization_url)
Ruby
- Gere um URL para solicitar acesso do servidor OAuth 2.0 do Google:
auth_uri = authorizer.get_authorization_url(request: request)
- Redirecione o usuário para
auth_uri.
Node.js
-
Use o URL gerado
authorizationUrldo métodogenerateAuthUrlda Etapa 1 para solicitar acesso do servidor OAuth 2.0 do Google. -
Redirecione o usuário para
authorizationUrl.res.redirect(authorizationUrl);
HTTP/REST
Exemplo de redirecionamento para o servidor de autorização do Google
Confira abaixo um exemplo de URL, com quebras de linha e espaços para facilitar a leitura. O URL solicita acesso a um escopo que permite recuperar os dados do usuário no YouTube. Ele usa a autorização incremental (include_granted_scopes=true) para garantir que o novo token de acesso cubra todos os escopos aos quais o usuário concedeu acesso ao aplicativo anteriormente. Vários outros parâmetros também são definidos no exemplo.
https://accounts.google.com/o/oauth2/v2/auth? scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.force-ssl& access_type=offline& include_granted_scopes=true& response_type=code& state=state_parameter_passthrough_value& redirect_uri=http%3A%2F%2Flocalhost%2Foauth2callback& client_id=client_id
Depois de criar o URL de solicitação, redirecione o usuário para ele.
O servidor OAuth 2.0 do Google autentica o usuário e recebe o consentimento dele para que seu aplicativo acesse os escopos solicitados. A resposta é enviada de volta ao aplicativo usando o URL de redirecionamento que você especificou.
Etapa 3: o Google pede o consentimento do usuário
Nesta etapa, o usuário decide se concede ao aplicativo o acesso solicitado. Nessa fase, o Google exibe uma janela de consentimento que mostra o nome do 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 e 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.
Seu aplicativo não precisa fazer nada nesse estágio, pois ele aguarda a resposta do servidor OAuth 2.0 do Google indicando se algum acesso foi concedido. Essa resposta é explicada na 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 ao usuário, em vez dos fluxos de autenticação e autorização esperados. Os códigos de erro comuns e as resoluções sugeridas são:
admin_policy_enforced
A Conta do Google não pode autorizar um ou mais escopos solicitados devido às políticas do administrador do Google Workspace. Consulte o artigo de ajuda para admins do Google Workspace Controlar os apps internos e de terceiros com acesso aos dados do Google Workspace para mais informações sobre como um administrador pode restringir o acesso a todos os escopos ou aos escopos sensíveis 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.
Os desenvolvedores de iOS e macOS podem encontrar esse erro ao abrir solicitações de autorização no
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 web podem encontrar esse erro quando um app para iOS ou macOS abre um link da Web geral em
um user agent incorporado e um usuário acessa 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, o que inclui os gerenciadores de
links universais
ou o app de navegador 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 às 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 "Como configurar a tela de permissão OAuth".
invalid_client
A chave secreta do cliente OAuth está incorreta. Revise a configuração do cliente OAuth, incluindo o ID do cliente e a chave secreta usados para essa solicitação.
deleted_client
O cliente OAuth usado para fazer a solicitação foi excluído. A exclusão pode acontecer de forma manual ou automática no caso de clientes não utilizados . Os clientes excluídos podem ser restaurados em até 30 dias após a exclusão. Saiba mais .
invalid_grant
Ao atualizar um token de acesso ou usar a autorização incremental, o token pode ter expirado ou sido invalidado. Autentique o usuário novamente e peça o consentimento do usuário para obter novos tokens. Se o erro persistir, verifique se o aplicativo foi configurado corretamente e se você está usando os tokens e parâmetros corretos na solicitação. Caso contrário, é possível que a conta do usuário 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 autorizado para o ID do cliente OAuth. Revise os URIs de redirecionamento autorizados na
página Clientes
do console do Google Cloud.
O parâmetro redirect_uri pode se referir ao fluxo fora de banda (OOB, na sigla em inglês) do OAuth, que foi
descontinuado e não é mais compatível. Consulte o
guia de migração para atualizar sua
integração.
invalid_request
Ocorreu um erro na sua solicitação. Isso pode acontecer por vários motivos:
- A solicitação não foi formatada corretamente
- A solicitação não tinha os parâmetros obrigatórios
- A solicitação usa um método de autorização que não é aceito pelo Google. Verifique se a integração do OAuth usa um método de integração recomendado
Etapa 4: processar 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 vai conter um código de autorização. Se o usuário não aprovar a solicitação, a resposta vai conter uma mensagem de erro. O código de autorização ou a mensagem de erro retornada ao servidor da Web aparece na string de consulta, como mostrado nos exemplos a seguir:
Uma resposta de erro:
https://oauth2.example.com/auth?error=access_denied
Uma resposta de código de autorização:
https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7
Exemplo de resposta do servidor OAuth 2.0
Para testar esse fluxo, clique no URL de exemplo a seguir, que solicita acesso somente leitura para visualizar metadados de arquivos no Google Drive e acesso somente leitura para visualizar seus eventos do Google Agenda:
https://accounts.google.com/o/oauth2/v2/auth? scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.force-ssl& access_type=offline& include_granted_scopes=true& response_type=code& state=state_parameter_passthrough_value& redirect_uri=http%3A%2F%2Flocalhost%2Foauth2callback& client_id=client_id
Depois de concluir o fluxo do OAuth 2.0, o navegador vai redirecionar você para o OAuth 2.0 Playground, uma ferramenta para testar fluxos do OAuth. Você vai notar que o OAuth 2.0 Playground capturou automaticamente o código de autorização.
Etapa 5: trocar o código de autorização por tokens de atualização e acesso
Depois que o servidor da Web recebe o código de autorização, ele pode trocar o código de autorização por um token de acesso.
PHP
Para trocar um código de autorização por um token de acesso, use o
método fetchAccessTokenWithAuthCode:
$access_token = $client->fetchAccessTokenWithAuthCode($_GET['code']);Python
Na página de callback, use a biblioteca google-auth para verificar a resposta do servidor de autorização. Em seguida, use o método flow.fetch_token para trocar o código de autorização
nessa resposta por 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/youtube.force-ssl'], 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 browser session storage, but for security: client_id, client_secret, # and token_uri are instead stored only on the backend server. credentials = flow.credentials flask.session['credentials'] = { 'token': credentials.token, 'refresh_token': credentials.refresh_token, 'granted_scopes': credentials.granted_scopes}
Ruby
Na página de callback, use a biblioteca googleauth para verificar a resposta do servidor de
autorização. Use o método authorizer.handle_auth_callback_deferred para salvar o
código de autorização e redirecionar de volta para o URL que solicitou a autorização originalmente. Isso
adia a troca do código ao armazenar 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 método 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
endpoint https://oauth2.googleapis.com/token e defina os seguintes parâmetros:
| Campos | |
|---|---|
client_id |
O ID do cliente obtido na página Clientes do console do Cloud. |
client_secret |
Opcional
A chave secreta do cliente obtida na página Clientes do console do Cloud. |
code |
O código de autorização retornado da solicitação inicial. |
grant_type |
Conforme definido na especificação do OAuth 2.0, o valor desse campo precisa ser definido como authorization_code. |
redirect_uri |
Um dos URIs de redirecionamento listados para seu projeto na
página Clientes do
Console do Cloud para o
client_id fornecido. |
Embora o uso do DPoP seja opcional, ele é recomendado para aumentar a segurança. A segurança do DPoP depende da restrição da chave privada a um único dispositivo. Recomendamos armazená-la de forma que não possa ser copiada para fora do dispositivo, por exemplo, usando TPMs, Secure Enclaves ou outros keystores com suporte de hardware. Para usar a DPoP, seu aplicativo precisa gerar um novo JWT de prova de DPoP exclusivo para cada solicitação ao endpoint do token e adicioná-lo como um cabeçalho da solicitação HTTP.
| Cabeçalho | Obrigatório | Descrição |
|---|---|---|
DPoP |
Opcional | Uma prova de DPoP é um JWT que comprova a
posse de uma chave privada. Este é um cabeçalho, não um parâmetro. Se fornecidos, os tokens retornados
serão vinculados a essa chave. Uma nova prova exclusiva precisa ser gerada para cada solicitação e
precisa incluir declarações htm (método HTTP) e htu (URI HTTP) que
correspondam à solicitaçã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 DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik\ VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR\ nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE\ QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiItQndDM0VTYzZhY2MybFRjIiwiaHRtIj\ oiUE9TVCIsImh0dSI6Imh0dHBzOi8vc2VydmVyLmV4YW1wbGUuY29tL3Rva2VuIiwia\ WF0IjoxNTYyMjYyNjE2fQ.2-GxA6T8lP4vfrg8v-FdWP0A0zdrj8igiMLvqRMUvwnQg\ 4PtFLbdLXiOSsX0x7NVY-FNyJK70nfbV37xRZT3Lg code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7& client_id=your_client_id& redirect_uri=https%3A//developers.google.com/oauthplayground& grant_type=authorization_code
Criar uma prova de DPoP
As etapas a seguir mostram como criar uma prova de DPoP usando o OpenSSL na linha de comando:
- Gere um par de chaves EC P-256:
openssl ecparam -name prime256v1 -genkey -noout -out dpop_private.pem openssl ec -in dpop_private.pem -pubout -out dpop_public.pem
- Crie o cabeçalho DPoP:
O cabeçalho precisa incluir as declarações
typ,algejwk(chave pública). Os valoresxeysão as coordenadas codificadas em Base64Url da sua chave pública EC. Codifique este JSON em Base64Url:{ "typ":"dpop+jwt", "alg":"ES256", "jwk": { "kty":"EC", "x":"YOUR_PUBLIC_KEY_X", "y":"YOUR_PUBLIC_KEY_Y", "crv":"P-256" } } - Crie o payload de DPoP:
O payload precisa incluir
jti(um identificador exclusivo para a solicitação),htm(método HTTP, por exemplo,POST),htu(URI HTTP, por exemplo,https://oauth2.googleapis.com/token) eiat(emitido no momento). Se você recebeu um valor de uso único do servidor em um cabeçalhoDPoP-Noncena resposta a uma solicitação anterior, inclua esse valor em uma declaraçãononce. A declaração nonce é opcional para trocas de código de autorização e usada apenas quando o cabeçalho DPoP-Nonce foi recebido anteriormente. Codifique este JSON em Base64Url:{ "jti":"JTI_VALUE", "htm":"POST", "htu":"https://oauth2.googleapis.com/token", "iat":YOUR_JWT_ISSUED_TIME, "nonce":"SERVER_PROVIDED_NONCE" }O valor de
jtidepende do tipo de troca:- Para trocas de código de autorização, o
jtiprecisa ser o hash SHA256 codificado em Base64Url do código de autorização:"jti":"BASE64URL(SHA256(AUTHORIZATION_CODE))". - Para trocas de token de atualização, o
jtiprecisa ser um identificador exclusivo por solicitação:"jti":"YOUR_UNIQUE_PER_REQUEST_IDENTIFIER".
- Para trocas de código de autorização, o
- Assine a prova:
Concatene o cabeçalho e o payload codificados com um ponto (
.) e assine o resultado com sua chave privada usando o ES256. A JWS exige que a assinatura esteja em um formato bruto concatenadoR | S(64 bytes para P-256). Se você usar o OpenSSL diretamente, será necessário converter a assinatura padrão codificada em DER ASN.1 para esse formato bruto.
Uma troca bem-sucedida é indicada por uma resposta 200 OK
que contém os tokens. Se uma prova de DPoP válida for usada durante
a troca, o token de atualização que o Google retornar será vinculado à sua chave por DPoP, mas os tokens de acesso
não serão vinculados por DPoP. Os tokens de acesso vão manter o token_type de
Bearer em vez de DPoP.
Além disso, o Google retorna um cabeçalho HTTP DPoP-Nonce na resposta.
O cliente precisa armazenar esse valor de uso único em cache e incluí-lo na declaração nonce da prova de DPoP
em solicitações subsequentes (como ao trocar um token de atualização por um novo token de acesso ou ao
chamar APIs protegidas por DPoP). Ao usar esse valor de uso único emitido antecipadamente, você pode evitar uma falha de ida e volta
extra (use_dpop_nonce) na próxima solicitação.
As provas de DPoP precisam ser incluídas nas solicitações de troca de token feitas com tokens de atualização vinculados a DPoP.
Uma troca com falha ocorre se o cabeçalho DPoP estiver
ausente quando esperado, for inválido ou se a prova usar uma chave diferente da
vinculada ao token. Nesses casos, o servidor retorna um erro 400 Bad Request.
Se a prova de DPoP tiver declarações htm ou htu incompatíveis, um iat expirado, um jti reutilizado ou uma assinatura inválida, o Google vai retornar um código do erro invalid_dpop_proof.
Se um valor de uso único de DPoP for necessário, como durante uma troca de token de atualização, e a prova de DPoP não tiver uma declaração nonce ou o valor de uso único for inaceitável para o servidor (por exemplo, expirou, já foi usado ou está incorreto), o Google vai retornar um código de erro use_dpop_nonce com um cabeçalho HTTP DPoP-Nonce contendo um novo valor de uso único que pode ser usado em uma solicitação subsequente.
Outras falhas podem retornar invalid_grant.
O Google responde a essa solicitação retornando um objeto JSON que contém um token de acesso de curta duração e um token de atualização.
O token de atualização só será retornado se o aplicativo definir o parâmetro access_type
como offline na solicitação inicial ao servidor de autorização
do Google.
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é que
o usuário revogue o acesso ou o token de atualização expire. Se o DPoP foi usado, o
token de atualização é vinculado à chave privada usada para assinar a prova do DPoP.
Novamente, esse campo só estará presente nessa resposta se você definir o parâmetro access_type
como offline na solicitação inicial para o servidor de autorização do Google.
|
refresh_token_expires_in |
A vida útil restante do token de atualização em segundos. Esse valor só é definido quando o usuário concede acesso com base no tempo. |
scope |
Os escopos de acesso concedidos pelo access_token expressos como uma lista de
strings que diferenciam maiúsculas de minúsculas e são delimitadas por espaços. |
token_type |
O tipo de token retornado. Esse valor é sempre Bearer, mesmo quando o DPoP é usado. |
O snippet a seguir mostra um exemplo de cabeçalhos de resposta e corpo bem-sucedidos quando o DPoP é usado:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
DPoP-Nonce: AN3XwJjZsjnb0ZuWkRlek8QU7wY-Zhf-5IP6tO0tORz0KgtDT1Bo8FX-w4nz3r5lnepI
{
"access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
"expires_in": 3920,
"token_type": "Bearer",
"scope": "https://www.googleapis.com/auth/youtube.force-ssl https://www.googleapis.com/auth/calendar.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 erro em vez da resposta esperada. Os códigos do erro comuns e as resoluções sugeridas estão listados nesta seção.
invalid_grant
O código de autorização fornecido é inválido ou está no formato incorreto. Solicite um novo código reiniciando o processo OAuth para pedir o consentimento do usuário novamente.
Etapa 6: verificar quais escopos os usuários concederam
Ao solicitar várias permissões (escopos), os usuários podem não conceder ao app acesso a todas elas. Seu app precisa verificar quais escopos foram realmente concedidos e lidar de forma adequada com situações em que algumas permissões são negadas, normalmente desativando os recursos que dependem desses escopos negados.
No entanto, há exceções. Os apps do Google Workspace Enterprise com delegação de autoridade em todo o domínio ou marcados como Confiáveis ignoram a tela de permissão granular. Para esses apps, os usuários não vão ver a tela de permissão granular. Em vez disso, o app vai receber todos os escopos solicitados ou nenhum.
Para mais informações, consulte Como processar permissões granulares.
PHP
Para verificar quais escopos o usuário concedeu, use o método getGrantedScope():
// Space-separated string of granted scopes if it exists, otherwise null. $granted_scopes = $client->getOAuth2Service()->getGrantedScope(); // Determine which scopes user granted and build a dictionary $granted_scopes_dict = [ 'Drive' => str_contains($granted_scopes, Google\Service\Drive::DRIVE_METADATA_READONLY), 'Calendar' => str_contains($granted_scopes, Google\Service\Calendar::CALENDAR_READONLY) ];
Python
O objeto credentials retornado tem uma propriedade granted_scopes,
que é uma lista de escopos que o usuário concedeu ao app.
credentials = flow.credentials flask.session['credentials'] = { 'token': credentials.token, 'refresh_token': credentials.refresh_token, 'granted_scopes': credentials.granted_scopes}
A função a seguir verifica quais escopos o usuário concedeu ao seu app.
def check_granted_scopes(credentials): features = {} if 'https://www.googleapis.com/auth/drive.metadata.readonly' in credentials['granted_scopes']: features['drive'] = True else: features['drive'] = False if 'https://www.googleapis.com/auth/calendar.readonly' in credentials['granted_scopes']: features['calendar'] = True else: features['calendar'] = False return features
Ruby
Ao solicitar vários escopos de uma só vez, verifique quais foram concedidos usando
a propriedade scope do objeto credentials.
# User authorized the request. Now, check which scopes were granted. if credentials.scope.include?(Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY) # User authorized read-only Drive activity permission. # Calling the APIs, etc else # User didn't authorize read-only Drive activity permission. # Update UX and application accordingly end # Check if user authorized Calendar read permission. if credentials.scope.include?(Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY) # User authorized Calendar read permission. # Calling the APIs, etc. else # User didn't authorize Calendar read permission. # Update UX and application accordingly end
Node.js
Ao solicitar vários escopos de uma só vez, verifique quais foram concedidos usando
a propriedade scope do objeto tokens.
// User authorized the request. Now, check which scopes were granted. if (tokens.scope.includes('https://www.googleapis.com/auth/youtube.force-ssl')) { // User authorized read-only Drive activity permission. // Calling the APIs, etc. } else { // User didn't authorize read-only Drive activity permission. // Update UX and application accordingly } // Check if user authorized Calendar read permission. if (tokens.scope.includes('https://www.googleapis.com/auth/calendar.readonly')) { // User authorized Calendar read permission. // Calling the APIs, etc. } else { // User didn't authorize Calendar read permission. // Update UX and application accordingly }
HTTP/REST
Para verificar se o usuário concedeu ao aplicativo acesso a um escopo específico,
examine o campo scope na resposta do token de acesso. Os escopos de acesso concedidos pelo
token de acesso expressos como uma lista de strings que diferenciam maiúsculas de minúsculas e são delimitadas por espaços.
Por exemplo, a resposta de token de acesso de amostra a seguir indica que o usuário concedeu ao seu aplicativo acesso às permissões de somente leitura de atividade do Drive e de eventos da agenda:
{ "access_token": "1/fFAGRNJru1FTz70BzhT3Zg", "expires_in": 3920, "token_type": "Bearer", "scope": "https://www.googleapis.com/auth/youtube.force-ssl https://www.googleapis.com/auth/calendar.readonly", "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI" }
Chamar APIs do Google
PHP
Use o token de acesso para chamar as APIs do Google seguindo estas etapas:
- Se você precisar aplicar um token de acesso a um novo objeto
Google\Client, por exemplo, se tiver armazenado o token de acesso em uma sessão de usuário, use o métodosetAccessToken:$client->setAccessToken($access_token); - Crie um objeto de serviço para a API que você quer chamar. Para criar um objeto de serviço,
forneça um objeto
Google\Clientautorizado ao construtor da API que você quer chamar. Por exemplo, para chamar a API YouTube Data:$youtube = new Google_Service_YouTube($client); - Faça solicitações ao serviço da API usando a
interface fornecida pelo objeto de serviço.
Por exemplo, para usar a API YouTube Data para recuperar uma lista de transmissões ao vivo do canal do usuário autenticado:
$broadcasts = $youtube->liveBroadcasts->listLiveBroadcasts('id,snippet', [ 'mine' => true ]);
Python
Depois de receber 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. Use 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, em seguida, use esse objeto para fazer solicitações de API autorizadas.
- Crie um objeto de serviço para a API que você quer chamar. Para criar um objeto de serviço,
chame o método
buildda bibliotecagoogleapiclient.discoverycom o nome e a versão da API e as credenciais do usuário: Por exemplo, para chamar a versão 3 da API YouTube Data:from googleapiclient.discovery import build youtube = build('youtube', 'v3', credentials=credentials)
- Faça solicitações ao serviço da API usando a
interface fornecida pelo objeto de serviço.
Por exemplo, para usar a API YouTube Data para recuperar uma lista de transmissões ao vivo do canal do usuário autenticado:
broadcasts = youtube.liveBroadcasts().list(part='id,snippet', mine=True).execute()
Ruby
Depois de receber um token de acesso, seu aplicativo pode usá-lo para fazer solicitações de API em nome de uma determinada conta de usuário ou de serviço. Use 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, em seguida, use esse objeto para fazer solicitações de API autorizadas.
- Crie um objeto de serviço para a API que você quer chamar.
Por exemplo, para chamar a versão 3 da API YouTube Data:
youtube = Google::Apis::YoutubeV3::YouTubeService.new
- Defina as credenciais no serviço:
youtube.authorization = credentials
- Faça solicitações ao serviço da API usando a
interface
fornecida pelo objeto de serviço.
Por exemplo, para usar a API YouTube Data para recuperar uma lista de transmissões ao vivo do canal do usuário autenticado:
broadcasts = youtube.list_liveBroadcasts('id,snippet', mine: true)
Como alternativa, a autorização pode ser fornecida por método, fornecendo o
parâmetro options a um método:
broadcasts = youtube.list_liveBroadcasts('id,snippet', mine: true)
Node.js
Depois de receber um token de acesso e defini-lo no objeto OAuth2, use o objeto
para chamar as APIs do Google. O 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.
Por exemplo, o código a seguir usa a API Google Drive para listar nomes de arquivos no Drive do usuário.
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 receber um token de acesso, você poderá 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 isso, inclua
o token de acesso em uma solicitação à API, incluindo um parâmetro de consulta access_token
ou um valor de cabeçalho HTTP Authorization Bearer. Quando possível,
o cabeçalho HTTP é preferível, porque as strings de consulta tendem a ficar visíveis nos registros do servidor. Na maioria
dos casos, é possível usar uma biblioteca de cliente para configurar as chamadas para as APIs do Google (por exemplo, ao
chamar a API YouTube Live Streaming).
A API YouTube Live Streaming não é compatível com o fluxo da conta de serviço. Como não
há como vincular uma conta de serviço a uma conta do YouTube, as tentativas de autorizar solicitações com esse
fluxo vão gerar um erro NoLinkedYouTubeAccount.
Você pode testar todas as APIs do Google e conferir os escopos delas no OAuth 2.0 Playground.
Exemplos de HTTP GET
Uma chamada para o endpoint
liveBroadcasts.list (API YouTube Live Streaming) usando o cabeçalho HTTP Authorization: Bearer
pode ser semelhante ao exemplo a seguir. É necessário especificar seu próprio token de acesso:
GET /youtube/v3/liveBroadcasts?part=id%2Csnippet&mine=true HTTP/1.1 Host: www.googleapis.com Authorization: Bearer access_token
Veja 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/youtube/v3/liveBroadcasts?access_token=access_token&part=id%2Csnippet&mine=true
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/youtube/v3/liveBroadcasts?part=id%2Csnippet&mine=true
Ou, como alternativa, a opção de parâmetro de string de consulta:
curl https://www.googleapis.com/youtube/v3/liveBroadcasts?access_token=access_token&part=id%2Csnippet&mine=true
Exemplo completo
O exemplo a seguir mostra um objeto formatado em JSON com as transmissões ao vivo do canal do YouTube do usuário autenticado depois que ele autoriza o aplicativo a recuperar esses dados.
PHP
Para executar esse exemplo:
- No console de APIs, adicione o URL da máquina local à lista de URLs de redirecionamento. Por exemplo, adicione
http://localhost:8080. - Crie um novo diretório e mude para ele. Exemplo:
mkdir ~/php-oauth2-example cd ~/php-oauth2-example
- Instale a biblioteca de cliente da API do Google para PHP usando o Composer:
composer require google/apiclient:^2.15.0
- Crie os arquivos
index.phpeoauth2callback.phpcom o conteúdo a seguir. - Execute o exemplo com 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_secret.json'); // User granted permission as an access token is in the session. if (isset($_SESSION['access_token']) && $_SESSION['access_token']) { $client->setAccessToken($_SESSION['access_token']); // Check if user granted Drive permission if ($_SESSION['granted_scopes_dict']['Drive']) { echo "Drive feature is enabled."; echo "</br>"; $drive = new Drive($client); $files = array(); $response = $drive->files->listFiles(array()); foreach ($response->files as $file) { echo "File: " . $file->name . " (" . $file->id . ")"; echo "</br>"; } } else { echo "Drive feature is NOT enabled."; echo "</br>"; } // Check if user granted Calendar permission if ($_SESSION['granted_scopes_dict']['Calendar']) { echo "Calendar feature is enabled."; echo "</br>"; } else { echo "Calendar feature is NOT enabled."; echo "</br>"; } } else { // Redirect users to outh2call.php which redirects users to Google OAuth 2.0 $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(); // Required, call the setAuthConfig function to load authorization credentials from // client_secret.json file. $client->setAuthConfigFile('client_secret.json'); $client->setRedirectUri('http://' . $_SERVER['HTTP_HOST']. $_SERVER['PHP_SELF']); // Required, to set the scope value, call the addScope function. $client->addScope(Google_Service_YouTube::YOUTUBE_FORCE_SSL); // Enable incremental authorization. Recommended as a best practice. $client->setIncludeGrantedScopes(true); // 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"); // Generate a URL for authorization as it doesn't contain code and error if (!isset($_GET['code']) && !isset($_GET['error'])) { // Generate and set state value $state = bin2hex(random_bytes(16)); $client->setState($state); $_SESSION['state'] = $state; // Generate a url that asks permissions. $auth_url = $client->createAuthUrl(); header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL)); } // User authorized the request and authorization code is returned to exchange access and // refresh tokens. if (isset($_GET['code'])) { // Check the state value if (!isset($_GET['state']) || $_GET['state'] !== $_SESSION['state']) { die('State mismatch. Possible CSRF attack.'); } // Get access and refresh tokens (if access_type is offline) $token = $client->fetchAccessTokenWithAuthCode($_GET['code']); /** Save access and refresh token to the session variables. * ACTION ITEM: In a production app, you likely want to save the * refresh token in a secure persistent storage instead. */ $_SESSION['access_token'] = $token; $_SESSION['refresh_token'] = $client->getRefreshToken(); // Space-separated string of granted scopes if it exists, otherwise null. $granted_scopes = $client->getOAuth2Service()->getGrantedScope(); // Determine which scopes user granted and build a dictionary $granted_scopes_dict = [ 'Drive' => str_contains($granted_scopes, Google\Service\Drive::DRIVE_METADATA_READONLY), 'Calendar' => str_contains($granted_scopes, Google\Service\Calendar::CALENDAR_READONLY) ]; $_SESSION['granted_scopes_dict'] = $granted_scopes_dict; $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/'; header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL)); } // An error response e.g. error=access_denied if (isset($_GET['error'])) { echo "Error: ". $_GET['error']; } ?>
Python
Este exemplo usa o framework Flask. Ele
executa um aplicativo da Web em http://localhost:8080 que permite testar o fluxo do
OAuth 2.0. Se você acessar esse URL, vai encontrar cinco links:
- Chamar a API Drive:esse link leva a uma página que tenta executar um exemplo de solicitação de API se os usuários concederam a permissão. Se necessário, ele inicia o fluxo de autorização. Se a operação for bem-sucedida, a página vai mostrar a resposta da API.
- Página simulada para chamar a API Calendar:este link aponta para uma página simulada que tenta executar uma solicitação de API de amostra da API Calendar se os usuários concederem a permissão. Se necessário, ele inicia o fluxo de autorização. Se a operação for bem-sucedida, a página vai mostrar a 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 solicita permissão para enviar solicitações de API autorizadas em nome do usuário.
- Revogar credenciais atuais:esse link aponta para uma página que revoga as permissões que o usuário já concedeu ao aplicativo.
- Limpar credenciais da sessão do Flask:esse link limpa as credenciais de autorização armazenadas na sessão do Flask. Isso permite que você veja o que aconteceria se um usuário que já concedeu permissão ao seu app tentasse executar uma solicitação de API em uma nova sessão. Ela também permite que você veja a resposta da API que seu app receberia se um usuário tivesse revogado as permissões concedidas ao app, e o app ainda tentasse autorizar uma solicitação com um token de acesso revogado.
# -*- coding: utf-8 -*- import os import flask import json 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" # The OAuth 2.0 access scope allows for access to the # authenticated user's account and requires requests to use an SSL connection. SCOPES = ['https://www.googleapis.com/auth/youtube.force-ssl', 'https://www.googleapis.com/auth/calendar.readonly'] API_SERVICE_NAME = 'youtube' API_VERSION = 'v3' 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('/drive') def drive_api_request(): if 'credentials' not in flask.session: return flask.redirect('authorize') features = flask.session['features'] if features['drive']: # Load client secrets from the server-side file. with open(CLIENT_SECRETS_FILE, 'r') as f: client_config = json.load(f)['web'] # Load user-specific credentials from browser session storage. session_credentials = flask.session['credentials'] # Reconstruct the credentials object. credentials = google.oauth2.credentials.Credentials( refresh_token=session_credentials.get('refresh_token'), scopes=session_credentials.get('granted_scopes'), token=session_credentials.get('token'), client_id=client_config.get('client_id'), client_secret=client_config.get('client_secret'), token_uri=client_config.get('token_uri')) youtube = googleapiclient.discovery.build( API_SERVICE_NAME, API_VERSION, credentials=credentials) broadcasts = youtube.liveBroadcasts().list(part='id,snippet', mine=True).execute() # Save credentials back to session in case access token was refreshed. flask.session['credentials'] = credentials_to_dict(credentials) return flask.jsonify(**broadcasts) else: # User didn't authorize read-only Drive activity permission. return '<p>Drive feature is not enabled.</p>' @app.route('/calendar') def calendar_api_request(): if 'credentials' not in flask.session: return flask.redirect('authorize') features = flask.session['features'] if features['calendar']: # User authorized Calendar read permission. # Calling the APIs, etc. return ('<p>User granted the Google Calendar read permission. '+ 'This sample code does not include code to call Calendar</p>') else: # User didn't authorize Calendar read permission. # Update UX and application accordingly return '<p>Calendar feature is not enabled.</p>' @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 credentials = credentials_to_dict(credentials) flask.session['credentials'] = credentials # Check which scopes user granted features = check_granted_scopes(credentials) flask.session['features'] = features return flask.redirect('/') @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.') # Load client secrets from the server-side file. with open(CLIENT_SECRETS_FILE, 'r') as f: client_config = json.load(f)['web'] # Load user-specific credentials from the session. session_credentials = flask.session['credentials'] # Reconstruct the credentials object. credentials = google.oauth2.credentials.Credentials( refresh_token=session_credentials.get('refresh_token'), scopes=session_credentials.get('granted_scopes'), token=session_credentials.get('token'), client_id=client_config.get('client_id'), client_secret=client_config.get('client_secret'), token_uri=client_config.get('token_uri')) 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: # Clear the user's session credentials after successful revocation if 'credentials' in flask.session: del flask.session['credentials'] del flask.session['features'] 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, 'granted_scopes': credentials.granted_scopes} def check_granted_scopes(credentials): features = {} if 'https://www.googleapis.com/auth/youtube.force-ssl' in credentials['granted_scopes']: features['drive'] = True else: features['drive'] = False if 'https://www.googleapis.com/auth/calendar.readonly' in credentials['granted_scopes']: features['calendar'] = True else: features['calendar'] = False return features def print_index_table(): return ('<table>' + '<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="/drive">Call Drive API directly</a></td>' + '<td> Use stored credentials to call the API, you still might not be prompted to reauthorize ' + ' the application.</td></tr>' + '<tr><td><a href="/calendar">Call Calendar API directly</a></td>' + '<td> Use stored credentials to call the API, 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="/authorize">authorize</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' # This disables the requested scopes and granted scopes check. # If users only grant partial request, the warning would not be thrown. os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '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
Este exemplo usa o framework Sinatra.
require 'googleauth' require 'googleauth/web_user_authorizer' require 'googleauth/stores/redis_token_store' require 'google/apis/youtube_v3' require 'google/apis/calendar_v3' require 'sinatra' configure do enable :sessions # Required, call the from_file method to retrieve the client ID from a # client_secret.json file. set :client_id, Google::Auth::ClientId.from_file('/path/to/client_secret.json') # Required, scope value # Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar. scope = ['Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY', 'Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY'] # Required, Authorizers require a storage instance to manage long term persistence of # access and refresh tokens. set :token_store, Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new) # 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. set :callback_uri, '/oauth2callback' # 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. set :authorizer, Google::Auth::WebUserAuthorizer.new(settings.client_id, settings.scope, settings.token_store, callback_uri: settings.callback_uri) end get '/' do # NOTE: Assumes the user is already authenticated to the app user_id = request.session['user_id'] # Fetch stored credentials for the user from the given request session. # nil if none present credentials = settings.authorizer.get_credentials(user_id, request) if credentials.nil? # Generate a url that asks the user to authorize requested scope(s). # Then, redirect user to the url. redirect settings.authorizer.get_authorization_url(request: request) end # User authorized the request. Now, check which scopes were granted. if credentials.scope.include?(Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY) # User authorized read-only Drive activity permission. # Example of using Google Drive API to list filenames in user's Drive. youtube = Google::Apis::YoutubeV3::YouTubeService.new broadcasts = youtube.list_liveBroadcasts('id,snippet', mine: true) "<pre>#{JSON.pretty_generate(broadcasts.to_h)}</pre>" else # User didn't authorize read-only Drive activity permission. # Update UX and application accordingly end # Check if user authorized Calendar read permission. if credentials.scope.include?(Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY) # User authorized Calendar read permission. # Calling the APIs, etc. else # User didn't authorize Calendar read permission. # Update UX and application accordingly end end # Receive the callback from Google's OAuth 2.0 server. get '/oauth2callback' do # Handle the result of the oauth callback. Defers the exchange of the code by # temporarily stashing the results in the user's session. target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request) redirect target_url end
Node.js
Para executar esse exemplo:
-
No Console de APIs, adicione o URL da máquina local à lista de URLs de redirecionamento. Por exemplo, adicione
http://localhost. - Verifique se você tem a versão LTS de manutenção, LTS ativa ou atual do Node.js instalada.
-
Crie um novo diretório e mude para ele. Exemplo:
mkdir ~/nodejs-oauth2-example cd ~/nodejs-oauth2-example
-
Instale a
biblioteca de cliente da API do Google
para Node.js usando o npm:
npm install googleapis
-
Crie os arquivos
main.jscom o conteúdo abaixo. -
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 two non-Sign-In scopes: Read-only Drive activity and Google Calendar. const scopes = [ 'https://www.googleapis.com/auth/youtube.force-ssl', 'https://www.googleapis.com/auth/calendar.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 and Google Calendar 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; // User authorized the request. Now, check which scopes were granted. if (tokens.scope.includes('https://www.googleapis.com/auth/youtube.force-ssl')) { // User authorized read-only Drive activity permission. // 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.'); } }); } else { // User didn't authorize read-only Drive activity permission. // Update UX and application accordingly } // Check if user authorized Calendar read permission. if (tokens.scope.includes('https://www.googleapis.com/auth/calendar.readonly')) { // User authorized Calendar read permission. // Calling the APIs, etc. } else { // User didn't authorize Calendar read permission. // Update UX and application accordingly } } }); // 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(8080); } main().catch(console.error);
HTTP/REST
Este exemplo em Python usa o framework Flask e a biblioteca Requests para demonstrar o fluxo da Web do OAuth 2.0. Recomendamos usar a biblioteca de cliente da API do Google para Python nesse fluxo. O exemplo na guia do Python usa a biblioteca de cliente.
import json import flask import requests app = flask.Flask(__name__) # To get these credentials (CLIENT_ID CLIENT_SECRET) and for your application, visit # https://console.cloud.google.com/apis/credentials. CLIENT_ID = '123456789.apps.googleusercontent.com' CLIENT_SECRET = 'abc123' # Read from a file or environmental variable in a real app # Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar. SCOPE = 'https://www.googleapis.com/auth/youtube.force-ssl https://www.googleapis.com/auth/calendar.readonly' # 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. 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: # User authorized the request. Now, check which scopes were granted. if 'https://www.googleapis.com/auth/drive.metadata.readonly' in credentials['scope']: # User authorized read-only Drive activity permission. # Example of using Google Drive API to list filenames in user's Drive. headers = {'Authorization': 'Bearer {}'.format(credentials['access_token'])} req_uri = 'https://youtube.googleapis.com/youtube/v3/liveBroadcasts' r = requests.get(req_uri, headers=headers).text else: # User didn't authorize read-only Drive activity permission. # Update UX and application accordingly r = 'User did not authorize Drive permission.' # Check if user authorized Calendar read permission. if 'https://www.googleapis.com/auth/calendar.readonly' in credentials['scope']: # User authorized Calendar read permission. # Calling the APIs, etc. r += 'User authorized Calendar permission.' else: # User didn't authorize Calendar read permission. # Update UX and application accordingly r += 'User did not authorize Calendar permission.' return r @app.route('/oauth2callback') def oauth2callback(): if 'code' not in flask.request.args: state = str(uuid.uuid4()) flask.session['state'] = state # Generate a url that asks permissions for the Drive activity # and Google Calendar scope. Then, redirect user to the url. 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'} # Exchange authorization code for access and refresh tokens (if access_type is offline) 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 de URI de redirecionamento
O Google aplica as seguintes regras de validação para redirecionar URIs para ajudar os desenvolvedores a manter os aplicativos seguros. Os URIs de redirecionamento precisam seguir estas regras. Consulte a seção 3 da RFC 3986 para ver a definição de domínio, host, caminho, consulta, esquema e informações do usuário, usados nessas regras.
| Regras de validação | |
|---|---|
| Esquema |
Os URIs de redirecionamento precisam usar o esquema HTTPS, não HTTP simples. Os URIs de host local (incluindo URIs de endereço IP de host local) estão isentos dessa regra. |
| Host |
Os hosts não podem ser endereços IP brutos. Os endereços IP do localhost estão isentos dessa regra. |
| Domínio |
“googleusercontent.com”.goo.gl), a menos que
o app seja o proprietário do domínio. Além disso, se um app que possui um domínio de encurtador optar por
redirecionar para esse domínio, o URI de redirecionamento precisará conter
“/google-callback/” no caminho ou terminar com
“/google-callback”. |
| Userinfo |
Os URIs de redirecionamento não podem conter o subcomponente userinfo. |
| Caminho |
Os URIs de redirecionamento não podem conter uma travessia de caminho (também chamada de retrocesso de diretório),
que é representada por um |
| Consulta |
Os URIs de redirecionamento não podem conter redirecionamentos abertos. |
| Fragmentos |
Os URIs de redirecionamento não podem conter o componente de fragmento. |
| Caracteres |
Os URIs de redirecionamento não podem conter determinados caracteres, incluindo:
|
Autorização incremental
No protocolo OAuth 2.0, seu app solicita autorização para acessar recursos, que são identificados por escopos. É considerada uma prática recomendada de experiência do usuário solicitar autorização para recursos no momento em que você precisa deles. Para permitir 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, retornar um código de autorização que pode ser trocado por um token que contém todos os escopos que o usuário concedeu ao projeto.
Por exemplo, imagine que um app recupera dados do canal do YouTube do usuário autenticado e também
permite que um usuário recupere dados do YouTube Analytics por um fluxo especial. Nesse caso, no momento do login, o app pode solicitar acesso apenas ao escopo
https://www.googleapis.com/auth/youtube.force-ssl. No entanto, se o usuário tentar acessar os dados do Analytics para o canal dele, o app também poderá
solicitar acesso ao escopo https://www.googleapis.com/auth/yt-analytics.readonly.
Para implementar a autorização incremental, conclua o fluxo normal para solicitar um token de acesso, mas verifique se a solicitação de autorização inclui escopos concedidos anteriormente. Essa abordagem evita que o app precise 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 na nova autorização combinada.
- Quando você usa o token de atualização para a autorização combinada para receber um token de acesso, o
token de acesso representa a autorização combinada e pode ser usado para qualquer um dos
valores de
scopeincluídos na resposta. - A autorização combinada inclui todos os escopos que o usuário concedeu ao projeto da API, mesmo que as concessões tenham sido solicitadas de clientes diferentes. Por exemplo, se um usuário concedeu acesso a um escopo usando o cliente para computador de um aplicativo e, em seguida, concedeu outro escopo ao mesmo aplicativo 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 os escopos dessa autorização em nome do usuário associado será revogado simultaneamente.
Os exemplos de código específicos para cada linguagem na Etapa 1: definir o redirecionamento de autorização para o servidor OAuth 2.0 do Google usam a autorização incremental. Os exemplos de código a seguir também mostram o código que você precisa adicionar para usar a autorização incremental.
PHP
$client->setIncludeGrantedScopes(true);Python
No Python, defina o argumento de palavra-chave include_granted_scopes como true para
garantir que uma solicitação de autorização inclua escopos concedidos anteriormente. É muito provável que
include_granted_scopes não seja o único argumento de palavra-chave que você vai definir, 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
Neste exemplo, o aplicativo de chamada solicita acesso para recuperar os dados do YouTube do usuário, além de qualquer outro acesso que o usuário já tenha concedido ao aplicativo.
GET https://accounts.google.com/o/oauth2/v2/auth?
scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.force-ssl&
access_type=offline&
state=security_token%3D138rk%3Btarget_url%3Dhttp...index&
redirect_uri=http%3A%2F%2Flocalhost%2Foauth2callback&
response_type=code&
client_id=client_id&
include_granted_scopes=true
Refresh an access token (offline access)
Access tokens periodically expire and become invalid credentials for a related API request. You can refresh an access token without prompting the user for permission (including when the user is not present) if you requested offline access to the scopes associated with the token.
- If you use a Google API Client Library, the client object refreshes the access token as needed as long as you configure that object for offline access.
- If you are not using a client library, you need to set the
access_typeHTTP query parameter toofflinewhen redirecting the user to Google's OAuth 2.0 server. In that case, Google's authorization server returns a refresh token when you exchange an authorization code for an access token. Then, if the access token expires (or at any other time), you can use a refresh token to obtain a new access token.
Requesting offline access is a requirement for any application that needs to access a Google
API when the user is not present. For example, an app that performs backup services or
executes actions at predetermined times needs to be able to refresh its access token when the
user is not present. The default style of access is called online.
Server-side web applications, installed applications, and devices all obtain refresh tokens during the authorization process. Refresh tokens are not typically used in client-side (JavaScript) web applications.
PHP
If your application needs offline access to a Google API, set the API client's access type to
offline:
$client->setAccessType("offline");
Depois que um usuário concede acesso off-line aos escopos solicitados, você pode continuar usando o cliente da API para acessar as APIs do Google em nome do usuário quando ele estiver off-line. O objeto do cliente vai atualizar o token de acesso conforme necessário.
Python
No Python, defina o argumento de palavra-chave access_type como offline para garantir
que você possa atualizar o token de acesso sem precisar solicitar novamente a permissão
do usuário. É muito provável que access_type não seja o único argumento de palavra-chave
que você vai definir, 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')
Depois que um usuário concede acesso off-line aos escopos solicitados, você pode continuar usando o cliente da API para acessar as APIs do Google em nome do usuário quando ele estiver off-line. O objeto do cliente vai atualizar o token de acesso conforme necessário.
Ruby
Se o 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 concede acesso off-line aos escopos solicitados, você pode continuar usando o cliente da API para acessar as APIs do Google em nome do usuário quando ele estiver off-line. O objeto do cliente vai atualizar o token de acesso conforme necessário.
Node.js
Se o 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 concede acesso off-line aos escopos solicitados, você pode continuar usando o cliente da API para acessar as APIs do Google em nome do usuário quando ele estiver off-line. O objeto do cliente vai atualizar o token de acesso conforme necessário.
Os tokens de acesso expiram. Essa biblioteca vai usar automaticamente um token de atualização para receber um novo token de acesso se ele estiver prestes a expirar. Uma maneira fácil de garantir que você sempre armazene os tokens mais recentes é usar o evento de 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 tokens só ocorre na primeira autorização, e é necessário definir o
access_type como offline ao chamar o método generateAuthUrl
para receber o token de atualização. Se você já tiver concedido as permissões necessárias ao app
sem definir as restrições adequadas para receber um token de atualização, será necessário
autorizar novamente o aplicativo para receber um novo token de atualização.
Para definir o refresh_token posteriormente, use o método setCredentials:
oauth2Client.setCredentials({ refresh_token: `STORED_REFRESH_TOKEN` });
Depois que o cliente tiver um token de atualização, os tokens de acesso serão adquiridos e atualizados automaticamente na próxima chamada para a API.
HTTP/REST
Para atualizar um token de acesso, seu aplicativo envia uma solicitação HTTPS POST
ao servidor de autorização do Google (https://oauth2.googleapis.com/token) que
inclui os seguintes parâmetros no corpo da solicitação:
| Nome | Valor |
|---|---|
client_id |
O ID do cliente recebido do Console de APIs. |
client_secret |
Opcional
A chave secreta do cliente recebida do Console de APIs. |
grant_type |
Conforme
definido na
especificação do 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ódigo de autorização. |
Embora o uso do DPoP seja opcional, ele é recomendado para aumentar a segurança. Para usar o DPoP com um token de atualização, seu aplicativo precisa gerar um novo JWT de prova de DPoP exclusivo para cada solicitação ao endpoint do token. Essa prova precisa ser assinada com a mesma chave privada usada durante a troca inicial do código de autorização. O aplicativo adiciona a prova como um cabeçalho da solicitação HTTP.
| Cabeçalho | Obrigatório | Descrição |
|---|---|---|
DPoP |
Opcional | Uma prova de DPoP é um JWT que comprova a
posse de uma chave privada. Este é um cabeçalho, não um parâmetro. Se fornecidos, os tokens retornados
serão vinculados a essa chave. Uma nova prova exclusiva precisa ser gerada para cada solicitação e
precisa incluir declarações htm (método HTTP) e htu (URI HTTP) que
correspondam à solicitaçã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 DPoP: DPOP_PROOF_JWT client_id=your_client_id& refresh_token=refresh_token& grant_type=refresh_token
Para usar o DPoP com um token de atualização, é necessário gerar um JWT de prova de DPoP novo e exclusivo para a solicitação. Consulte Criar uma prova de DPoP para instruções detalhadas sobre como gerar o par de chaves e criar o JWT.
Uma troca bem-sucedida é indicada por uma resposta 200 OK
que contém um novo token de acesso. Quando o DPoP é usado, o
token_type é Bearer. Uma resposta bem-sucedida confirma
que a prova de DPoP para o token de atualização foi aceita. O Google também pode retornar um novo
cabeçalho HTTP DPoP-Nonce na resposta. Se isso acontecer, seu cliente precisará armazenar em cache esse
nonce e incluí-lo na declaração nonce da prova de DPoP em solicitações subsequentes.
Uma falha na troca ocorre se o cabeçalho DPoP estiver ausente, for inválido ou usar uma chave incorreta. Para detalhes sobre códigos de erro específicos do DPoP e como lidar com nonces, consulte Falha na troca.
O snippet a seguir mostra um exemplo de cabeçalhos de resposta e corpo bem-sucedidos quando o DPoP é usado:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
DPoP-Nonce: AN3XwJjZsjnb0ZuWkRlek8QU7wY-Zhf-5IP6tO0tORz0KgtDT1Bo8FX-w4nz3r5lnepI
{
"access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
"expires_in": 3920,
"scope": "https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/calendar.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 outro por usuário em todos os clientes. Salve os tokens de atualização no armazenamento de longo prazo e continue usando-os enquanto forem válidos. Se o aplicativo solicitar muitos tokens de atualização, ele poderá atingir esses limites. Nesse caso, os tokens de atualização mais antigos vão parar de funcionar.
Revogação de token
Em alguns casos, um usuário pode querer revogar o acesso concedido a um aplicativo. Para revogar o acesso, o usuário precisa acessar as Configurações da conta. Consulte a seção Remover o acesso de sites ou apps de terceiros com acesso à sua conta no documento de suporte 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 em casos em que um usuário cancela a inscrição, remove um aplicativo ou os recursos da API exigidos por um app 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.
PHP
Para revogar um token de maneira programática, chame revokeToken():
$client->revokeToken();Python
Para revogar um token de forma programática, faça uma solicitação para
https://oauth2.googleapis.com/revoke que inclua o token como um parâmetro e defina 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 maneira programática, faça uma solicitação HTTP para o endpoint oauth2.revoke:
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 um token 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, o código de status da resposta será
200. Para condições de erro, um código de status 400 é retornado junto com um código do erro.
Node.js
Para revogar um token de maneira programática, faça uma solicitação POST HTTPS para o endpoint /revoke:
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 de token pode ser um token de acesso ou um token 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, o código de status da resposta será
200. Para condições de erro, um código de status 400 é retornado junto com um código do erro.
HTTP/REST
Para revogar um token de maneira programática, 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 um token 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 com um código do erro.
Acesso baseado no horário
O acesso baseado em tempo permite que um usuário conceda ao app acesso aos dados dele por um período limitado para concluir uma ação. O acesso por tempo limitado está disponível em alguns produtos do Google durante o fluxo de consentimento, permitindo que os usuários concedam acesso por um período limitado. Um exemplo é a API Data Portability, que permite uma transferência única de dados.
Quando um usuário concede ao aplicativo acesso com base no tempo, o token de atualização expira após a
duração especificada. Os tokens de atualização podem ser invalidados antes em circunstâncias específicas. Consulte estes casos para mais detalhes. O campo refresh_token_expires_in retornado na resposta da troca de código de autorização representa o tempo restante até que o token de atualização expire nesses casos.
Implementar a Proteção entre Contas
Outra etapa que você deve seguir para proteger as contas dos usuários é implementar a Proteção entre Contas usando o serviço de Proteção entre Contas do Google. Esse serviço permite que você se inscreva para receber notificações de ocorrências de segurança que fornecem informações ao seu aplicativo sobre mudanças importantes na conta do usuário. Em seguida, você pode usar as informações para entrar em ação, dependendo de como decidir responder aos eventos.
Alguns exemplos de tipos de evento enviados ao seu app pelo serviço de Proteção entre Contas do Google são:
-
https://schemas.openid.net/secevent/risc/event-type/sessions-revoked -
https://schemas.openid.net/secevent/oauth/event-type/token-revoked -
https://schemas.openid.net/secevent/risc/event-type/account-disabled
Consulte a página Proteger contas de usuário com a Proteção entre Contas para saber como implementar a Proteção entre Contas e conferir a lista completa de eventos disponíveis.