Google Workspace-Add-on mit einem Drittanbieterdienst verknüpfen

Eine benutzerdefinierte Autorisierungskarte aus einer Linkvorschau mit dem Logo des Unternehmens, einer Beschreibung und einer Schaltfläche zum Anmelden.
Eine Anmeldekartenoberfläche für ein Add-on, in dem Links von einem Drittanbieterdienst in der Vorschau angezeigt werden.

Wenn Ihr Google Workspace-Add-on eine Verbindung zu einem Drittanbieterdienst oder einer Drittanbieter-API herstellt, für die eine Autorisierung erforderlich ist, kann das Add-on Nutzer auffordern, sich anzumelden und den Zugriff zu autorisieren.

Auf dieser Seite wird beschrieben, wie Sie Nutzer mithilfe eines Autorisierungsablaufs (z. B. OAuth) authentifizieren. Dazu sind die folgenden Schritte erforderlich:

  1. Erkennen, wann eine Autorisierung erforderlich ist
  2. Gibt eine Kartenoberfläche zurück, in der Nutzer aufgefordert werden, sich im Dienst anzumelden.
  3. Aktualisieren Sie das Add-on, damit Nutzer auf den Dienst oder die geschützte Ressource zugreifen können.

Wenn für Ihr Add-on nur die Nutzeridentität erforderlich ist, können Sie Nutzer direkt mit ihrer Google Workspace-ID oder E-Mail-Adresse authentifizieren. Informationen zur Verwendung der E-Mail-Adresse für die Authentifizierung finden Sie unter JSON-Anfragen validieren. Wenn Sie Ihr Add‑on mit Google Apps Script erstellt haben, können Sie diesen Prozess vereinfachen, indem Sie die OAuth2-Bibliothek für Google Apps Script verwenden. Es gibt auch eine OAuth1-Version.

Erkennen, dass eine Autorisierung erforderlich ist

Wenn Nutzer Ihr Add-on verwenden, sind sie möglicherweise aus verschiedenen Gründen nicht autorisiert, auf eine geschützte Ressource zuzugreifen, z. B. aus folgenden:

  • Es wurde noch kein Zugriffstoken für die Verbindung zum Drittanbieterdienst generiert oder das Zugriffstoken ist abgelaufen.
  • Das Zugriffstoken deckt die angeforderte Ressource nicht ab.
  • Der Zugriffstoken deckt die für die Anfrage erforderlichen Bereiche nicht ab.

Ihr Add-on sollte diese Fälle erkennen, damit Nutzer sich anmelden und auf Ihren Dienst zugreifen können.

Wenn Sie Apps Script verwenden, können Sie mit der Funktion hasAccess() der OAuth-Bibliothek prüfen, ob Sie Zugriff auf einen Dienst haben. Alternativ können Sie bei Verwendung von UrlFetchApp fetch()-Anfragen den Parameter muteHttpExceptions auf true festlegen. Dadurch wird verhindert, dass bei einem Fehler in der Anfrage eine Ausnahme ausgelöst wird. Sie können den Antwortcode und den Inhalt der Anfrage im zurückgegebenen HttpResponse-Objekt untersuchen.

Nutzer auffordern, sich bei Ihrem Dienst anzumelden

Wenn Ihr Add-on erkennt, dass eine Autorisierung erforderlich ist, muss es eine card-Schnittstelle zurückgeben, um Nutzer aufzufordern, sich beim Dienst anzumelden. Die Anmeldekarte muss Nutzer weiterleiten, damit sie den Authentifizierungs- und Autorisierungsprozess des Drittanbieters auf Ihrer Infrastruktur abschließen können.

Wenn Sie Ihr Add-on mit HTTP-Endpunkten erstellen, empfehlen wir, die Zielanwendung mit Google Log-in zu schützen und die Nutzer-ID mit dem Identitätstoken abzurufen, das bei der Anmeldung ausgestellt wird. Die sub-Anforderung enthält die eindeutige ID des Nutzers und kann mit der ID aus Ihrem Add-on verknüpft werden.

, bevor Sie die bestätigte Nutzer-ID akzeptieren.

Anmeldekarte erstellen und zurückgeben

Für die Anmeldekarte Ihres Dienstes können Sie die Karte für die grundlegende Autorisierung von Google verwenden oder eine Karte anpassen, um zusätzliche Informationen wie das Logo Ihrer Organisation anzuzeigen. Wenn Sie Ihr Add-on öffentlich veröffentlichen, müssen Sie eine benutzerdefinierte Karte verwenden.

Einfache Autorisierungskarte

Das folgende Bild zeigt ein Beispiel für die grundlegende Autorisierungskarte von Google:

