Autenticar com um back-end usando tokens de ID

O cliente de login com um toque recupera um token de ID do Google quando o usuário seleciona uma Conta do Google. Um token de ID é uma declaração assinada da identidade de um usuário que também contém as informações básicas do perfil dele, possivelmente incluindo um endereço de e-mail verificado pelo Google.

Quando os tokens de ID estiverem disponíveis, você poderá usá-los para autenticar com segurança no back-end do app ou para inscrever automaticamente o usuário em uma nova conta sem precisar verificar o endereço de e-mail.

Para fazer login ou inscrever um usuário com um token de ID, envie o token para o back-end do app. No back-end, verifique o token usando uma biblioteca de cliente da API do Google ou uma biblioteca JWT de uso geral. Se o usuário não tiver feito login no seu app com essa Conta do Google antes, crie uma nova conta.

Se você tiver optado por usar um valor de uso único para ajudar a evitar ataques repetidos, utilize getNonce para enviá-lo com o token de ID ao servidor de back-end e verifique o valor esperado. É altamente recomendável usar um valor de uso único para melhorar a segurança do usuário.

Receber um token de ID do objeto de credenciais

Depois de recuperar as credenciais de um usuário, verifique se o objeto de credenciais inclui um token de ID. Em caso afirmativo, envie-o para o back-end.

Java

public class YourActivity extends AppCompatActivity {

  // ...
  private static final int REQ_ONE_TAP = 2;  // Can be any integer unique to the Activity.
  private boolean showOneTapUI = true;
  // ...

  @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
      super.onActivityResult(requestCode, resultCode, data);

      switch (requestCode) {
          case REQ_ONE_TAP:
              try {
                  SignInCredential credential = oneTapClient.getSignInCredentialFromIntent(data);
                  String idToken = credential.getGoogleIdToken();
                  if (idToken !=  null) {
                      // Got an ID token from Google. Use it to authenticate
                      // with your backend.
                      Log.d(TAG, "Got ID token.");
                  }
              } catch (ApiException e) {
                  // ...
              }
              break;
      }
  }
}

Kotlin

class YourActivity : AppCompatActivity() {

    // ...
    private val REQ_ONE_TAP = 2  // Can be any integer unique to the Activity
    private var showOneTapUI = true
    // ...

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        when (requestCode) {
             REQ_ONE_TAP -> {
                try {
                    val credential = oneTapClient.getSignInCredentialFromIntent(data)
                    val idToken = credential.googleIdToken
                    when {
                        idToken != null -> {
                            // Got an ID token from Google. Use it to authenticate
                            // with your backend.
                            Log.d(TAG, "Got ID token.")
                        }
                        else -> {
                            // Shouldn't happen.
                            Log.d(TAG, "No ID token!")
                        }
                    }
                } catch (e: ApiException) {
                    // ...
            }
        }
    }
    // ...
}

Verificar a integridade do token de ID

Depois de receber o token de ID por HTTPS POST, verifique a integridade do token.

Para verificar se o token é válido, verifique se os critérios a seguir foram atendidos:

  • O token de ID é assinado corretamente pelo Google. Use as chaves públicas do Google (disponíveis no formato JWK ou PEM) para verificar a assinatura do token. Essas chaves são alternadas regularmente. Examine o cabeçalho Cache-Control na resposta para determinar quando é preciso recuperá-las novamente.
  • O valor de aud no token de ID é igual a um dos IDs do cliente do seu app. Essa verificação é necessária para evitar que tokens de ID emitidos para um app malicioso seja usado para acessar dados sobre o mesmo usuário no servidor de back-end do app.
  • O valor de iss no token de ID é igual a accounts.google.com ou https://accounts.google.com.
  • O prazo de validade (exp) do token de ID não passou.
  • Se você precisar validar se o token de ID representa uma conta de organização do Google Workspace ou do Cloud, verifique a declaração hd, que indica o domínio hospedado do usuário. Precisa ser usado para restringir o acesso a um recurso apenas a membros de determinados domínios. A ausência dessa declaração indica que a conta não pertence a um domínio hospedado pelo Google.

