Google Chat의 요청 확인하기

이 섹션에서는 HTTP 엔드포인트를 기반으로 빌드된 Google Chat 앱의 경우 엔드포인트에 대한 요청이 Chat에서 오는지 확인합니다

채팅 앱의 엔드포인트가 있으면 Google이 서비스에 요청합니다. 요청이 Google에서 발생했는지 확인하기 위해 Chat은 엔드포인트에 대한 모든 HTTPS 요청의 Authorization 헤더에 베어러 토큰을 포함합니다. 예를 들면 다음과 같습니다.

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

위 예시에서 AbCdEf123456 문자열은 보유자 인증 토큰입니다. 이는 Google에서 생성한 암호화 토큰입니다. 베어러 유형 토큰의 값이며 audience 필드는 생성할 때 선택한 인증 대상의 유형에 따라 달라집니다. 채팅 앱 구성에 관해 자세히 알아보세요.

Cloud를 사용하여 채팅 앱을 구현한 경우 Functions 또는 Cloud Run을 사용하는 경우 Cloud IAM이 자동으로 토큰 확인을 처리합니다. 나 Google Chat 서비스 계정을 승인된 호출자로 추가하기만 하면 됩니다. 앱이 자체 HTTP 서버를 구현하는 경우 Bearer 토큰을 확인할 수 있습니다. 오픈소스 Google API 클라이언트 라이브러리 사용:

토큰이 Chat 앱에 대해 확인되지 않으면 서비스는 요청에 HTTPS 응답 코드 401 (Unauthorized)로 응답해야 합니다.

Cloud Functions 또는 Cloud Run을 사용하여 요청 인증

Cloud Functions 또는 Cloud Run을 사용하여 함수 로직을 구현하는 경우 인증 대상 필드에서 HTTP 엔드포인트 URL을 채팅 앱 연결 설정을 하고 구성의 HTTP 엔드포인트 URL이 Cloud 함수의 URL에 해당하는 경우 또는 Cloud Run 엔드포인트

그런 다음 Google Chat 서비스 계정을 승인해야 합니다. chat@system.gserviceaccount.com를 호출자로 정의합니다.

다음 단계에서는 Cloud Functions (1세대)를 사용하는 방법을 보여줍니다.

콘솔

함수를 Google Cloud에 배포한 후 다음을 실행합니다.

  1. Google Cloud 콘솔에서 Cloud Functions 페이지로 이동합니다.

    Cloud Functions로 이동

  2. Cloud Functions 목록에서 함수를 사용하세요. 함수 자체를 클릭하지 마세요.

  3. 화면 상단의 권한을 클릭합니다. 권한 패널이 열립니다.

  4. 주 구성원 추가를 클릭합니다.

  5. 새 주 구성원 필드에 chat@system.gserviceaccount.com를 입력합니다.

  6. Cloud Functions 역할을 선택합니다. Cloud Functions 호출자 역할 선택 드롭다운 메뉴

  7. 저장을 클릭합니다.

gcloud

gcloud functions add-iam-policy-binding 명령어를 사용합니다.

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

RECEIVING_FUNCTION을 채팅 앱의 기능

다음 단계에서는 Cloud Functions (2세대) 또는 Cloud Run 서비스를 사용하는 방법을 보여줍니다.

콘솔

함수 또는 서비스를 Google Cloud에 배포한 후 다음을 수행합니다.

  1. Google Cloud 콘솔에서 Cloud Run 페이지로 이동합니다.

    Cloud Run으로 이동

  2. Cloud Run 서비스 목록에서 함수를 사용하세요. 함수 자체를 클릭하지 마세요.

  3. 화면 상단의 권한을 클릭합니다. 권한 패널이 열립니다.

  4. 주 구성원 추가를 클릭합니다.

  5. 새 주 구성원 필드에 chat@system.gserviceaccount.com를 입력합니다.

  6. Cloud Run 역할을 선택합니다. Cloud Run 호출자 역할 선택 드롭다운 메뉴

  7. 저장을 클릭합니다.

gcloud

gcloud functions add-invoker-policy-binding 명령어를 사용합니다.

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

RECEIVING_FUNCTION을 채팅 앱의 기능

ID 토큰으로 HTTP 요청 인증

채팅 앱의 인증 대상 필드 연결 설정이 다음과 같이 설정됩니다. HTTP 엔드포인트 URL 요청의 Bearer 인증 토큰이 Google이 서명한 OpenID Connect인 경우 (OIDC) ID 토큰입니다. email 필드는 chat@system.gserviceaccount.com로 설정됩니다. Authentication Audience 필드는 Google Chat이 Chat 앱에 요청을 전송하도록 구성한 URL로 설정됩니다. 예를 들어 Chat 앱의 구성된 엔드포인트가 https://example.com/app/인 경우 ID 토큰의 Authentication Audience 필드는 https://example.com/app/입니다.

다음 샘플은 Bearer 토큰이 다음을 통해 발급되었는지 확인하는 방법을 보여줍니다. Google Chat으로, Google OAuth 클라이언트 라이브러리를 사용하여 앱을 타겟팅합니다.

자바

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

프로젝트 번호 JWT로 요청 인증

채팅 앱의 인증 대상 필드 연결 설정Project Number로 설정된 경우 요청의 Bearer 인증 토큰이 자체 서명됨 JSON 웹 토큰 (JWT), chat@system.gserviceaccount.com에서 발급 및 서명합니다. audience 필드는 사용한 Google Cloud 프로젝트 번호로 설정됩니다. 채팅 앱을 빌드할 수 있습니다 예를 들어 채팅 앱의 Cloud 프로젝트 번호 1234567890이면 JWT의 audience 필드는 1234567890입니다.

다음 샘플은 Bearer 토큰이 다음을 통해 발급되었는지 확인하는 방법을 보여줍니다. Google Chat으로, Google OAuth 클라이언트 라이브러리를 사용하여 사용자의 프로젝트를 대상으로 합니다.

자바

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