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
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_urldie 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_urlbereits eine Query, wirdwsamit&angehängt; derwsa-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);
}
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
catchmanuellstripHandoffToken()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
⚠️ Ö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
verifyWsaim 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 });
}
});
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.replaceStatedaswsaentfernen (consumeHandoffmacht dies standardmäßig) - In eigene Session umwandeln, sodass nachfolgende XHR/fetch/img das
wsanicht mehr weiterreichen - Den Zweig „Nutzer:in greift direkt zu, kein
wsa" behandeln (zur Anmeldung leiten oder anonym) - Bei Prüffehler anhand von
WsaVerificationError.codeeinen 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.
