Google Chat से मिले अनुरोधों की पुष्टि करना

एचटीटीपी एंडपॉइंट पर बनाए गए Google Chat ऐप्लिकेशन के लिए, इस सेक्शन में यह बताया गया है कि यह कैसे पुष्टि करें कि आपके एंडपॉइंट पर किए गए अनुरोध, Chat से आए हैं.

Google, आपके Chat ऐप्लिकेशन के एंडपॉइंट पर इंटरैक्शन इवेंट भेजने के लिए, आपकी सेवा को एचटीटीपीएस अनुरोध भेजता है. अनुरोध Google से आ रहा है, इसकी पुष्टि करने के लिए Chat, Google के हस्ताक्षर वाला OpenID Connect (OIDC) आईडी टोकन शामिल करता है. यह धारक टोकन के तौर पर, हर एचटीटीपी अनुरोध के Authorization हेडर में (और अनुरोध के मुख्य हिस्से के authorizationEventObject.systemIdToken फ़ील्ड में) शामिल होता है. उदाहरण के लिए:

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

ऊपर दिए गए उदाहरण में, स्ट्रिंग AbCdEf123456, बियरर ऑथराइज़ेशन टोकन है. इस क्रिप्टोग्राफ़िक टोकन पर, आपके Chat ऐप्लिकेशन के यूनीक, पर-प्रोजेक्ट सेवा खाते (service-<var>PROJECT_NUMBER</var>@gcp-sa-gsuiteaddons.iam.gserviceaccount.com) के हस्ताक्षर होते हैं. साथ ही, audience फ़ील्ड को, Chat ऐप्लिकेशन को कॉन्फ़िगर करते समय आपके Chat ऐप्लिकेशन के लिए कॉन्फ़िगर किए गए एचटीटीपी एंडपॉइंट यूआरएल पर सेट किया जाता है.

Google Cloud Console में, Chat API के कॉन्फ़िगरेशन टैब के कनेक्शन सेटिंग सेक्शन में जाकर, Chat ऐप्लिकेशन के सेवा खाते का ईमेल पता कॉपी किया जा सकता है:

  1. Google Cloud Console में, मेन्यू > एपीआई और सेवाएं > चालू किए गए एपीआई और सेवाएं > Google Chat API > कॉन्फ़िगरेशन पर जाएं:

    Google Chat API कॉन्फ़िगरेशन पर जाएं

  2. इंटरैक्टिव सुविधाएं > कनेक्शन की सेटिंग में जाकर, सेवा खाते का ईमेल पता (service-<var>PROJECT_NUMBER</var>@gcp-sa-gsuiteaddons.iam.gserviceaccount.com) कॉपी करें.

अगर आपने Cloud Run फ़ंक्शन या Cloud Run का इस्तेमाल करके Chat ऐप्लिकेशन लागू किया है, तो Cloud IAM, टोकन की पुष्टि अपने-आप करता है. ऐसा तब होता है, जब Chat ऐप्लिकेशन के सेवा खाते को Cloud Run Invoker (roles/run.invoker) की भूमिका दी जाती है. अगर आपका ऐप्लिकेशन अपना एचटीटीपी सर्वर लागू करता है, तो ओपन सोर्स Google API क्लाइंट लाइब्रेरी का इस्तेमाल करके, बियरर टोकन की पुष्टि की जा सकती है:

अगर Chat ऐप्लिकेशन के लिए टोकन की पुष्टि नहीं होती है, तो आपकी सेवा को अनुरोध का जवाब एचटीटीपीएस रिस्पॉन्स कोड 401 (Unauthorized) के साथ देना चाहिए.

Cloud Run फ़ंक्शन का इस्तेमाल करके अनुरोधों की पुष्टि करना

अगर आपके फ़ंक्शन लॉजिक को Cloud Run फ़ंक्शन या Cloud Run का इस्तेमाल करके लागू किया गया है, तो पक्का करें कि Chat ऐप्लिकेशन की कनेक्शन सेटिंग में ट्रिगर के तहत कॉन्फ़िगर किए गए एचटीटीपी एंडपॉइंट यूआरएल, आपके Cloud Run फ़ंक्शन एंडपॉइंट के यूआरएल से मेल खाते हों.

