
Si votre module complémentaire Google Workspace se connecte à un service ou à une API tiers nécessitant une autorisation, il peut inviter les utilisateurs à se connecter et à autoriser l'accès.
Cette page explique comment authentifier les utilisateurs à l'aide d'un flux d'autorisation (tel qu'OAuth), qui comprend les étapes suivantes :
- Détecter les cas où une autorisation est requise
- Renvoie une interface de carte qui invite les utilisateurs à se connecter au service.
- Actualisez le module complémentaire pour que les utilisateurs puissent accéder au service ou à la ressource protégée.
Si votre module complémentaire ne nécessite que l'identité de l'utilisateur, vous pouvez authentifier directement les utilisateurs à l'aide de leur adresse e-mail ou de leur ID Google Workspace. Pour utiliser l'adresse e-mail pour l'authentification, consultez Valider les requêtes JSON. Si vous avez créé votre module complémentaire à l'aide de Google Apps Script, vous pouvez simplifier ce processus en utilisant la bibliothèque OAuth2 pour Google Apps Script (il existe également une version OAuth1).
Détecter qu'une autorisation est requise
Lorsqu'ils utilisent votre module complémentaire, les utilisateurs peuvent ne pas être autorisés à accéder à une ressource protégée pour diverses raisons, par exemple :
- Un jeton d'accès pour se connecter au service tiers n'a pas encore été généré ou a expiré.
- Le jeton d'accès ne couvre pas la ressource demandée.
- Le jeton d'accès ne couvre pas les champs d'application requis par la requête.
Votre module complémentaire doit détecter ces cas pour que les utilisateurs puissent se connecter et accéder à votre service.
Si vous développez dans Apps Script, la fonction hasAccess()
de la bibliothèque OAuth peut vous indiquer si vous avez accès à un service.
Vous pouvez également définir le paramètre muteHttpExceptions
sur true
lorsque vous utilisez des requêtes UrlFetchApp fetch()
. Cela empêche la requête de générer une exception en cas d'échec et vous permet d'examiner le code de réponse et le contenu de la requête dans l'objet HttpResponse
renvoyé.
Inviter les utilisateurs à se connecter à votre service
Lorsque votre module complémentaire détecte qu'une autorisation est requise, il doit renvoyer une interface card pour inviter les utilisateurs à se connecter au service. La fiche de connexion doit rediriger les utilisateurs pour qu'ils effectuent le processus d'authentification et d'autorisation tiers sur votre infrastructure.
Lorsque vous créez votre module complémentaire à l'aide de points de terminaison HTTP, nous vous recommandons de protéger l'application de destination avec Se connecter avec Google et d'obtenir l'ID utilisateur à l'aide du jeton d'identité émis lors de la connexion. La revendication "sub" contient l'ID unique de l'utilisateur et peut être mise en corrélation avec l'ID de votre module complémentaire.
Créer et renvoyer une fiche de connexion
Pour la fiche de connexion de votre service, vous pouvez utiliser la fiche d'autorisation de base de Google ou personnaliser une fiche pour afficher des informations supplémentaires, comme le logo de votre organisation. Si vous publiez votre module complémentaire publiquement, vous devez utiliser une fiche personnalisée.
Carte d'autorisation de base
L'image suivante montre un exemple de carte d'autorisation de base de Google :

