logo
Entwicklung
Suchen
Push-Anbindung (Identitäts-Handshake / Push Handoff)

Push-Anbindung (Identitäts-Handshake / Push Handoff)

Szenario: Nutzer:innen klicken auf der Seite Workspace → Erweiterungen auf die Erweiterungs-App der Entwickler:innen, und die Plattform pusht die Nutzeridentität als ?wsa=<JWT> an die Landingpage der Ziel-Erweiterungs-App. Entwickler:innen konsumieren sie auf der Landingpage, prüfen sie im Backend und wandeln sie anschließend in ihre eigene Session um.

In diesem Modus müssen Entwickler:innen den Signatur-Endpunkt der Plattform nicht aufrufen – diesen ruft das Workspace-Frontend beim Klick der Nutzer:innen aktiv auf. Entwickler:innen sind nur für „entgegennehmen und prüfen" zuständig.

End-to-End-Ablauf

loading...
sequenceDiagram
    autonumber
    actor User as Nutzer:in ruft Erweiterungs-App auf
    participant GB as GPTBots-Plattform
    participant FE as Erweiterungs-App-Landingpage
    participant BE as Erweiterungs-App-Backend

    User->>GB: Klickt App-Symbol (POST sign-token)
    GB->>GB: Prüft, ob Klickende:r Mitglied dieses workspace ist
    GB->>GB: Signiert wsa mit dem Schlüssel<br/>(5-Minuten-JWT, aud=Erweiterungs-App-Host)
    GB->>FE: Öffnet app_home_url?wsa=<JWT>

    Note over FE: consumeHandoff()<br/>liest ?wsa=, POST an Erweiterungs-App-Backend
    FE->>BE: POST /session/exchange { wsa }
    BE->>BE: verifyWsa() → identity
    BE->>BE: Baut eigene Session auf
    BE-->>FE: Gibt Session zurück (Set-Cookie)

    Note over FE: history.replaceState entfernt ?wsa=

Regeln, nach denen die Plattform die Sprung-URL generiert (Entwickler:innen müssen dies nicht implementieren):

  • Ordnet aus den Registrierungsdaten anhand der app_home_url die exakt übereinstimmende Ziel-Erweiterungs-App zu (nicht registrierte URLs werden grundsätzlich nicht signiert, um Identitätslecks zu verhindern).
  • Prüft, dass die klickende Person tatsächlich Mitglied dieses Workspace (workspace_id) ist.
  • Enthält die app_home_url bereits eine Query, wird wsa mit & angehängt; der wsa-Wert ist bereits URL-kodiert, sodass Sie ihn nach dem Auslesen nicht manuell dekodieren müssen.

Frontend: das wsa der Landingpage konsumieren

Mit dem SDK (empfohlen)