इसके बाद, अपने Chat ऐप्लिकेशन के सेवा खाते (service-<var>PROJECT_NUMBER</var>@gcp-sa-gsuiteaddons.iam.gserviceaccount.com, Chat API के कॉन्फ़िगरेशन टैब के कनेक्शन सेटिंग सेक्शन से कॉपी किया गया) को, यहां दिया गया तरीका अपनाकर इनवॉकर के तौर पर अनुमति दें:

कंसोल

Google Cloud पर फ़ंक्शन या सेवा डिप्लॉय करने के बाद:

  1. Google Cloud Console में, Cloud Run पेज पर जाएं:

    Cloud Run पर जाएं

  2. Cloud Run सेवाओं की सूची में, डेटा पाने वाले फ़ंक्शन के बगल में मौजूद चेकबॉक्स पर क्लिक करें. (फ़ंक्शन पर क्लिक न करें.)

  3. स्क्रीन पर सबसे ऊपर मौजूद, अनुमतियां पर क्लिक करें. अनुमतियां पैनल खुलता है.

  4. प्रिंसिपल जोड़ें पर क्लिक करें.

  5. नए प्रिंसिपल फ़ील्ड में, Chat ऐप्लिकेशन के सेवा खाते का ईमेल पता (service-<var>PROJECT_NUMBER</var>@gcp-sa-gsuiteaddons.iam.gserviceaccount.com) डालें.

  6. कोई भूमिका चुनें मेन्यू में जाकर, Cloud Run भूमिका चुनें

    Cloud Run Invoker.

  7. सेव करें पर क्लिक करें.

gcloud

gcloud functions add-invoker-policy-binding कमांड का इस्तेमाल करें:

gcloud functions add-invoker-policy-binding RECEIVING_FUNCTION \
  --member='serviceAccount:service-PROJECT_NUMBER@gcp-sa-gsuiteaddons.iam.gserviceaccount.com'

इनकी जगह ये डालें:

  • RECEIVING_FUNCTION: आपके चैट ऐप्लिकेशन के फ़ंक्शन का नाम.
  • PROJECT_NUMBER: आपके Chat ऐप्लिकेशन के सेवा खाते के ईमेल पते से मिला प्रोजेक्ट नंबर.

आईडी टोकन की मदद से एचटीटीपी अनुरोधों की पुष्टि करना

एचटीटीपी एंडपॉइंट के लिए, अनुरोध में मौजूद बियरर ऑथराइज़ेशन टोकन, Google के हस्ताक्षर वाला OpenID Connect (OIDC) आईडी टोकन होता है. email फ़ील्ड को आपके Chat ऐप्लिकेशन के सेवा खाते के ईमेल पते (service-<var>PROJECT_NUMBER</var>@gcp-sa-gsuiteaddons.iam.gserviceaccount.com) पर सेट किया जाता है. साथ ही, audience फ़ील्ड को अनुरोध पाने के लिए कॉन्फ़िगर किए गए एचटीटीपी एंडपॉइंट यूआरएल पर सेट किया जाता है. उदाहरण के लिए, अगर आपके चैट ऐप्लिकेशन का कॉन्फ़िगर किया गया एंडपॉइंट https://example.com/app/ है, तो आईडी टोकन में audience फ़ील्ड https://example.com/app/ होगा.

अगर आपका एचटीटीपी एंडपॉइंट, IAM पर आधारित पुष्टि करने की सुविधा देने वाली सेवा (जैसे कि Cloud Run) पर होस्ट नहीं किया गया है, तो पुष्टि करने के लिए इस तरीके का इस्तेमाल करने का सुझाव दिया जाता है.

नीचे दिए गए सैंपल में, यह पुष्टि करने का तरीका बताया गया है कि Google OAuth क्लाइंट लाइब्रेरी का इस्तेमाल करके, Google ने आपके Chat ऐप्लिकेशन के लिए धारक टोकन जारी किया है और उसे आपके ऐप्लिकेशन के एंडपॉइंट के लिए टारगेट किया गया है:

Java

java/chat/secured-app/src/main/java/com/google/chat/app/secured/App.java
/**
 * Determine whether a Google Workspace add-on request is legitimate.
 * 
 * @param event Event sent from Google Workspace add-on
 * @param authorization Authorization header from the request
 * @return {boolean} Whether the request is legitimate
 */