Pour inviter les utilisateurs à utiliser une carte d'autorisation de base, vous devez renvoyer l'objet AuthorizationError
. Le code suivant montre un exemple d'objet AuthorizationError
:
Apps Script
CardService.newAuthorizationException() .setAuthorizationUrl('AUTHORIZATION_URL') .setResourceDisplayName('RESOURCE_DISPLAY_NAME') .throwException();
JSON
Renvoie la réponse JSON suivante :
{
"basic_authorization_prompt": {
"authorization_url": "AUTHORIZATION_URL",
"resource": "RESOURCE_DISPLAY_NAME"
}
}
Remplacez les éléments suivants :
AUTHORIZATION_URL
: URL de l'application Web qui gère l'autorisation.RESOURCE_DISPLAY_NAME
: nom à afficher de la ressource ou du service protégés. Ce nom est affiché pour l'utilisateur dans l'invite d'autorisation. Par exemple, si votreRESOURCE_DISPLAY_NAME
estExample Account
, l'invite indique "Ce module complémentaire a besoin de votre autorisation pour accéder à votre compte Exemple afin d'afficher d'autres informations".
Une fois l'autorisation accordée, l'utilisateur est invité à actualiser le module complémentaire pour accéder à la ressource protégée.
Cartes d'autorisation de retour dans Google Chat
Si votre module complémentaire étend Google Chat et que l'utilisateur l'exécute dans Google Chat, il peut effectuer le processus d'autorisation sans actualisation manuelle. Google Chat permet de réessayer automatiquement l'exécution précédente si le déclencheur est Message, Ajouté à l'espace ou Commande d'application. Pour ces déclencheurs, votre module complémentaire reçoit completeRedirectUri
dans la charge utile de l'événement.
Vous devez encoder completeRedirectUri
dans votre URL de configuration pour déclencher la nouvelle tentative automatique. La redirection vers cette URL indique à Google Chat que la demande de configuration a été traitée et permet à Google Chat de réessayer l'exécution précédente.
Lorsqu'un utilisateur est redirigé vers l'configCompleteRedirectUrl
fourni dans le message d'origine, Google Chat effectue les étapes suivantes :
- Efface l'invite affichée pour l'utilisateur à l'origine de la demande.
- Envoie l'objet événement d'origine au même module complémentaire une deuxième fois.
Si vous n'encodez pas completeRedirectUri
dans l'URL de configuration, l'utilisateur peut toujours effectuer le flux d'autorisation. Toutefois, Google Chat ne relance pas l'exécution précédente, et l'utilisateur doit invoquer manuellement votre module complémentaire.
L'exemple de code suivant montre comment une application Chat peut demander des identifiants OAuth2 hors connexion, les stocker dans une base de données et les utiliser pour effectuer des appels d'API avec authentification de l'utilisateur.
Apps Script
Node.js
Python
Java
Carte d'autorisation personnalisée
Pour modifier l'invite d'autorisation, vous pouvez créer une fiche personnalisée pour l'expérience de connexion de votre service.
Si vous publiez votre module complémentaire publiquement, vous devez utiliser une fiche d'autorisation personnalisée pour toutes les applications hôtes Google Workspace, à l'exception de Chat. Pour en savoir plus sur les exigences de publication sur Google Workspace Marketplace, consultez À propos de l'examen des applications.
La carte renvoyée doit :
- Indiquez clairement à l'utilisateur que le module complémentaire demande l'autorisation d'accéder à un service non Google en son nom.
- Indiquez clairement ce que le module complémentaire peut faire s'il est autorisé.
- Contenir un bouton ou un widget similaire qui redirige l'utilisateur vers l'URL d'autorisation du service. Assurez-vous que la fonction de ce widget est évidente pour l'utilisateur.
- Le widget ci-dessus doit utiliser le paramètre
OnClose.RELOAD
dans son objetOpenLink
pour s'assurer que le module complémentaire se recharge une fois l'autorisation reçue. - Tous les liens ouverts à partir de l'invite d'autorisation doivent utiliser HTTPS.
L'image ci-dessous montre un exemple de fiche d'autorisation personnalisée pour la page d'accueil d'un module complémentaire. La fiche inclut un logo, une description et un bouton de connexion :