Em vez de escrever seu próprio código para realizar essas etapas de verificação, é altamente recomendável usar uma biblioteca de cliente da API do Google para sua plataforma ou uma biblioteca JWT de uso geral. Para desenvolvimento e depuração, é possível chamar nosso endpoint de validação tokeninfo.

Usar uma biblioteca de cliente das APIs do Google

Usar uma das bibliotecas de cliente das APIs do Google (por exemplo, Java, Node.js, PHP, Python) é a maneira recomendada de validar os tokens de ID do Google em um ambiente de produção.

Java

Para validar um token de ID em Java, use o objeto GoogleIdTokenVerifier. Exemplo:

import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;

...

GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
    // Specify the CLIENT_ID of the app that accesses the backend:
    .setAudience(Collections.singletonList(CLIENT_ID))
    // Or, if multiple clients access the backend:
    //.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3))
    .build();

// (Receive idTokenString by HTTPS POST)

GoogleIdToken idToken = verifier.verify(idTokenString);
if (idToken != null) {
  Payload payload = idToken.getPayload();

  // Print user identifier
  String userId = payload.getSubject();
  System.out.println("User ID: " + userId);

  // Get profile information from payload
  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");

  // Use or store profile information
  // ...

} else {
  System.out.println("Invalid ID token.");
}

O método GoogleIdTokenVerifier.verify() verifica a assinatura JWT, as declarações aud, iss e exp.

Se você precisar validar que o token de ID representa uma conta de organização do Google Workspace ou do Cloud, verifique a declaração hd conferindo o nome de domínio retornado pelo método Payload.getHostedDomain(). O domínio da declaração email não é suficiente para garantir que a conta seja gerenciada por um domínio ou organização.

Node.js

Para validar um token de ID no Node.js, use a Biblioteca Google Auth para Node.js. Instale a biblioteca:

npm install google-auth-library --save
. Em seguida, chame a função verifyIdToken(). Exemplo:

const {OAuth2Client} = require('google-auth-library');
const client = new OAuth2Client();
async function verify() {
  const ticket = await client.verifyIdToken({
      idToken: token,
      audience: CLIENT_ID,  // Specify the CLIENT_ID of the app that accesses the backend
      // Or, if multiple clients access the backend:
      //[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]
  });
  const payload = ticket.getPayload();
  const userid = payload['sub'];
  // If request specified a G Suite domain:
  // const domain = payload['hd'];
}
verify().catch(console.error);

A função verifyIdToken verifica a assinatura JWT, a declaração aud, a declaração exp e a declaração iss.

Se você precisar validar se o token de ID representa uma conta de organização do Google Workspace ou do Cloud, verifique a declaração hd, que indica o domínio hospedado do usuário. Precisa ser usado para restringir o acesso a um recurso apenas a membros de determinados domínios. A ausência dessa declaração indica que a conta não pertence a um domínio hospedado pelo Google.

PHP

Para validar um token de ID em PHP, use a biblioteca de cliente de APIs do Google para PHP. Instale a biblioteca (por exemplo, usando o Composer):

composer require google/apiclient
. Em seguida, chame a função verifyIdToken(). Exemplo:

require_once 'vendor/autoload.php';

// Get $id_token via HTTPS POST.

$client = new Google_Client(['client_id' => $CLIENT_ID]);  // Specify the CLIENT_ID of the app that accesses the backend
$payload = $client->verifyIdToken($id_token);
if ($payload) {
  $userid = $payload['sub'];
  // If request specified a G Suite domain:
  //$domain = $payload['hd'];
} else {
  // Invalid ID token
}

A função verifyIdToken verifica a assinatura JWT, a declaração aud, a declaração exp e a declaração iss.

Se você precisar validar se o token de ID representa uma conta de organização do Google Workspace ou do Cloud, verifique a declaração hd, que indica o domínio hospedado do usuário. Precisa ser usado para restringir o acesso a um recurso apenas a membros de determinados domínios. A ausência dessa declaração indica que a conta não pertence a um domínio hospedado pelo Google.

Python