private boolean verifyAddOnRequest(JsonNode event, String authorization) throws Exception {
  JsonFactory factory = JacksonFactory.getDefaultInstance();

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

  String bearer = authorization.substring("Bearer ".length(), authorization.length());
  GoogleIdToken idToken = GoogleIdToken.parse(factory, bearer);
  return idToken != null
    && verifier.verify(idToken)
    && idToken.getPayload().getEmailVerified()
    && idToken.getPayload().getEmail().equals(SERVICE_ACCOUNT_EMAIL);
}

Python

python/chat/secured-app/main.py
def verifyAddOnRequest() -> bool:
  """Determine whether a Google Workspace add-on request is legitimate.

  Args:
    request: Request sent from Google Workspace add-on

  Returns:
    Whether the request is legitimate
  """
  try:
    bearer = request.headers.get('Authorization')[len("Bearer "):]
    token = id_token.verify_oauth2_token(bearer, requests.Request(), HTTP_ENDPOINT)
    return token['email'] == SERVICE_ACCOUNT_EMAIL

  except:
    return False

Node.js

node/chat/secured-app/index.js
/**
 * Determine whether a Google Workspace add-on request is legitimate.
 * 
 * @param {Object} req Request sent from Google Workspace add-on
 * @return {boolean} Whether the request is legitimate
 */
async function verifyAddOnRequest(req) {
  try {
    const authorization = req.headers.authorization;
    const idToken = authorization.substring('Bearer '.length, authorization.length);
    const ticket = await new OAuth2Client().verifyIdToken({idToken, audience: HTTP_ENDPOINT});
    return ticket.getPayload().email_verified
        && ticket.getPayload().email === SERVICE_ACCOUNT_EMAIL;
  } catch (unused) {
    return false;
  }
}

ऐसे चैट ऐप्लिकेशन जो ऐड-ऑन नहीं हैं: Google Chat से मिले अनुरोधों की पुष्टि करना

यहां दिया गया दस्तावेज़, उन Chat ऐप्लिकेशन पर लागू होता है जो Google Workspace ऐड-ऑन नहीं हैं. अगर आपको किसी ऐसे Chat ऐप्लिकेशन को माइग्रेट करना है जो ऐड-ऑन नहीं है, तो Google Chat ऐप्लिकेशन को Google Workspace ऐड-ऑन में बदलना लेख पढ़ें.

कनेक्शन सेटिंग में जाकर, एचटीटीपी एंडपॉइंट यूआरएल के साथ कॉन्फ़िगर किए गए ऐड-ऑन के तौर पर काम न करने वाले Chat ऐप्लिकेशन के लिए, धारक टोकन का टाइप और audience फ़ील्ड की वैल्यू, Authentication Audience के टाइप पर निर्भर करती है. यह टाइप, Chat ऐप्लिकेशन को कॉन्फ़िगर करते समय चुना जाता है. साथ ही, अनुरोधों पर शेयर किए गए सेवा खाते chat@system.gserviceaccount.com के हस्ताक्षर होते हैं.

Cloud Run फ़ंक्शन का इस्तेमाल करके अनुरोधों की पुष्टि करना (ऐसे Chat ऐप्लिकेशन जो ऐड-ऑन नहीं हैं)

अगर आपके फ़ंक्शन लॉजिक को Cloud Run फ़ंक्शन का इस्तेमाल करके लागू किया गया है, तो आपको Chat ऐप्लिकेशन की कनेक्शन सेटिंग के Authentication Audience फ़ील्ड में HTTP एंडपॉइंट यूआरएल चुनना होगा. साथ ही, यह पक्का करना होगा कि कॉन्फ़िगरेशन में मौजूद एचटीटीपी एंडपॉइंट यूआरएल, Cloud Run फ़ंक्शन एंडपॉइंट के यूआरएल से मेल खाता हो.

इसके बाद, आपको Google Chat सेवा खाते chat@system.gserviceaccount.com को इनवॉकर के तौर पर अनुमति देनी होगी. इसके लिए, यह तरीका अपनाएं:

कंसोल

