Gérer les autorisations OAuth granulaires pour les applications Google Chat

Les applications Chat qui utilisent l'authentification des utilisateurs doivent être compatibles avec les autorisations OAuth granulaires pour permettre aux utilisateurs d'accorder un sous-ensemble des champs d'application demandés. Par exemple, un utilisateur peut accorder l'accès à son nom, mais refuser l'accès à son agenda.

La gestion des autorisations OAuth granulaires dépend de la façon dont vous créez votre application Chat :

Apps Script

Si vous créez votre application Chat à l'aide de Apps Script, Apps Script gère automatiquement les autorisations OAuth granulaires. Toutefois, assurez-vous que votre code gère les cas où un utilisateur n'accorde pas tous les champs d'application demandés. La méthode dépend du fait que votre Apps Script soit un module complémentaire Google Workspace qui étend Google Chat à l'aide d'Apps Script ou une application Chat autonome créée avec Apps Script et des événements d'interaction.

Modules complémentaires Google Workspace qui étendent Chat

Si vous créez votre application Chat en tant que module complémentaire Google Workspace qui étend Google Chat à l'aide d'Apps Script, suivez les instructions de la section Gérer les autorisations OAuth granulaires dans Apps Script.

Applications Chat Apps Script autonomes

Si vous créez votre application Chat à l'aide de Apps Script et d'événements d'interaction, les instructions de la section Gérer les autorisations OAuth granulaires dans Apps Script fonctionnent avec une seule considération :

ScriptApp.requireScopes arrête l'exécution du script si les champs d'application spécifiés ne sont pas accordés, mais l'utilisateur voit une carte de configuration dans Chat au lieu de l'écran de consentement OAuth. La carte de configuration invite toujours l'utilisateur à accorder tous les champs d'application demandés au lieu de ceux qui ne sont pas accordés.

Pour fournir des vérifications individuelles au niveau du champ d'application d'autorisation, utilisez ScriptApp.getAuthorizationInfo pour vérifier l'autorisation et, si nécessaire, demander l'autorisation à l'aide d'un message privé.

L'exemple suivant montre comment vérifier une autorisation spécifique (comme l'accès à l'agenda) et, si elle est manquante, renvoyer un message privé avec l'URL d'autorisation requise.

Apps Script

/**
* Responds to a MESSAGE event in Google Chat.
* Checks for required permissions and if missing asks for them.
*
* @param {Object} event the event object from Chat
* @return {Object} JSON response
*/
function onMessage(event) {
  // Check if the script has the necessary permissions.
  // In this example, the script checks for the "calendar.events" scope.
  var requiredScopes = ['https://www.googleapis.com/auth/calendar.events'];
  var authInfo = ScriptApp.getAuthorizationInfo(ScriptApp.AuthMode.FULL, requiredScopes);

  // If permissions are missing, return a message with the authorization URL.
  if (authInfo.getAuthorizationStatus() === ScriptApp.AuthorizationStatus.REQUIRED) {
    var authUrl = authInfo.getAuthorizationUrl();
    return {
      "text": "This action requires authorization. Please <" + authUrl + "|click here to authorize>.",
      "privateMessageViewer": {
        "name": event.user.name
      }
    };
  }

  // Permission granted; proceed with the application logic.
  // ...
}

Points de terminaison HTTP

Si vous créez votre application Chat à l'aide de points de terminaison HTTP, votre application Chat doit être compatible avec les autorisations OAuth granulaires.

Modules complémentaires Google Workspace qui étendent Chat

Si vous créez votre application Chat en tant que module complémentaire Google Workspace, configurez votre code pour gérer les autorisations OAuth granulaires. Vérifiez les champs d'application d'autorisation que l'utilisateur a accordés et, si nécessaire, demandez l'autorisation pour les champs d'application manquants ou tous les champs d'application.

  1. Dans le fichier manifeste de votre module complémentaire, spécifiez les champs d'application d'autorisation requis dans le champ oauthScopes. Ce champ fait partie de la projects.deployments ressource.

    L'exemple suivant nécessite les champs d'application d'autorisation chat.messages et calendar.events :

    JSON

    {
      "oauthScopes": [
        "https://www.googleapis.com/auth/chat.messages",
        "https://www.googleapis.com/auth/calendar.events"
      ],
      "addOns": {
        "common": {
          "name": "My Chat App",
          "logoUrl": "https://lh3.googleusercontent.com/..."
        },
        "chat": {},
        "calendar": {},
        "httpOptions": {}
      }
    }
    
  2. Pour voir les champs d'application que l'utilisateur a accordés, consultez le champ authorizationEventObject.authorizedScopes. Si un champ d'application requis est manquant, renvoyez une requesting_google_scopes action pour inviter l'utilisateur à fournir les champs d'application manquants.

    Node.js

    // Check for authorized scopes.
    const authorizedScopes = req.body.authorizationEventObject?.authorizedScopes || [];
    if (!authorizedScopes.includes('https://www.googleapis.com/auth/chat.messages')) {
      // Respond with a request for the missing scope.
      res.send({
        'requesting_google_scopes': {
          'scopes': ['https://www.googleapis.com/auth/chat.messages']
        }
      });
      return;
    }
    

    Python

    from flask import jsonify, request
    
    # Check for authorized scopes.
    event_data = request.get_json()
    authorized_scopes = event_data.get('authorizationEventObject', {}).get('authorizedScopes', [])
    if 'https://www.googleapis.com/auth/chat.messages' not in authorized_scopes:
        # Respond with a request for the missing scope.
        return jsonify({
            'requesting_google_scopes': {
                'scopes': ['https://www.googleapis.com/auth/chat.messages']
            }
        })
    

    Java

    import com.google.gson.JsonArray;
    import com.google.gson.JsonObject;
    import java.util.List;
    
    // Check for authorized scopes.
    List<String> authorizedScopes = event.getAuthorizationEventObject() != null
        ? event.getAuthorizationEventObject().getAuthorizedScopes()
        : null;
    if (authorizedScopes == null || !authorizedScopes.contains("https://www.googleapis.com/auth/chat.messages")) {
      // Respond with a request for the missing scope.
      JsonObject requestingGoogleScopes = new JsonObject();
      JsonArray scopes = new JsonArray();
      scopes.add("https://www.googleapis.com/auth/chat.messages");
      requestingGoogleScopes.add("scopes", scopes);
    
      JsonObject response = new JsonObject();
      response.add("requesting_google_scopes", requestingGoogleScopes);
      return response.toString();
    }
    

    Pour demander tous les champs d'application associés au module complémentaire, définissez all_scopes sur true :

    Node.js

    res.send({
      'requesting_google_scopes': { 'all_scopes': true }
    });
    

    Python

    from flask import jsonify
    
    return jsonify({
        'requesting_google_scopes': { 'all_scopes': True }
    })
    

    Java

    import com.google.gson.JsonObject;
    
    JsonObject requestingGoogleScopes = new JsonObject();
    requestingGoogleScopes.addProperty("all_scopes", true);
    
    JsonObject response = new JsonObject();
    response.add("requesting_google_scopes", requestingGoogleScopes);
    return response.toString();
    