Le code suivant montre comment utiliser cet exemple de carte personnalisée :
Apps Script
function customAuthorizationCard() {
let cardSection1Image1 = CardService.newImage()
.setImageUrl('LOGO_URL')
.setAltText('LOGO_ALT_TEXT');
let cardSection1Divider1 = CardService.newDivider();
let cardSection1TextParagraph1 = CardService.newTextParagraph()
.setText('DESCRIPTION');
let cardSection1ButtonList1Button1 = CardService.newTextButton()
.setText('Sign in')
.setBackgroundColor('#0055ff')
.setTextButtonStyle(CardService.TextButtonStyle.FILLED)
.setAuthorizationAction(CardService.newAuthorizationAction()
.setAuthorizationUrl('AUTHORIZATION_URL'));
let cardSection1ButtonList1 = CardService.newButtonSet()
.addButton(cardSection1ButtonList1Button1);
let cardSection1TextParagraph2 = CardService.newTextParagraph()
.setText('TEXT_SIGN_UP');
let cardSection1 = CardService.newCardSection()
.addWidget(cardSection1Image1)
.addWidget(cardSection1Divider1)
.addWidget(cardSection1TextParagraph1)
.addWidget(cardSection1ButtonList1)
.addWidget(cardSection1TextParagraph2);
let card = CardService.newCardBuilder()
.addSection(cardSection1)
.build();
return [card];
}
function startNonGoogleAuth() {
CardService.newAuthorizationException()
.setAuthorizationUrl('AUTHORIZATION_URL')
.setResourceDisplayName('RESOURCE_DISPLAY_NAME')
.setCustomUiCallback('customAuthorizationCard')
.throwException();
}
JSON
Renvoie la réponse JSON suivante :
{
"custom_authorization_prompt": {
"action": {
"navigations": [
{
"pushCard": {
"sections": [
{
"widgets": [
{
"image": {
"imageUrl": "LOGO_URL",
"altText": "LOGO_ALT_TEXT"
}
},
{
"divider": {}
},
{
"textParagraph": {
"text": "DESCRIPTION"
}
},
{
"buttonList": {
"buttons": [
{
"text": "Sign in",
"onClick": {
"openLink": {
"url": "AUTHORIZATION_URL",
"onClose": "RELOAD",
"openAs": "OVERLAY"
}
},
"color": {
"red": 0,
"green": 0,
"blue": 1,
"alpha": 1,
}
}
]
}
},
{
"textParagraph": {
"text": "TEXT_SIGN_UP"
}
}
]
}
]
}
}
]
}
}
}
Remplacez les éléments suivants :
LOGO_URL
: URL d'un logo ou d'une image. L'URL doit être publique.LOGO_ALT_TEXT
: texte alternatif pour le logo ou l'image, tel queCymbal Labs Logo
.DESCRIPTION
: un appel à l'action invitant les utilisateurs à se connecter, par exempleSign in to get started
.- Pour mettre à jour le bouton de connexion :
AUTHORIZATION_URL
: URL de l'application Web qui gère l'autorisation.- Facultatif : Pour modifier la couleur du bouton, mettez à jour les valeurs float RVBA du champ
color
. Pour Apps Script, mettez à jour la méthodesetBackgroundColor()
à l'aide de valeurs hexadécimales.
TEXT_SIGN_UP
: texte invitant les utilisateurs à créer un compte s'ils n'en ont pas. Exemple :New to Cymbal Labs? <a href=\"https://www.example.com/signup\">Sign up</a> here
Gérer les identifiants tiers dans les applications Google Workspace
Une application courante des modules complémentaires Google Workspace consiste à fournir une interface permettant d'interagir avec un système tiers à partir d'une application hôte Google Workspace.
Les systèmes tiers exigent souvent que l'utilisateur se connecte à l'aide d'un ID utilisateur, d'un mot de passe ou d'autres identifiants. Lorsqu'un utilisateur se connecte à votre service tiers alors qu'il utilise un hôte Google Workspace, vous devez vous assurer qu'il n'a pas besoin de se reconnecter lorsqu'il passe à un autre hôte Google Workspace.
Si vous développez dans Apps Script, vous pouvez éviter les demandes de connexion répétées avec les propriétés utilisateur ou les jetons d'identité. Ces éléments sont expliqués dans les sections suivantes.
Propriétés utilisateur
Vous pouvez stocker les données de connexion d'un utilisateur dans les propriétés utilisateur d'Apps Script. Par exemple, vous pouvez créer votre propre jeton Web JSON (JWT) à partir de leur service de connexion et l'enregistrer dans une propriété utilisateur, ou enregistrer le nom d'utilisateur et le mot de passe de leur service.
Les propriétés utilisateur sont limitées de sorte qu'elles ne sont accessibles qu'à cet utilisateur dans le script de votre module complémentaire. Les autres utilisateurs et scripts ne peuvent pas accéder à ces propriétés. Pour plus d'informations, consultez la section PropertiesService
.
Jetons d'ID
Vous pouvez utiliser un jeton d'ID Google comme identifiant de connexion pour votre service. Il s'agit d'une méthode d'authentification unique. Les utilisateurs sont déjà connectés à Google, car ils se trouvent dans une application hôte Google.
Exemple de configuration OAuth non Google
L'exemple de code Apps Script suivant montre comment configurer un module complémentaire pour utiliser une API non Google nécessitant OAuth. Cet exemple utilise la bibliothèque OAuth2 pour Apps Script pour créer un service permettant d'accéder à l'API.
Apps Script
/**
* Attempts to access a non-Google API using a constructed service
* object.
*
* If your add-on needs access to non-Google APIs that require OAuth,
* you need to implement this method. You can use the OAuth1 and
* OAuth2 Apps Script libraries to help implement it.
*
* @param {String} url The URL to access.
* @param {String} method_opt The HTTP method. Defaults to GET.
* @param {Object} headers_opt The HTTP headers. Defaults to an empty
* object. The Authorization field is added
* to the headers in this method.
* @return {HttpResponse} the result from the UrlFetchApp.fetch() call.
*/
function accessProtectedResource(url, method_opt, headers_opt) {
var service = getOAuthService();
var maybeAuthorized = service.hasAccess();
if (maybeAuthorized) {
// A token is present, but it may be expired or invalid. Make a
// request and check the response code to be sure.
// Make the UrlFetch request and return the result.
var accessToken = service.getAccessToken();
var method = method_opt || 'get';
var headers = headers_opt || {};
headers['Authorization'] =
Utilities.formatString('Bearer %s', accessToken);
var resp = UrlFetchApp.fetch(url, {
'headers': headers,
'method' : method,
'muteHttpExceptions': true, // Prevents thrown HTTP exceptions.
});
var code = resp.getResponseCode();
if (code >= 200 && code < 300) {
return resp.getContentText("utf-8"); // Success
} else if (code == 401 || code == 403) {
// Not fully authorized for this action.
maybeAuthorized = false;
} else {
// Handle other response codes by logging them and throwing an
// exception.
console.error("Backend server error (%s): %s", code.toString(),
resp.getContentText("utf-8"));
throw ("Backend server error: " + code);
}
}
if (!maybeAuthorized) {
// Invoke the authorization flow using the default authorization
// prompt card.
CardService.newAuthorizationException()
.setAuthorizationUrl(service.getAuthorizationUrl())
.setResourceDisplayName("Display name to show to the user")
.throwException();
}
}
/**
* Create a new OAuth service to facilitate accessing an API.
* This example assumes there is a single service that the add-on needs to
* access. Its name is used when persisting the authorized token, so ensure
* it is unique within the scope of the property store. You must set the
* client secret and client ID, which are obtained when registering your
* add-on with the API.
*
* See the Apps Script OAuth2 Library documentation for more
* information:
* https://github.com/googlesamples/apps-script-oauth2#1-create-the-oauth2-service
*
* @return A configured OAuth2 service object.
*/
function getOAuthService() {
return OAuth2.createService('SERVICE_NAME')
.setAuthorizationBaseUrl('SERVICE_AUTH_URL')
.setTokenUrl('SERVICE_AUTH_TOKEN_URL')
.setClientId('CLIENT_ID')
.setClientSecret('CLIENT_SECRET')
.setScope('SERVICE_SCOPE_REQUESTS')
.setCallbackFunction('authCallback')
.setCache(CacheService.getUserCache())
.setPropertyStore(PropertiesService.getUserProperties());
}
/**
* Boilerplate code to determine if a request is authorized and returns
* a corresponding HTML message. When the user completes the OAuth2 flow
* on the service provider's website, this function is invoked from the
* service. In order for authorization to succeed you must make sure that
* the service knows how to call this function by setting the correct
* redirect URL.
*
* The redirect URL to enter is:
* https://script.google.com/macros/d/<Apps Script ID>/usercallback
*
* See the Apps Script OAuth2 Library documentation for more
* information:
* https://github.com/googlesamples/apps-script-oauth2#1-create-the-oauth2-service
*
* @param {Object} callbackRequest The request data received from the
* callback function. Pass it to the service's
* handleCallback() method to complete the
* authorization process.
* @return {HtmlOutput} a success or denied HTML message to display to
* the user.
*/
function authCallback(callbackRequest) {
var authorized = getOAuthService().handleCallback(callbackRequest);
if (authorized) {
return HtmlService.createHtmlOutput(
'Success!');
} else {
return HtmlService.createHtmlOutput('Denied');
}
}
/**
* Unauthorizes the non-Google service. This is useful for OAuth
* development/testing. Run this method (Run > resetOAuth in the script
* editor) to reset OAuth to re-prompt the user for OAuth.
*/
function resetOAuth() {
getOAuthService().reset();
}