Verificar solicitações do Google Chat

Para apps do Google Chat criados em endpoints HTTP, esta seção explica como Verifique se as solicitações para o endpoint vêm do Chat.

Para enviar eventos de interação para o endpoint, o Google faz solicitações ao seu serviço. Para verificar se a solicitação é vindo do Google, o Chat inclui token do portador no cabeçalho Authorization de cada solicitação HTTPS para seu endpoint. Por exemplo:

POST
Host: yourappurl.com
Authorization: Bearer AbCdEf123456
Content-Type: application/json
User-Agent: Google-Dynamite

A string AbCdEf123456 no exemplo anterior é a autorização do portador. com base no token correto anterior. Esse é um token criptográfico produzido pelo Google. Tipo do portador token e o valor do atributo audience dependem do tipo de público de autenticação selecionado ao configurar o app Chat.

Se você implementou seu app do Chat usando o Cloud Functions ou o Cloud Run, o Cloud IAM lida com a verificação de tokens automaticamente. Você basta adicionar a conta de serviço do Google Chat como um invocador autorizado. Se o app implementar o próprio servidor HTTP, você poderá verificar o token do portador usando uma biblioteca de cliente das APIs do Google de código aberto:

Se o token não for verificado para o app do Chat, seu deve responder à solicitação com um código de resposta HTTPS 401 (Unauthorized):

Autenticar solicitações usando o Cloud Functions ou o Cloud Run

Se a lógica da função for implementada usando o Cloud Functions ou o Cloud Run, precisa selecionar App URL no campo Authentication Audience do App Chat configuração de conexão e verifique se o URL do app na configuração corresponde ao URL da função do Cloud ou endpoint do Cloud Run.

Em seguida, você precisa autorizar a conta de serviço do Google Chat chat@system.gserviceaccount.com como invocador.

As etapas a seguir mostram como usar o Cloud Functions (1a geração):

Console

Após implantar a função no Google Cloud:

  1. No console do Google Cloud, acesse a página Cloud Functions:

    Acesse o Cloud Functions

  2. Na lista do Cloud Functions, clique na caixa de seleção ao lado do nome função. (Não clique na função em si.)

  3. Clique em Permissões na parte superior da tela. O painel Permissões é aberto.

  4. Clique em Adicionar principal.

  5. No campo Novos participantes, insira chat@system.gserviceaccount.com.

  6. Selecione o papel Cloud Functions > Chamador do Cloud Functions do Menu suspenso Selecionar um papel.

  7. Clique em Save.

gcloud

Use o comando gcloud functions add-iam-policy-binding:

gcloud functions add-iam-policy-binding RECEIVING_FUNCTION \
  --member='serviceAccount:chat@system.gserviceaccount.com' \
  --role='roles/cloudfunctions.invoker'

Substitua RECEIVING_FUNCTION pelo nome do seu Função do app de chat.

As etapas a seguir mostram como usar os serviços do Cloud Functions (2a geração) ou do Cloud Run:

Console

Após implantar a função ou serviço no Google Cloud:

  1. No console do Google Cloud, acesse a página do Cloud Run:

    Acessar o Cloud Run

  2. Na lista de serviços do Cloud Run, clique na caixa de seleção ao lado dos função. (Não clique na função em si.)

  3. Clique em Permissões na parte superior da tela. O painel Permissões é aberto.

  4. Clique em Adicionar principal.

  5. No campo Novos participantes, insira chat@system.gserviceaccount.com.

  6. Selecione o papel Cloud Run > Invocador do Cloud Run pelo Menu suspenso Selecionar um papel.

  7. Clique em Salvar.

gcloud

Use o comando gcloud functions add-invoker-policy-binding:

gcloud functions add-invoker-policy-binding RECEIVING_FUNCTION \
  --member='serviceAccount:chat@system.gserviceaccount.com'

Substitua RECEIVING_FUNCTION pelo nome do seu Função do app de chat.

Autenticar solicitações com um token de ID do URL do aplicativo

Se o campo "Authentication Audience" do app do Chat configuração de conexão definida como App URL, o token de autorização do portador na solicitação é um OpenID Connect assinado pelo Google (OIDC) Token de ID. O campo email é definido como chat@system.gserviceaccount.com. O campo audience é definido como o URL que você configurou para enviar pelo Google Chat. para seu app do Chat. Por exemplo, se o que o endpoint configurado do seu app do Chat seja https://example.com/app/, o campo audience no token de ID será https://example.com/app/.

