Para apps do Google Chat criados em endpoints HTTP, explicamos nesta seção como verificar se as solicitações para o endpoint vêm do Chat.
Para enviar eventos de interação ao endpoint do app do Chat, o Google faz solicitações ao serviço. Para verificar se a solicitação vem
do Google, o Chat inclui um
token do portador
no cabeçalho Authorization
de cada solicitação HTTPS para seu endpoint. Exemplo:
POST
Host: yourappurl.com
Authorization: Bearer AbCdEf123456
Content-Type: application/json
User-Agent: Google-Dynamite
A string AbCdEf123456
no exemplo anterior é o token de autorização do portador. Esse é um token criptográfico produzido pelo Google. O tipo de token do portador e o valor do campo audience
dependem do tipo de público de autenticação selecionado ao configurar o app do Chat.
Se você tiver implementado o app do Chat usando o Cloud Functions ou o Cloud Run, o Cloud IAM processará a verificação do token automaticamente. Você só precisa 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:
- Java: https://github.com/google/google-api-java-client
- Python: https://github.com/google/google-api-python-client
- Node.js: https://github.com/google/google-api-java-client
- .NET: https://github.com/google/google-api-dotnet-client
Se o token não for verificado para o app do Chat, o
serviço 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, selecione App URL
no campo Público de autenticação da
configuração de conexão do
app do Chat e verifique se o
URL do app na configuração corresponde ao URL do endpoint da função do Cloud ou
do Cloud Run.
Em seguida, autorize a conta de serviço do Google Chat
chat@system.gserviceaccount.com
como um invocador.
As etapas a seguir mostram como usar o Cloud Functions (1a geração):
Console
Após implantar a função no Google Cloud:
No console do Google Cloud, acesse a página Cloud Functions:
Na lista do Cloud Functions, clique na caixa de seleção ao lado da função de destino. (Não clique na função em si.)
Clique em Permissões na parte superior da tela. O painel Permissões é aberto.
Clique em Adicionar principal.
No campo Novos participantes, insira
chat@system.gserviceaccount.com
.Selecione o papel Cloud Functions > Invocador do Cloud Functions no menu suspenso Selecionar um papel.
Clique em Salvar.
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 da função do seu app do 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:
No console do Google Cloud, acesse a página do Cloud Run:
Na lista de serviços do Cloud Run, clique na caixa de seleção ao lado da função de destino. (Não clique na função em si.)
Clique em Permissões na parte superior da tela. O painel Permissões é aberto.
Clique em Adicionar principal.
No campo Novos participantes, insira
chat@system.gserviceaccount.com
.Selecione o papel Cloud Run > Invocador do Cloud Run no menu suspenso Selecionar um papel.
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 da função do seu app do Chat.
Autenticar solicitações com um token de ID do URL do aplicativo
Se o campo "Público de autenticação" da
configuração de conexão do app do Chat
estiver definido como App URL
,
o token de autorização do portador na solicitação será um token de ID do OpenID Connect
(OIDC) assinado pelo Google.
O campo email
é definido como chat@system.gserviceaccount.com
.
O campo audience
é definido como o URL que você configurou para enviar
solicitações ao app do Chat. Por exemplo, se o
endpoint configurado do app do Chat for
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 pelo Google Chat e segmentado para seu app usando a biblioteca de cliente OAuth do Google.
Java
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Collections;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.googleapis.auth.oauth2.GooglePublicKeysManager;
import com.google.api.client.http.apache.ApacheHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.client.json.JsonFactory;
/** Tool for verifying JWT Tokens for Apps in Google Chat. */
public class JWTVerify {
// Bearer Tokens received by apps will always specify this issuer.
static String CHAT_ISSUER = "chat@system.gserviceaccount.com";
// Intended audience of the token, which is the URL of the app.
static String AUDIENCE = "https://example.com/app/";
// Get this value from the request's Authorization HTTPS header.
// For example, for "Authorization: Bearer AbCdEf123456" use "AbCdEf123456".
static String BEARER_TOKEN = "AbCdEf123456";
public static void main(String[] args) throws GeneralSecurityException, IOException {
JsonFactory factory = new GsonFactory();
GoogleIdTokenVerifier verifier =
new GoogleIdTokenVerifier.Builder(new ApacheHttpTransport(), factory)
.setAudience(Collections.singletonList(AUDIENCE))
.build();
GoogleIdToken idToken = GoogleIdToken.parse(factory, BEARER_TOKEN);
if (idToken == null) {
System.out.println("Token cannot be parsed");
System.exit(-1);
}
// Verify valid token, signed by CHAT_ISSUER, intended for a third party.
if (!verifier.verify(idToken)
|| !idToken.getPayload().getEmailVerified()
|| !idToken.getPayload().getEmail().equals(CHAT_ISSUER)) {
System.out.println("Invalid token");
System.exit(-1);
}
// Token originates from Google and is targeted to a specific client.
System.out.println("The token is valid");
}
}
Python
import sys
from google.oauth2 import id_token
from google.auth.transport import requests
# Bearer Tokens received by apps will always specify this issuer.
CHAT_ISSUER = 'chat@system.gserviceaccount.com'
# Intended audience of the token, which is the URL of the app.
AUDIENCE = 'https://example.com/app/'
# Get this value from the request's Authorization HTTPS header.
# For example, for 'Authorization: Bearer AbCdEf123456' use 'AbCdEf123456'.
BEARER_TOKEN = 'AbCdEf123456'
try:
# Verify valid token, signed by CHAT_ISSUER, intended for a third party.
request = requests.Request()
token = id_token.verify_oauth2_token(BEARER_TOKEN, request, AUDIENCE)
if token['email'] != CHAT_ISSUER:
sys.exit('Invalid token')
except:
sys.exit('Invalid token')
# Token originates from Google and is targeted to a specific client.
print('The token is valid')
Node.js
import {OAuth2Client} from 'google-auth-library';
// Bearer Tokens received by apps will always specify this issuer.
const CHAT_ISSUER = 'chat@system.gserviceaccount.com';
// Intended audience of the token, which is the URL of the app.
const AUDIENCE = 'https://example.com/app/';
// Get this value from the request's Authorization HTTPS header.
// For example, for "Authorization: Bearer AbCdEf123456" use "AbCdEf123456"
const BEARER_TOKEN = 'AbCdEf123456';
const client = new OAuth2Client();
async function verify() {
// Verify valid token, signed by CHAT_ISSUER, intended for a third party.
try {
const ticket = await client.verifyIdToken({
idToken: BEARER_TOKEN,
audience: AUDIENCE
});
if (!ticket.getPayload().email_verified
|| ticket.getPayload().email !== CHAT_ISSUER) {
throw new Error('Invalid issuer');
}
} catch (unused) {
console.error('Invalid token');
process.exit(1);
}
// Token originates from Google and is targeted to a specific client.
console.log('The token is valid');
}
verify();
Autenticar solicitações com um JWT de número de projeto
Se o campo "Authentication Audience" da configuração de conexão do app do Chat estiver definido como Project
Number
, o token de autorização do portador na solicitação será um JSON Web Token (JWT) autoassinado, emitido e assinado por chat@system.gserviceaccount.com
.
O campo audience
é definido como o número do projeto do Google Cloud usado
para criar o app do Chat. Por exemplo, se o
número do projeto do Cloud do app do Chat for
1234567890
, o campo audience
no JWT será 1234567890
.
Os exemplos a seguir mostram como verificar se o token do portador foi emitido pelo Google Chat e direcionado ao seu projeto usando a biblioteca de cliente OAuth do Google.
Java
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Collections;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.googleapis.auth.oauth2.GooglePublicKeysManager;
import com.google.api.client.http.apache.ApacheHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.client.json.JsonFactory;
/** Tool for verifying JWT Tokens for Apps in Google Chat. */
public class JWTVerify {
// Bearer Tokens received by apps will always specify this issuer.
static String CHAT_ISSUER = "chat@system.gserviceaccount.com";
// Url to obtain the public certificate for the issuer.
static String PUBLIC_CERT_URL_PREFIX =
"https://www.googleapis.com/service_accounts/v1/metadata/x509/";
// Intended audience of the token, which is the project number of the app.
static String AUDIENCE = "1234567890";
// Get this value from the request's Authorization HTTPS header.
// For example, for "Authorization: Bearer AbCdEf123456" use "AbCdEf123456".
static String BEARER_TOKEN = "AbCdEf123456";
public static void main(String[] args) throws GeneralSecurityException, IOException {
JsonFactory factory = new GsonFactory();
GooglePublicKeysManager.Builder keyManagerBuilder =
new GooglePublicKeysManager.Builder(new ApacheHttpTransport(), factory);
String certUrl = PUBLIC_CERT_URL_PREFIX + CHAT_ISSUER;
keyManagerBuilder.setPublicCertsEncodedUrl(certUrl);
GoogleIdTokenVerifier.Builder verifierBuilder =
new GoogleIdTokenVerifier.Builder(keyManagerBuilder.build());
verifierBuilder.setIssuer(CHAT_ISSUER);
GoogleIdTokenVerifier verifier = verifierBuilder.build();
GoogleIdToken idToken = GoogleIdToken.parse(factory, BEARER_TOKEN);
if (idToken == null) {
System.out.println("Token cannot be parsed");
System.exit(-1);
}
// Verify valid token, signed by CHAT_ISSUER, intended for a third party.
if (!verifier.verify(idToken)
|| !idToken.verifyAudience(Collections.singletonList(AUDIENCE))
|| !idToken.verifyIssuer(CHAT_ISSUER)) {
System.out.println("Invalid token");
System.exit(-1);
}
// Token originates from Google and is targeted to a specific client.
System.out.println("The token is valid");
}
}
Python
import sys
from google.oauth2 import id_token
from google.auth.transport import requests
# Bearer Tokens received by apps will always specify this issuer.
CHAT_ISSUER = 'chat@system.gserviceaccount.com'
# Url to obtain the public certificate for the issuer.
PUBLIC_CERT_URL_PREFIX = 'https://www.googleapis.com/service_accounts/v1/metadata/x509/'
# Intended audience of the token, which will be the project number of the app.
AUDIENCE = '1234567890'
# Get this value from the request's Authorization HTTPS header.
# For example, for 'Authorization: Bearer AbCdEf123456' use 'AbCdEf123456'.
BEARER_TOKEN = 'AbCdEf123456'
try:
# Verify valid token, signed by CHAT_ISSUER, intended for a third party.
request = requests.Request()
certs_url = PUBLIC_CERT_URL_PREFIX + CHAT_ISSUER
token = id_token.verify_token(BEARER_TOKEN, request, AUDIENCE, certs_url)
if token['iss'] != CHAT_ISSUER:
sys.exit('Invalid issuer')
except:
sys.exit('Invalid token')
# Token originates from Google and is targeted to a specific client.
print('The token is valid')
Node.js
import fetch from 'node-fetch';
import {OAuth2Client} from 'google-auth-library';
// Bearer Tokens received by apps will always specify this issuer.
const CHAT_ISSUER = 'chat@system.gserviceaccount.com';
// Url to obtain the public certificate for the issuer.
const PUBLIC_CERT_URL_PREFIX =
'https://www.googleapis.com/service_accounts/v1/metadata/x509/';
// Intended audience of the token, which is the project number of the app.
const AUDIENCE = '1234567890';
// Get this value from the request's Authorization HTTPS header.
// For example, for "Authorization: Bearer AbCdEf123456" use "AbCdEf123456"
const BEARER_TOKEN = 'AbCdEf123456';
const client = new OAuth2Client();
/** Verifies JWT Tokens for Apps in Google Chat. */
async function verify() {
// Verify valid token, signed by CHAT_ISSUER, intended for a third party.
try {
const response = await fetch(PUBLIC_CERT_URL_PREFIX + CHAT_ISSUER);
const certs = await response.json();
const ticket = await client.verifySignedJwtWithCertsAsync(
BEARER_TOKEN, certs, AUDIENCE, [CHAT_ISSUER]);
} catch (unused) {
console.error('Invalid token');
process.exit(1);
}
// Token originates from Google and is targeted to a specific client.
console.log('The token is valid');
}
verify();
Temas relacionados
- Para uma visão geral da autenticação e autorização no Google Workspace, consulte Saiba mais sobre autenticação e autorização.
- Para ter uma visão geral da autenticação e autorização no Chat, consulte Visão geral da autenticação.
- Configure a autenticação e a autorização com credenciais de usuário ou uma conta de serviço.