Para usar os serviços do Google em nome de um usuário quando ele estiver off-line, use um fluxo híbrido do lado do servidor em que um usuário autoriza seu app do lado do cliente usando o cliente da API JavaScript e você envia um código de autorização único especial para o servidor. O servidor troca esse código de uso único para adquirir os próprios tokens de acesso e de atualização do Google para que ele possa fazer as próprias chamadas de API, o que pode ser feito enquanto o usuário está off-line. Esse fluxo de código único tem vantagens de segurança em relação a um fluxo puro do lado do servidor e ao envio de tokens de acesso para o servidor.
O fluxo de login para receber um token de acesso para seu aplicativo do lado do servidor é ilustrado abaixo.
Os códigos únicos têm várias vantagens de segurança. Com os códigos, o Google fornece tokens diretamente ao seu servidor sem intermediários. Embora não recomendemos vazar códigos, eles são muito difíceis de usar sem a chave secreta do cliente. Mantenha a chave secreta do cliente em segredo.
Implementar o fluxo de código único
O botão do Login do Google fornece um token de acesso e um código de autorização. Esse código é um código único que seu servidor pode trocar com os servidores do Google por um token de acesso.
O exemplo de código abaixo demonstra como fazer o fluxo de código único.
Para autenticar o login do Google com o fluxo de código único, você precisa:
Etapa 1: criar um ID e uma chave secreta do cliente
Para criar um ID e um segredo de cliente, crie um projeto do Console de APIs do Google, configure um ID de cliente OAuth e registre suas origens JavaScript:
Vá para o Console de APIs do Google.
No menu suspenso, selecione um projeto existente ou crie um novo clicando em Create a new project.
Na barra lateral, em "APIs e serviços", selecione Credenciais e clique em Configurar tela de consentimento.
Escolha um endereço de e-mail, especifique um nome de produto e pressione Salvar.
Na guia Credenciais, selecione a lista suspensa Criar credenciais e escolha ID do cliente do OAuth.
Em Tipo de aplicativo, selecione Aplicativo da Web.
Registre as origens de onde o app pode acessar as APIs do Google, conforme mostrado abaixo. Uma origem é uma combinação exclusiva de protocolo, nome do host e porta.
No campo Origens JavaScript autorizadas, insira a origem do app. É possível inserir várias origens para permitir que o app seja executado em diferentes protocolos, domínios ou subdomínios. Não é possível usar caracteres curinga. No exemplo abaixo, o segundo URL pode ser um URL de produção.
http://localhost:8080 https://myproductionurl.example.com
O campo URI de redirecionamento autorizado não exige um valor. Os URIs de redirecionamento não são usados com APIs JavaScript.
Pressione o botão Criar.
Na caixa de diálogo Cliente OAuth, copie o ID do cliente. O ID do cliente permite que seu app acesse as APIs do Google ativadas.
Etapa 2: incluir a biblioteca da plataforma Google na sua página
Inclua os scripts a seguir que demonstram uma função anônima que
insere um script no DOM desta página da Web index.html
.
<!-- The top of file index.html -->
<html itemscope itemtype="http://schema.org/Article">
<head>
<!-- BEGIN Pre-requisites -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js">
</script>
<script src="https://apis.google.com/js/client:platform.js?onload=start" async defer>
</script>
<!-- END Pre-requisites -->
Etapa 3: inicializar o objeto GoogleAuth
Carregue a biblioteca auth2 e chame gapi.auth2.init()
para inicializar o
objeto GoogleAuth
. Especifique o ID do cliente e os escopos que você quer solicitar
ao chamar init()
.
<!-- Continuing the <head> section -->
<script>
function start() {
gapi.load('auth2', function() {
auth2 = gapi.auth2.init({
client_id: 'YOUR_CLIENT_ID.apps.googleusercontent.com',
// Scopes to request in addition to 'profile' and 'email'
//scope: 'additional_scope'
});
});
}
</script>
</head>
<body>
<!-- ... -->
</body>
</html>
Etapa 4: adicionar o botão de login à página
Adicione o botão de login à sua página da Web e anexe um manipulador de cliques para chamar
grantOfflineAccess()
e iniciar o fluxo de código único.
<!-- Add where you want your sign-in button to render -->
<!-- Use an image that follows the branding guidelines in a real app -->
<button id="signinButton">Sign in with Google</button>
<script>
$('#signinButton').click(function() {
// signInCallback defined in step 6.
auth2.grantOfflineAccess().then(signInCallback);
});
</script>
Etapa 5: fazer login do usuário
O usuário clica no botão de login e concede ao app acesso às permissões
que você solicitou. Em seguida, a função de callback especificada no método
grantOfflineAccess().then()
recebe um objeto JSON com um
código de autorização. Exemplo:
{"code":"4/yU4cQZTMnnMtetyFcIWNItG32eKxxxgXXX-Z4yyJJJo.4qHskT-UtugceFc0ZRONyF4z7U4UmAI"}
Etapa 6: enviar o código de autorização para o servidor
O code
é o código único que o servidor pode trocar pelo próprio
token de acesso e de atualização. Só é possível receber um token de atualização depois que o
usuário receber uma caixa de diálogo de autorização solicitando acesso off-line.
Se você tiver especificado o select-account
prompt
na
OfflineAccessOptions
na etapa 4, será necessário armazenar o token de atualização que você extrair para uso posterior,
porque as trocas subsequentes vão retornar null
para o token de atualização. Esse fluxo
oferece mais segurança do que o fluxo padrão do OAuth 2.0.
Os tokens de acesso são sempre retornados com a troca de um código de autorização válido.
O script a seguir define uma função de callback para o botão de login. Quando um login é bem-sucedido, a função armazena o token de acesso para uso do lado do cliente e envia o código único para o servidor no mesmo domínio.
<!-- Last part of BODY element in file index.html -->
<script>
function signInCallback(authResult) {
if (authResult['code']) {
// Hide the sign-in button now that the user is authorized, for example:
$('#signinButton').attr('style', 'display: none');
// Send the code to the server
$.ajax({
type: 'POST',
url: 'http://example.com/storeauthcode',
// Always include an `X-Requested-With` header in every AJAX request,
// to protect against CSRF attacks.
headers: {
'X-Requested-With': 'XMLHttpRequest'
},
contentType: 'application/octet-stream; charset=utf-8',
success: function(result) {
// Handle or verify the server response.
},
processData: false,
data: authResult['code']
});
} else {
// There was an error.
}
}
</script>
Etapa 7: trocar o código de autorização por um token de acesso
No servidor, troque o código de autenticação por tokens de acesso e de atualização. Use o token de acesso para chamar as APIs do Google em nome do usuário e, como opção, armazene o token de atualização para receber um novo token de acesso quando ele expirar.
Se você solicitou acesso ao perfil, também receberá um token de ID que contém informações básicas do perfil do usuário.
Exemplo:
Java
// (Receive authCode via HTTPS POST) if (request.getHeader("X-Requested-With") == null) { // Without the `X-Requested-With` header, this request could be forged. Aborts. } // Set path to the Web application client_secret_*.json file you downloaded from the // Google API Console: https://console.cloud.google.com/apis/credentials // You can also find your Web application client ID and client secret from the // console and specify them directly when you create the GoogleAuthorizationCodeTokenRequest // object. String CLIENT_SECRET_FILE = "/path/to/client_secret.json"; // Exchange auth code for access token GoogleClientSecrets clientSecrets = GoogleClientSecrets.load( JacksonFactory.getDefaultInstance(), new FileReader(CLIENT_SECRET_FILE)); GoogleTokenResponse tokenResponse = new GoogleAuthorizationCodeTokenRequest( new NetHttpTransport(), JacksonFactory.getDefaultInstance(), "https://oauth2.googleapis.com/token", clientSecrets.getDetails().getClientId(), clientSecrets.getDetails().getClientSecret(), authCode, REDIRECT_URI) // Specify the same redirect URI that you use with your web // app. If you don't have a web version of your app, you can // specify an empty string. .execute(); String accessToken = tokenResponse.getAccessToken(); // Use access token to call API GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken); Drive drive = new Drive.Builder(new NetHttpTransport(), JacksonFactory.getDefaultInstance(), credential) .setApplicationName("Auth Code Exchange Demo") .build(); File file = drive.files().get("appfolder").execute(); // Get profile info from ID token GoogleIdToken idToken = tokenResponse.parseIdToken(); GoogleIdToken.Payload payload = idToken.getPayload(); String userId = payload.getSubject(); // Use this value as a key to identify a user. String email = payload.getEmail(); boolean emailVerified = Boolean.valueOf(payload.getEmailVerified()); String name = (String) payload.get("name"); String pictureUrl = (String) payload.get("picture"); String locale = (String) payload.get("locale"); String familyName = (String) payload.get("family_name"); String givenName = (String) payload.get("given_name");
Python
from apiclient import discovery import httplib2 from oauth2client import client # (Receive auth_code by HTTPS POST) # If this request does not have `X-Requested-With` header, this could be a CSRF if not request.headers.get('X-Requested-With'): abort(403) # Set path to the Web application client_secret_*.json file you downloaded from the # Google API Console: https://console.cloud.google.com/apis/credentials CLIENT_SECRET_FILE = '/path/to/client_secret.json' # Exchange auth code for access token, refresh token, and ID token credentials = client.credentials_from_clientsecrets_and_code( CLIENT_SECRET_FILE, ['https://www.googleapis.com/auth/drive.appdata', 'profile', 'email'], auth_code) # Call Google API http_auth = credentials.authorize(httplib2.Http()) drive_service = discovery.build('drive', 'v3', http=http_auth) appfolder = drive_service.files().get(fileId='appfolder').execute() # Get profile info from ID token userid = credentials.id_token['sub'] email = credentials.id_token['email']