Os exemplos a seguir mostram como verificar se o token do portador foi emitido pela Google Chat e direcionados ao seu app usando a biblioteca de cliente OAuth do Google.

Java

java/basic-app/src/main/java/com/google/chat/app/basic/App.java
String CHAT_ISSUER = "chat@system.gserviceaccount.com";
JsonFactory factory = JacksonFactory.getDefaultInstance();

GoogleIdTokenVerifier verifier =
    new GoogleIdTokenVerifier.Builder(new ApacheHttpTransport(), factory)
        .setAudience(Collections.singletonList(AUDIENCE))
        .build();

GoogleIdToken idToken = GoogleIdToken.parse(factory, bearer);
return idToken != null
    && verifier.verify(idToken)
    && idToken.getPayload().getEmailVerified()
    && idToken.getPayload().getEmail().equals(CHAT_ISSUER);

Python

python/basic-app/main.py
# Bearer Tokens received by apps will always specify this issuer.
CHAT_ISSUER = 'chat@system.gserviceaccount.com'

try:
    # Verify valid token, signed by CHAT_ISSUER, intended for a third party.
    request = requests.Request()
    token = id_token.verify_oauth2_token(bearer, request, AUDIENCE)
    return token['email'] == CHAT_ISSUER

except:
    return False

Node.js

node/basic-app/index.js
// Bearer Tokens received by apps will always specify this issuer.
const chatIssuer = 'chat@system.gserviceaccount.com';

// Verify valid token, signed by chatIssuer, intended for a third party.
try {
  const ticket = await client.verifyIdToken({
    idToken: bearer,
    audience: audience
  });
  return ticket.getPayload().email_verified
      && ticket.getPayload().email === chatIssuer;
} catch (unused) {
  return false;
}

Autenticar solicitações com um JWT de número de projeto

Se o campo "Authentication Audience" do app do Chat a configuração de conexão estiver definida como Project Number, o token de autorização do portador na solicitação é um token autoassinado JSON Web Token (JWT), emitido e assinado por chat@system.gserviceaccount.com. O campo audience está definido como o número do projeto do Google Cloud que você usou para criar seu app do Chat. Por exemplo, se sua O número do projeto na nuvem do app do Chat é 1234567890, o campo audience no JWT será 1234567890.

Os exemplos a seguir mostram como verificar se o token do portador foi emitido pela Google Chat e direcionado ao seu projeto com a biblioteca de cliente OAuth do Google.

Java

java/basic-app/src/main/java/com/google/chat/app/basic/App.java
String CHAT_ISSUER = "chat@system.gserviceaccount.com";
JsonFactory factory = JacksonFactory.getDefaultInstance();

GooglePublicKeysManager keyManagerBuilder =
    new GooglePublicKeysManager.Builder(new ApacheHttpTransport(), factory)
        .setPublicCertsEncodedUrl(
            "https://www.googleapis.com/service_accounts/v1/metadata/x509/" + CHAT_ISSUER)
        .build();

GoogleIdTokenVerifier verifier =
    new GoogleIdTokenVerifier.Builder(keyManagerBuilder).setIssuer(CHAT_ISSUER).build();

GoogleIdToken idToken = GoogleIdToken.parse(factory, bearer);
return idToken != null
    && verifier.verify(idToken)
    && idToken.verifyAudience(Collections.singletonList(AUDIENCE))
    && idToken.verifyIssuer(CHAT_ISSUER);

Python

python/basic-app/main.py
# Bearer Tokens received by apps will always specify this issuer.
CHAT_ISSUER = 'chat@system.gserviceaccount.com'

try:
    # Verify valid token, signed by CHAT_ISSUER, intended for a third party.
    request = requests.Request()
    certs_url = 'https://www.googleapis.com/service_accounts/v1/metadata/x509/' + CHAT_ISSUER
    token = id_token.verify_token(bearer, request, AUDIENCE, certs_url)
    return token['iss'] == CHAT_ISSUER

except:
    return False

Node.js

node/basic-app/index.js
// Bearer Tokens received by apps will always specify this issuer.
const chatIssuer = 'chat@system.gserviceaccount.com';

// Verify valid token, signed by CHAT_ISSUER, intended for a third party.
try {
  const response = await fetch('https://www.googleapis.com/service_accounts/v1/metadata/x509/' + chatIssuer);
  const certs = await response.json();
  await client.verifySignedJwtWithCertsAsync(
    bearer, certs, audience, [chatIssuer]);
  return true;
} catch (unused) {
  return false;
}