Pour obtenir des instructions détaillées, consultez Gérer les autorisations granulaires pour les modules complémentaires Google Workspace HTTP.

Applications Chat HTTP autonomes

Si votre application Chat est un service HTTP autonome (et non un module complémentaire Google Workspace), vous gérez vous-même le flux OAuth 2.0.

Lorsque vous récupérez un jeton stocké ou échangez un code d'autorisation, vérifiez les champs d'application qui ont été accordés. Si des champs d'application requis sont manquants, invitez l'utilisateur à les autoriser.

Node.js

// 1. List authorized scopes.
const fs = require('fs');
const tokens = JSON.parse(fs.readFileSync('token.json'));
const grantedScopes = tokens.scope.split(' ');

// 2. Detect missing scopes.
const requiredScopes = ['https://www.googleapis.com/auth/chat.messages'];
const missingScopes = requiredScopes.filter(scope => !grantedScopes.includes(scope));

if (missingScopes.length > 0) {
  // 3. Request missing scopes.
  const authUrl = oauth2Client.generateAuthUrl({
    access_type: 'offline',
    scope: missingScopes,
    include_granted_scopes: true
  });
  res.redirect(authUrl);
}

// To request all scopes instead of just the missing ones:
const allScopesAuthUrl = oauth2Client.generateAuthUrl({
  access_type: 'offline',
  scope: requiredScopes,
  include_granted_scopes: true
});

Python

from flask import redirect
from google.oauth2.credentials import Credentials

# 1. List authorized scopes.
credentials = Credentials.from_authorized_user_file('token.json')
granted_scopes = set(credentials.scopes)

# 2. Detect missing scopes.
required_scopes = {'https://www.googleapis.com/auth/chat.messages'}
missing_scopes = required_scopes - granted_scopes

if missing_scopes:
    # 3. Request missing scopes.
    flow.scope = list(missing_scopes)
    auth_url, _ = flow.authorization_url(
        access_type='offline',
        include_granted_scopes=True
    )
    return redirect(auth_url)

# To request all scopes instead of just the missing ones:
flow.scope = list(required_scopes)
all_scopes_auth_url, _ = flow.authorization_url(
    access_type='offline',
    include_granted_scopes='true'
)

Java

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeRequestUrl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

// 1. List authorized scopes.
// The "user" string is the user ID for which to load credentials.
Credential credential = flow.loadCredential("user");
Collection<String> grantedScopes = credential.getScopes();

// 2. Detect missing scopes.
// The `requiredScopes` variable contains a list of the OAuth scopes
// that your app requires to function. Define this variable with the
// scopes needed by your application.
List<String> requiredScopes = Arrays.asList("https://www.googleapis.com/auth/chat.messages");
List<String> missingScopes = new ArrayList<>();
for (String scope : requiredScopes) {
  if (!grantedScopes.contains(scope)) {
    missingScopes.add(scope);
  }
}

if (!missingScopes.isEmpty()) {
  // 3. Request missing scopes.
  GoogleAuthorizationCodeRequestUrl urlBuilder = new GoogleAuthorizationCodeRequestUrl(
      clientId, redirectUri, missingScopes)
      .setAccessType("offline")
      .set("include_granted_scopes", "true");
  String authUrl = urlBuilder.build();
  response.sendRedirect(authUrl);
}

// To request all scopes instead of just the missing ones:
GoogleAuthorizationCodeRequestUrl allScopesUrlBuilder = new GoogleAuthorizationCodeRequestUrl(
    clientId, redirectUri, requiredScopes)
    .setAccessType("offline")
    .set("include_granted_scopes", "true");
String allScopesAuthUrl = allScopesUrlBuilder.build();

Pour en savoir plus, consultez Autorisations OAuth granulaires.