Memverifikasi permintaan dari Google Chat

Untuk aplikasi Google Chat yang dibangun di endpoint HTTP, bagian ini menjelaskan cara pastikan bahwa permintaan ke endpoint Anda berasal dari Chat.

Untuk mengirim peristiwa interaksi ke aplikasi Chat Anda endpoint, Google akan membuat permintaan ke layanan Anda. Untuk memverifikasi bahwa permintaan tersebut dari Google, Chat menyertakan token pemilik di header Authorization setiap permintaan HTTPS ke endpoint Anda. Contoh:

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

String AbCdEf123456 dalam contoh sebelumnya adalah token otorisasi pembawa. Ini adalah token kriptografis yang dihasilkan oleh Google. Jenis token pembawa dan nilai kolom audience bergantung pada jenis audiens autentikasi yang Anda pilih saat mengonfigurasi aplikasi Chat.

Jika Anda telah menerapkan aplikasi Chat menggunakan Cloud Functions atau Cloud Run, Cloud IAM akan menangani verifikasi token secara otomatis. Anda hanya perlu menambahkan akun layanan Google Chat sebagai invoker resmi. Jika aplikasi Anda menerapkan server HTTP-nya sendiri, Anda dapat memverifikasi token pembawa menggunakan library klien Google API open source:

Jika token tidak diverifikasi untuk aplikasi Chat, layanan harus merespons permintaan tersebut dengan kode respons HTTPS 401 (Unauthorized).

Mengautentikasi permintaan menggunakan Cloud Functions atau Cloud Run

Jika logika fungsi Anda diterapkan menggunakan Cloud Functions atau Cloud Run, Anda harus memilih HTTP endpoint URL di kolom Authentication Audience di setelan koneksi aplikasi Chat dan memastikan bahwa URL endpoint HTTP dalam konfigurasi sesuai dengan URL endpoint Cloud Function atau Cloud Run.

Kemudian, Anda perlu memberikan otorisasi ke akun layanan Google Chat chat@system.gserviceaccount.com sebagai pemanggil.

Langkah-langkah berikut menunjukkan cara menggunakan Cloud Functions (generasi ke-1):

Konsol

Setelah men-deploy fungsi Anda ke Google Cloud:

  1. Di konsol Google Cloud, buka halaman Cloud Functions:

    Buka Cloud Functions

  2. Dalam daftar Cloud Functions, klik kotak centang di samping kolom fungsi tersebut. (Jangan klik fungsi itu sendiri.)

  3. Klik Izin di bagian atas layar. Panel Izin akan terbuka.

  4. Klik Tambahkan akun utama.

  5. Di kolom New principals, masukkan chat@system.gserviceaccount.com.

  6. Pilih peran Cloud Functions > Invoker Cloud Functions dari Menu drop-down Pilih peran.

  7. Klik Simpan.

gcloud

Gunakan perintah gcloud functions add-iam-policy-binding:

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

Ganti RECEIVING_FUNCTION dengan nama Anda Fungsi aplikasi Chat.

Langkah-langkah berikut menunjukkan cara menggunakan layanan Cloud Functions (generasi ke-2) atau Cloud Run:

Konsol

Setelah men-deploy fungsi atau layanan Anda ke Google Cloud:

  1. Di konsol Google Cloud, buka halaman Cloud Run:

    Buka Cloud Run

  2. Dalam daftar layanan Cloud Run, klik kotak centang di samping fungsi tersebut. (Jangan klik fungsi itu sendiri.)

  3. Klik Izin di bagian atas layar. Panel Izin akan terbuka.

  4. Klik Tambahkan akun utama.

  5. Di kolom New principals, masukkan chat@system.gserviceaccount.com.

  6. Pilih peran Cloud Run > Cloud Run Invoker dari Menu drop-down Pilih peran.

  7. Klik Simpan.

gcloud

Gunakan perintah gcloud functions add-invoker-policy-binding:

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

Ganti RECEIVING_FUNCTION dengan nama Anda Fungsi aplikasi Chat.

Mengautentikasi permintaan HTTP dengan Token ID

Jika kolom Authentication Audience di aplikasi Chat connection settings disetel ke URL endpoint HTTP, token otorisasi pembawa dalam permintaan adalah OpenID Connect yang ditandatangani oleh Google (OIDC) Token ID. Kolom email ditetapkan ke chat@system.gserviceaccount.com. Kolom Authentication Audience ditetapkan ke URL yang Anda konfigurasikan untuk Google Chat agar dapat mengirim permintaan ke aplikasi Chat Anda. Misalnya, jika endpoint yang dikonfigurasi untuk aplikasi Chat Anda adalah https://example.com/app/, kolom Authentication Audience dalam token ID adalah https://example.com/app/.

Contoh berikut menunjukkan cara memverifikasi bahwa token pemilik diterbitkan oleh Google Chat dan ditargetkan pada aplikasi Anda menggunakan library klien OAuth 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;
}

Mengautentikasi permintaan dengan JWT Nomor Project

Jika kolom Audiens Autentikasi dari setelan koneksi aplikasi Chat ditetapkan ke Project Number, token otorisasi pembawa dalam permintaan adalah Token Web JSON (JWT) yang ditandatangani sendiri, yang dikeluarkan dan ditandatangani oleh chat@system.gserviceaccount.com. Kolom audience ditetapkan ke nomor project Google Cloud yang Anda gunakan untuk mem-build aplikasi Chat. Misalnya, jika nomor project Cloud aplikasi Chat Anda adalah 1234567890, kolom audience di JWT adalah 1234567890.

Contoh berikut menunjukkan cara memverifikasi bahwa token pembawa dikeluarkan oleh Google Chat dan ditargetkan ke project Anda menggunakan library klien Google OAuth.

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;
}