Google Cloud पर फ़ंक्शन या सेवा डिप्लॉय करने के बाद:

  1. Google Cloud Console में, Cloud Run पेज पर जाएं:

    Cloud Run पर जाएं

  2. Cloud Run सेवाओं की सूची में, डेटा पाने वाले फ़ंक्शन के बगल में मौजूद चेकबॉक्स पर क्लिक करें. (फ़ंक्शन पर क्लिक न करें.)

  3. स्क्रीन पर सबसे ऊपर मौजूद, अनुमतियां पर क्लिक करें. अनुमतियां पैनल खुलता है.

  4. प्रिंसिपल जोड़ें पर क्लिक करें.

  5. नए प्रिंसिपल फ़ील्ड में, chat@system.gserviceaccount.com डालें.

  6. कोई भूमिका चुनें मेन्यू में जाकर, Cloud Run भूमिका चुनें

    Cloud Run Invoker.

  7. सेव करें पर क्लिक करें.

gcloud

gcloud functions add-invoker-policy-binding कमांड का इस्तेमाल करें:

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

RECEIVING_FUNCTION की जगह, अपने चैट ऐप्लिकेशन के फ़ंक्शन का नाम डालें.

आईडी टोकन की मदद से एचटीटीपी अनुरोधों की पुष्टि करना (ऐसे चैट ऐप्लिकेशन जो ऐड-ऑन नहीं हैं)

अगर ऐड-ऑन नहीं है, तो Chat ऐप्लिकेशन की कनेक्शन सेटिंग के Authentication Audience फ़ील्ड को HTTP endpoint URL पर सेट किया जाता है, तो अनुरोध में मौजूद बियरर ऑथराइज़ेशन टोकन, Google के हस्ताक्षर वाला OpenID Connect (OIDC) आईडी टोकन होता है. email फ़ील्ड को chat@system.gserviceaccount.com पर सेट किया गया है. पुष्टि करने वाली ऑडियंस फ़ील्ड को उस यूआरएल पर सेट किया जाता है जिसे आपने Google Chat को कॉन्फ़िगर किया है, ताकि वह आपके Chat ऐप्लिकेशन को अनुरोध भेज सके. यह ऐप्लिकेशन, ऐड-ऑन नहीं है. उदाहरण के लिए, अगर आपके चैट ऐप्लिकेशन का कॉन्फ़िगर किया गया एंडपॉइंट https://example.com/app/ है, तो आईडी टोकन में मौजूद पुष्टि करने वाली ऑडियंस फ़ील्ड https://example.com/app/ होगा.

यहां दिए गए सैंपल से पता चलता है कि Google OAuth क्लाइंट लाइब्रेरी का इस्तेमाल करके, यह कैसे पुष्टि की जाती है कि धारक टोकन, Google Chat ने जारी किया है और इसे आपके Chat ऐप्लिकेशन के लिए टारगेट किया गया है. यह ऐप्लिकेशन, ऐड-ऑन नहीं है.

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

प्रोजेक्ट नंबर JWT की मदद से अनुरोधों की पुष्टि करना (ऐसे चैट ऐप्लिकेशन जो ऐड-ऑन नहीं हैं)

अगर ऐड-ऑन नहीं है, तो Chat ऐप्लिकेशन की कनेक्शन सेटिंग के Authentication Audience फ़ील्ड को Project Number पर सेट किया गया है, तो अनुरोध में मौजूद Bearer Authorization Token, JSON Web Token (JWT) पर खुद हस्ताक्षर किया हुआ है. इसे chat@system.gserviceaccount.com ने जारी किया है और इस पर हस्ताक्षर किए हैं. audience फ़ील्ड को उस Google Cloud प्रोजेक्ट नंबर पर सेट किया जाता है जिसका इस्तेमाल आपने ऐड-ऑन के तौर पर काम न करने वाला Chat ऐप्लिकेशन बनाने के लिए किया था. उदाहरण के लिए, अगर आपके Chat ऐप्लिकेशन का क्लाउड प्रोजेक्ट नंबर 1234567890 है, तो JWT में audience फ़ील्ड 1234567890 होगा.

यहां दिए गए सैंपल में, यह पुष्टि करने का तरीका बताया गया है कि Google Chat ने धारक टोकन जारी किया है और 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;
}