import { consumeHandoff } from '@gptbots/workspace-extension-sdk'; try { const identity = await consumeHandoff({ exchangeUrl: '/session/exchange', // Ihre eigene Backend-Prüfschnittstelle // search: location.search, // liest standardmäßig location.search // paramName: 'wsa', // Standard-Parametername wsa // strip: true, // entfernt standardmäßig nach Erfolg das wsa aus der URL }); bootYourApp(identity); } catch (e) { // Kein wsa (Nutzer:in greift direkt zu) oder Backend-Prüfung fehlgeschlagen showLoginOrError(e); }
                      
                      import { consumeHandoff } from '@gptbots/workspace-extension-sdk';

try {
  const identity = await consumeHandoff({
    exchangeUrl: '/session/exchange', // Ihre eigene Backend-Prüfschnittstelle
    // search:   location.search,     // liest standardmäßig location.search
    // paramName: 'wsa',              // Standard-Parametername wsa
    // strip:     true,              // entfernt standardmäßig nach Erfolg das wsa aus der URL
  });
  bootYourApp(identity);
} catch (e) {
  // Kein wsa (Nutzer:in greift direkt zu) oder Backend-Prüfung fehlgeschlagen
  showLoginOrError(e);
}

                    
Dieser Codeblock im schwebenden Fenster

consumeHandoff erledigt vier Dinge: ① liest ?wsa= ② POST { wsa } an exchangeUrl ③ entfernt nach Erfolg mit history.replaceState das ?wsa= ④ gibt die vom Backend zurückgesendete identity zurück.

Zeitpunkt des Entfernens: Das Token wird erst nach erfolgreichem Austausch aus der URL entfernt, damit ein einmaliger vorübergehender Fehler durch Neuladen erneut versucht werden kann. Es ist ein 5-Minuten-Einmal-Token; möchten Entwickler:innen es auch bei Fehlschlag sofort entfernen, können sie im catch manuell stripHandoffToken() aufrufen.

Keine Session aufbauen, nur Identität lesen (receive-only)

import { readHandoffToken, stripHandoffToken } from '@gptbots/workspace-extension-sdk'; const token = readHandoffToken(); // reine Funktion, gibt das rohe JWT als String oder null zurück if (token) { // Es wird dennoch empfohlen, das Token erst an Ihr Backend zu senden und mit verifyWsa zu prüfen, bevor Sie seinem Inhalt vertrauen (JWT nicht im Frontend als vertrauenswürdige Identität parsen) await fetch('/telemetry/visit', { method: 'POST', body: JSON.stringify({ wsa: token }) }); } stripHandoffToken(); // entfernt in jedem Fall das wsa aus der URL
                      
                      import { readHandoffToken, stripHandoffToken } from '@gptbots/workspace-extension-sdk';

const token = readHandoffToken();   // reine Funktion, gibt das rohe JWT als String oder null zurück
if (token) {
  // Es wird dennoch empfohlen, das Token erst an Ihr Backend zu senden und mit verifyWsa zu prüfen, bevor Sie seinem Inhalt vertrauen (JWT nicht im Frontend als vertrauenswürdige Identität parsen)
  await fetch('/telemetry/visit', { method: 'POST', body: JSON.stringify({ wsa: token }) });
}
stripHandoffToken();                // entfernt in jedem Fall das wsa aus der URL

                    
Dieser Codeblock im schwebenden Fenster

⚠️ Öffnen Sie das JWT nicht im Frontend und behandeln Sie es als vertrauenswürdige Identität. Die Signatur des JWT lässt sich nur mit dem Schlüssel prüfen, und der Schlüssel liegt ausschließlich im Backend. Das Parsen im Frontend darf nur als „nicht sicherheitsrelevanter" Anzeige-Platzhalter dienen; jede Autorisierungsentscheidung muss sich nach dem Ergebnis von verifyWsa im Backend richten.


Backend: das wsa prüfen

3.1 Mit dem SDK (empfohlen)

import { verifyWsa, WsaVerificationError } from '@gptbots/workspace-extension-verify'; app.post('/session/exchange', (req, res) => { try { const identity = verifyWsa(req.body.wsa, { secret: process.env.EXTENSION_APP_SECRET, // Tier2-per-App-Schlüssel oder Tier1-geteilter Schlüssel audience: 'app.example.com', // Erweiterungs-App-Host, muss gleich aud sein // issuer: 'gptbots-workspace', // Standard // leewaySeconds: 30, // Toleranz für Uhrenabweichung, Standard 30s // algorithms: ['HS256'], // Standard }); // Mandantentrennung: Anfrage dem identity.workspaceId zuordnen const sid = createSession(identity); res.cookie('sid', sid, { httpOnly: true, secure: true, sameSite: 'lax' }); res.json(identity); } catch (e) { const code = e instanceof WsaVerificationError ? e.code : 'Error'; res.status(401).json({ code }); } });
                      
                      import { verifyWsa, WsaVerificationError } from '@gptbots/workspace-extension-verify';

app.post('/session/exchange', (req, res) => {
  try {
    const identity = verifyWsa(req.body.wsa, {
      secret: process.env.EXTENSION_APP_SECRET, // Tier2-per-App-Schlüssel oder Tier1-geteilter Schlüssel
      audience: 'app.example.com',              // Erweiterungs-App-Host, muss gleich aud sein
      // issuer: 'gptbots-workspace',          // Standard
      // leewaySeconds: 30,                    // Toleranz für Uhrenabweichung, Standard 30s
      // algorithms: ['HS256'],                // Standard
    });

    // Mandantentrennung: Anfrage dem identity.workspaceId zuordnen
    const sid = createSession(identity);
    res.cookie('sid', sid, { httpOnly: true, secure: true, sameSite: 'lax' });
    res.json(identity);
  } catch (e) {
    const code = e instanceof WsaVerificationError ? e.code : 'Error';
    res.status(401).json({ code });
  }
});

                    
Dieser Codeblock im schwebenden Fenster

Ohne SDK

Das wsa ist ein standardmäßiges HS256-JWT, das jede JWT-Bibliothek in jeder Sprache prüfen kann. Beispiele für Java / Node / Python siehe 05-Token-Prüfung und Sicherheit §3. Ob mit oder ohne SDK: Signatur / iss / aud / exp – alle vier müssen geprüft werden.

Erweiterungs-App registrieren (Schlüssel beschaffen)

OWNER/ADMIN des Workspace: Workspace → Space-Verwaltung → Erweiterungs-Apps → Hinzufügen, folgende Angaben ausfüllen:

Feld Beschreibung
App-Name Anzeigename, empfohlen ≤ 12 chinesische Zeichen, um Abschneiden zu vermeiden
App-Symbol Quadratisches Symbol, empfohlen ≥ 128×128
App-Einstiegs-URL Ihre app_home_url, dient als eindeutiger Schlüssel, bei der Signatur wird streng nach der vollständigen Zeichenkette abgeglichen
Authentifizierungsmodus workspace_account wählen (Identität muss übergeben werden)

Nach dem Absenden wird das App Secret einmalig im Klartext angezeigt; kopieren und speichern Sie es sofort (nach dem Schließen kann es nur rotiert werden).

Landingpage-Checkliste

  • Nach dem Empfang von ?wsa= zuerst per POST an den Backend-Dienst der Erweiterungs-App zur Prüfung senden, erst dann dem Inhalt vertrauen
  • Nach bestandener Prüfung sofort mit history.replaceState das wsa entfernen (consumeHandoff macht dies standardmäßig)
  • In eigene Session umwandeln, sodass nachfolgende XHR/fetch/img das wsa nicht mehr weiterreichen
  • Den Zweig „Nutzer:in greift direkt zu, kein wsa" behandeln (zur Anmeldung leiten oder anonym)
  • Bei Prüffehler anhand von WsaVerificationError.code einen lesbaren Hinweis ausgeben

Sicherheitsdetails und Prüfung in mehreren Sprachen: Token-Prüfung und Sicherheit. Möchten Sie stattdessen einen „App-internen Anmelde-Button": Pull-Login.