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 que OAuth), qui comprend les étapes suivantes:
- Détectez les cas où une autorisation est requise.
- Renvoyez une interface de carte qui invite les utilisateurs à se connecter au service.
- Actualisez le module complémentaire afin 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 l'authentifier directement à l'aide de son ID Google Workspace ou de son adresse e-mail. Pour utiliser l'adresse e-mail à des fins d'authentification, consultez la section 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 (une version OAuth1 est également disponible).
Détecter qu'une autorisation est requise
Lorsque vous utilisez 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 est arrivé à expiration.
- 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 de la requête.
Votre module complémentaire doit détecter ces cas afin que les utilisateurs puissent se connecter et accéder à votre service.
Si vous créez une application 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 et le contenu de la réponse 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 de fiche pour inviter les utilisateurs à se connecter au service. La fiche de connexion doit rediriger les utilisateurs vers 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 Connexion Google et d'obtenir l'ID utilisateur à l'aide du jeton d'identité émis lors de la connexion. La sous-revendication 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 fiche d'autorisation de base de Google:
Le code suivant illustre l'utilisation de la fiche d'autorisation de base de Google:
Apps Script
CardService.newAuthorizationException() .setAuthorizationUrl('AUTHORIZATION_URL') .setResourceDisplayName('RESOURCE_DISPLAY_NAME') .throwException();
JSON
Renvoyez 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é. Ce nom s'affiche pour l'utilisateur dans l'invite d'autorisation. Par exemple, si votreRESOURCE_DISPLAY_NAME
estExample Account
, l'invite indique "Ce module complémentaire souhaite afficher des informations supplémentaires, mais il a besoin d'être approuvé pour accéder à votre compte Exemple".
Une fois l'autorisation terminée, l'utilisateur est invité à actualiser le module complémentaire pour accéder à la ressource protégée.
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 en savoir plus sur les conditions requises pour la 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 autre que 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 suivante montre un exemple de fiche d'autorisation personnalisée pour la page d'accueil d'un module complémentaire. La fiche comprend un logo, une description et un bouton de connexion:
Le code suivant montre comment utiliser cet exemple de fiche 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
Renvoyez 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. Il doit s'agir d'une URL publique.LOGO_ALT_TEXT
: texte alternatif du logo ou de l'image, par exempleCymbal Labs Logo
.DESCRIPTION
: incitation à l'action pour que les utilisateurs se connectent, 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, modifiez les valeurs de 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 connexions tierces dans les applications Google Workspace
Les modules complémentaires Google Workspace sont souvent utilisés pour 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 créez une application dans Apps Script, vous pouvez empêcher les requêtes de connexion répétées à l'aide de propriétés utilisateur ou de jetons d'ID. Ils 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 définies de sorte qu'elles ne soient accessibles qu'à cet utilisateur dans le script de votre module complémentaire. Les autres utilisateurs et les autres 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 autre que Google
L'exemple de code Apps Script suivant montre comment configurer un module complémentaire pour utiliser une API autre que 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. Also sets a timer to close the window
* automatically.
*/
function authCallback(callbackRequest) {
var authorized = getOAuthService().handleCallback(callbackRequest);
if (authorized) {
return HtmlService.createHtmlOutput(
'Success! <script>setTimeout(function() { top.window.close() }, 1);</script>');
} 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();
}