Aufforderung zur grundlegenden Autorisierung für das Beispielkonto Im Prompt wird angegeben, dass das Add-on zusätzliche Informationen anzeigen möchte, aber die Genehmigung des Nutzers für den Zugriff auf das Konto benötigt.

Wenn Sie Nutzern eine einfache Autorisierungskarte präsentieren möchten, müssen Sie das Objekt AuthorizationError zurückgeben. Der folgende Code zeigt ein Beispiel für ein AuthorizationError-Objekt:

Apps Script

CardService.newAuthorizationException()
    .setAuthorizationUrl('AUTHORIZATION_URL')
    .setResourceDisplayName('RESOURCE_DISPLAY_NAME')
    .throwException();

JSON

Geben Sie die folgende JSON-Antwort zurück:

{
  "basic_authorization_prompt": {
    "authorization_url": "AUTHORIZATION_URL",
    "resource": "RESOURCE_DISPLAY_NAME"
  }
}

Ersetzen Sie Folgendes:

  • AUTHORIZATION_URL: Die URL für die Web-App, die die Autorisierung übernimmt.
  • RESOURCE_DISPLAY_NAME: Der Anzeigename für die geschützte Ressource oder den geschützten Dienst. Dieser Name wird dem Nutzer in der Autorisierungsaufforderung angezeigt. Wenn Ihr RESOURCE_DISPLAY_NAME beispielsweise Example Account ist, wird in der Aufforderung Folgendes angezeigt: „Über dieses Add-on können zusätzliche Informationen angezeigt werden. Allerdings ist dafür der Zugriff auf Ihr Beispielkonto erforderlich.“

Nach Abschluss der Autorisierung wird der Nutzer aufgefordert, das Add-on zu aktualisieren, um auf die geschützte Ressource zuzugreifen.

Autorisierungskarten in Google Chat zurückgeben

Wenn Ihr Add-on Google Chat erweitert und der Nutzer es in Google Chat ausführt, kann der Nutzer den Autorisierungsprozess ohne manuelles Aktualisieren abschließen. Google Chat unterstützt das automatische Wiederholen der vorherigen Ausführung, wenn der Trigger Nachricht, Zum Gruppenbereich hinzugefügt oder App-Befehl ist. Bei diesen Triggern erhält Ihr Add-on completeRedirectUri in der Ereignisnutzlast. Sie müssen completeRedirectUri in Ihrer Konfigurations-URL codieren, um einen automatischen Wiederholungsversuch auszulösen. Durch die Weiterleitung zu dieser URL wird Google Chat signalisiert, dass die Konfigurationsanfrage erfüllt wurde. Google Chat kann dann die vorherige Ausführung noch einmal versuchen.

Wenn ein Nutzer erfolgreich zur configCompleteRedirectUrl weitergeleitet wird, die in der ursprünglichen Nachricht angegeben ist, führt Google Chat die folgenden Schritte aus:

  1. Löscht den Prompt, der dem Nutzer angezeigt wird, der die Aktion initiiert hat.
  2. Das ursprüngliche Ereignisobjekt wird ein zweites Mal an dasselbe Add-on gesendet.

Wenn Sie completeRedirectUri nicht in der Konfigurations-URL codieren, kann der Nutzer den Autorisierungsvorgang trotzdem abschließen. Google Chat versucht jedoch nicht, die vorherige Ausführung noch einmal auszuführen, und der Nutzer muss Ihr Add-on manuell noch einmal aufrufen.

Das folgende Codebeispiel zeigt, wie eine Chat-App Offline-OAuth2-Anmeldedaten anfordern, in einer Datenbank speichern und damit API-Aufrufe mit Nutzerauthentifizierung ausführen kann.

Benutzerdefinierte Autorisierungskarte

Wenn Sie die Autorisierungsaufforderung ändern möchten, können Sie eine benutzerdefinierte Karte für die Anmeldeseite Ihres Dienstes erstellen.

Wenn Sie Ihr Add‑on öffentlich veröffentlichen, müssen Sie für alle Google Workspace-Hostanwendungen außer Chat eine benutzerdefinierte Autorisierungskarte verwenden. Weitere Informationen zu den Veröffentlichungsanforderungen für den Google Workspace Marketplace finden Sie unter App-Überprüfung.