Para validar um token de ID em Python, use a função verify_oauth2_token. Exemplo:

from google.oauth2 import id_token
from google.auth.transport import requests

# (Receive token by HTTPS POST)
# ...

try:
    # Specify the CLIENT_ID of the app that accesses the backend:
    idinfo = id_token.verify_oauth2_token(token, requests.Request(), CLIENT_ID)

    # Or, if multiple clients access the backend server:
    # idinfo = id_token.verify_oauth2_token(token, requests.Request())
    # if idinfo['aud'] not in [CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]:
    #     raise ValueError('Could not verify audience.')

    # If auth request is from a G Suite domain:
    # if idinfo['hd'] != GSUITE_DOMAIN_NAME:
    #     raise ValueError('Wrong hosted domain.')

    # ID token is valid. Get the user's Google Account ID from the decoded token.
    userid = idinfo['sub']
except ValueError:
    # Invalid token
    pass

A função verify_oauth2_token verifica a assinatura JWT, a declaração aud e a declaração exp. Também é preciso verificar a declaração hd (se aplicável) examinando o objeto retornado por verify_oauth2_token. Se vários clientes acessarem o servidor de back-end, verifique também a declaração aud manualmente.

Como chamar o endpoint tokeninfo

Uma maneira fácil de validar uma assinatura de token de ID para depuração é usar o endpoint tokeninfo. Chamar esse endpoint envolve uma outra solicitação de rede que faz a maior parte da validação enquanto você testa a validação adequada e a extração de payload no seu próprio código. Ele não é adequado para uso em código de produção, porque as solicitações podem ser limitadas ou sujeitas a erros intermitentes.

Para validar um token de ID usando o endpoint tokeninfo, faça uma solicitação HTTPS POST ou GET para o endpoint e transmita seu token de ID no parâmetro id_token. Por exemplo, para validar o token "XYZ123", faça a seguinte solicitação GET:

https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123

Se o token estiver assinado corretamente e as declarações iss e exp tiverem os valores esperados, você receberá uma resposta HTTP 200, em que o corpo contém as declarações de token de ID formatado em JSON. Veja um exemplo de resposta:

{
 // These six fields are included in all Google ID Tokens.
 "iss": "https://accounts.google.com",
 "sub": "110169484474386276334",
 "azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "iat": "1433978353",
 "exp": "1433981953",

 // These seven fields are only included when the user has granted the "profile" and
 // "email" OAuth scopes to the application.
 "email": "testuser@gmail.com",
 "email_verified": "true",
 "name" : "Test User",
 "picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg",
 "given_name": "Test",
 "family_name": "User",
 "locale": "en"
}

Se você precisar confirmar que o token de ID representa uma conta do Google Workspace, verifique a declaração hd, que indica o domínio hospedado do usuário. Precisa ser usado para restringir o acesso a um recurso apenas a membros de determinados domínios. A ausência dessa declaração indica que a conta não pertence a um domínio hospedado do Google Workspace.

Criar uma conta ou sessão

Depois de verificar o token, verifique se o usuário já está no banco de dados de usuários. Se for o caso, estabeleça uma sessão autenticada para o usuário. Se o usuário ainda não estiver no banco de dados, crie um novo registro usando as informações no payload do token de ID e estabeleça uma sessão para o usuário. Você pode solicitar outras informações de perfil necessárias ao detectar um usuário recém-criado no app.

Como proteger as contas dos usuários com a Proteção entre contas

Ao confiar no Google para fazer o login de um usuário, você aproveita automaticamente todos os recursos de segurança e a infraestrutura que o Google criou para proteger os dados do usuário. No entanto, no caso improvável de a Conta do Google do usuário ser comprometida ou de alguma outra ocorrência de segurança significativa, seu app também poderá ficar vulnerável a ataques. Para proteger melhor suas contas contra grandes ocorrências de segurança, use a Proteção entre contas para receber alertas de segurança do Google. Ao receber esses eventos, você confere mudanças importantes na segurança da Conta do Google do usuário e pode tomar medidas no seu serviço para proteger suas contas.