Die zurückgegebene Karte muss Folgendes tun:

  • Machen Sie dem Nutzer deutlich, dass das Add-on um die Berechtigung bittet, in seinem Namen auf einen Nicht-Google-Dienst zuzugreifen.
  • Machen Sie deutlich, was das Add‑on tun kann, wenn es autorisiert ist.
  • Sie enthalten eine Schaltfläche oder ein ähnliches Widget, über das Nutzer zur Autorisierungs-URL des Dienstes weitergeleitet werden. Die Funktion dieses Widgets muss für den Nutzer offensichtlich sein.
  • Für das oben genannte Widget muss die Einstellung OnClose.RELOAD im OpenLink-Objekt verwendet werden, damit das Add-on neu geladen wird, nachdem die Autorisierung erfolgt ist.
  • Alle Links, die über die Autorisierungsaufforderung geöffnet werden, müssen HTTPS verwenden.

Das folgende Bild zeigt ein Beispiel für eine benutzerdefinierte Autorisierungskarte für die Startseite eines Add-ons. Die Karte enthält ein Logo, eine Beschreibung und eine Schaltfläche zum Anmelden:

Eine benutzerdefinierte Autorisierungskarte für Cymbal Labs, die das Unternehmenslogo, eine Beschreibung und eine Anmeldeschaltfläche enthält.

Der folgende Code zeigt, wie Sie dieses Beispiel für eine benutzerdefinierte Karte verwenden:

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

Geben Sie die folgende JSON-Antwort zurück:

{
  "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"
                    }
                  }
                ]
              }
            ]
          }
        }
      ]
    }
  }
}

Ersetzen Sie Folgendes:

  • LOGO_URL: Die URL für ein Logo oder Bild. Muss eine öffentliche URL sein.
  • LOGO_ALT_TEXT: Alt-Text für das Logo oder Bild, z. B. Cymbal Labs Logo.
  • DESCRIPTION: Ein Call-to-Action für Nutzer, sich anzumelden, z. B. Sign in to get started.
  • So aktualisieren Sie die Anmeldeschaltfläche:
    • AUTHORIZATION_URL: Die URL für die Web-App, die die Autorisierung übernimmt.
    • Optional: Wenn Sie die Schaltflächenfarbe ändern möchten, aktualisieren Sie die RGBA-Gleitkommawerte des Felds color. Aktualisieren Sie für Apps Script die Methode setBackgroundColor() mit Hexadezimalwerten.
  • TEXT_SIGN_UP: Ein Text, der Nutzer auffordert, ein Konto zu erstellen, wenn sie noch keines haben. Beispiel: New to Cymbal Labs? <a href=\"https://www.example.com/signup\">Sign up</a> here.

Anmeldungen von Drittanbietern in Google Workspace-Apps verwalten

Eine häufige Anwendung für Google Workspace-Add-ons ist die Bereitstellung einer Schnittstelle für die Interaktion mit einem Drittanbietersystem aus einer Hostanwendung von Google Workspace heraus.

Bei Drittanbietersystemen ist häufig eine Anmeldung mit einer Nutzer-ID, einem Passwort oder anderen Anmeldedaten erforderlich. Wenn sich ein Nutzer in Ihrem Drittanbieterdienst anmeldet, während er einen Google Workspace-Host verwendet, müssen Sie dafür sorgen, dass er sich nicht noch einmal anmelden muss, wenn er zu einem anderen Google Workspace-Host wechselt.

Wenn Sie Apps Script verwenden, können Sie wiederholte Anmeldeanfragen mit Nutzereigenschaften oder ID-Tokens verhindern. Diese werden in den folgenden Abschnitten erläutert.

Nutzereigenschaften

Sie können die Anmeldedaten eines Nutzers in den Nutzereigenschaften von Apps Script speichern. Sie könnten beispielsweise ein eigenes JSON Web Token (JWT) aus dem Anmeldedienst erstellen und in einer Nutzer-Property speichern oder den Nutzernamen und das Passwort für den Dienst aufzeichnen.

Nutzereigenschaften sind so konfiguriert, dass sie nur für den jeweiligen Nutzer im Script Ihres Add-ons zugänglich sind. Andere Nutzer und andere Skripts können nicht auf diese Eigenschaften zugreifen. Unter PropertiesService finden Sie weitere Informationen.

ID-Tokens

Sie können ein Google-ID-Token als Anmeldedaten für Ihren Dienst verwenden. Dies ist eine Möglichkeit, die Einmalanmeldung zu erreichen. Nutzer sind bereits in Google angemeldet, da sie sich in einer Google-Host-App befinden.

Beispiel für die OAuth-Konfiguration für Nicht-Google-Konten

Das folgende Apps Script-Codebeispiel zeigt, wie Sie ein Add-on für die Verwendung einer Nicht-Google-API konfigurieren, für die OAuth erforderlich ist. In diesem Beispiel wird die OAuth2 for Apps Script-Bibliothek verwendet, um einen Dienst für den Zugriff auf die API zu erstellen.

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