Référence de l'API SDK
Le SDK officiel se compose de deux paquets indépendants du framework et sans dépendance d'exécution, dont le code source est disponible sur GitHub à l'adresse : https://github.com/gptbots/workspace-extension-sdk.
| Nom du paquet | Emplacement d'exécution | Point d'entrée |
|---|---|---|
@gptbots/workspace-extension-verify |
Backend (Node ≥ 18) | verifyWsa, exchangeWorkspaceCode |
@gptbots/workspace-extension-sdk |
Navigateur | consumeHandoff, startWorkspaceLogin, completeWorkspaceLogin … |
Les deux paquets sont en ESM (
"type": "module"). Pour un projet CommonJS, utilisez unimport()dynamique ou passez à ESM.
Paquet backend @gptbots/workspace-extension-verify
verifyWsa(token, options): WorkspaceIdentity
Vérifie le wsa et retourne l'identité de l'espace de travail. Ordre de vérification : signature → iss → aud → expiration (exp±leeway, avec iat/nbf) → claims obligatoires.
interface VerifyOptions {
secret?: string; // clé HS256 (per-app ou partagée). Obligatoire pour vérifier en HS256
publicKey?: string; // clé publique PEM RS256. Obligatoire pour vérifier en RS256 (feuille de route)
audience: string; // host de l'application d'extension, doit être égal au aud du jeton (obligatoire)
issuer?: string; // par défaut 'gptbots-workspace'
leewaySeconds?: number; // tolérance de dérive d'horloge (secondes), 30 par défaut
algorithms?: ('HS256' | 'RS256')[]; // par défaut ['HS256']
}
interface WorkspaceIdentity {
accountId: string; // = JWT sub
role: 'OWNER' | 'ADMIN' | 'MEMBER'; // valeur inconnue normalisée en MEMBER
workspaceId: string; // = JWT workspace_id
username?: string; email?: string; avatar?: string; appName?: string;
issuedAt?: number; // = iat (secondes)
expiresAt?: number; // = exp (secondes)
}
expobligatoire : absent ou nombre non fini → lèveMissingClaim(ne sera pas traité comme « n'expire jamais »).iat/nbf(si présents) dans le futur au-delà de la leeway → lèveNotYetValid.- En cas d'échec, lève
WsaVerificationError(avec.code) ; une erreur de configuration de l'appelant (ex. clé manquante) lèveTypeError.
Valeurs de WsaVerificationError.code :
| code | Signification |
|---|---|
InvalidToken |
Jeton vide / structure invalide / segment n'est pas un objet JSON |
InvalidSignature |
Signature non concordante (clé erronée, jeton altéré) |
Expired |
Expiré (avant exp + leeway) |
NotYetValid |
iat/nbf dans le futur (au-delà de la leeway) |
WrongIssuer |
iss ≠ valeur attendue |
WrongAudience |
aud ≠ votre audience |
MissingClaim |
Manque exp / sub / role / workspace_id |
UnsupportedAlgorithm |
alg absent de la liste blanche (par défaut uniquement HS256) |
exchangeWorkspaceCode(options): Promise<WorkspaceCodeExchangeResult>
Pour la connexion pull : dans le backend de l'application d'extension, échange le code à usage unique + codeVerifier PKCE contre un wsa. Ne l'appelez jamais dans le navigateur.
interface ExchangeWorkspaceCodeOptions {
tokenUrl: string; // endpoint /token de la plateforme (URL absolue)
code: string; // code d'autorisation à usage unique obtenu au callback
codeVerifier: string; // verifier PKCE correspondant au code_challenge
fetch?: typeof fetch; // fetch injectable (tests/anciens runtimes) ; fetch global par défaut
timeoutMs?: number; // timeout de requête, 10000 par défaut ; passez 0 pour désactiver
}
interface WorkspaceCodeExchangeResult {
wsa: string; // le wsa signé, à passer à verifyWsa
tokenType?: string; // 'Bearer'
expiresIn?: number; // durée de validité du wsa (secondes)
}
- Échec de transport / non 2xx /
code≠0métier (ex.403209 invalid_grant,403210 invalid_verifier) /data.wsamanquant → lèveError. - En cas de timeout, lève
token exchange timed out after <ms>ms(10s par défaut, empêche qu'une réponse lente de la plateforme bloque votre backend).
Exemple de middleware Express
import { verifyWsa, WsaVerificationError } from '@gptbots/workspace-extension-verify';
export function requireWorkspaceIdentity(secret: string, audience: string) {
return (req, res, next) => {
try {
req.identity = verifyWsa(req.body.wsa, { secret, audience });
next();
} catch (e) {
const code = e instanceof WsaVerificationError ? e.code : 'Error';
res.status(401).json({ code });
}
};
}
Paquet navigateur @gptbots/workspace-extension-sdk
Push (Push handoff)
readHandoffToken(search?, paramName?): string | null
Fonction pure, lit le wsa brut depuis la query string. search vaut par défaut location.search, paramName vaut par défaut 'wsa'.
stripHandoffToken(paramName?, ctx?): void
Supprime le wsa de l'URL courante via history.replaceState, pour qu'il ne subsiste ni dans la barre d'adresse, ni dans l'historique, ni dans le Referer. No-op sûr hors navigateur. ctx?: { history?, location? } est injectable (tests).
consumeHandoff(options): Promise<WorkspaceIdentity>
Flux pratique du niveau use : lit le wsa → POST vers le backend de l'application d'extension → après succès, efface le wsa → retourne l'identité.
interface ConsumeHandoffOptions {
exchangeUrl: string; // l'interface de vérification backend de l'application d'extension
fetch?: typeof fetch; // injectable
search?: string; // par défaut location.search
paramName?: string; // par défaut 'wsa'
strip?: boolean; // par défaut true (efface uniquement en cas de succès)
}
Le jeton n'est effacé qu'après un échange réussi, afin qu'un échec transitoire puisse être réessayé par actualisation. Si vous souhaitez l'effacer immédiatement même en cas d'échec, appelez manuellement
stripHandoffToken()dans lecatch.
Pull (Pull / M-Auth)
startWorkspaceLogin(options): Promise<WorkspaceLoginRequest>
Génère le PKCE, stocke dans sessionStorage, construit et (par défaut) redirige vers /authorize. Nécessite un contexte sécurisé (HTTPS/localhost).
interface StartWorkspaceLoginOptions {
authorizeUrl: string; // endpoint /authorize de la plateforme (URL absolue)
clientId: string; // l'app home URL de l'application d'extension
redirectUri: string; // adresse de callback, le host doit être du même domaine que clientId
state?: string; // par défaut, génère automatiquement un state CSRF aléatoire de 16 octets
workspaceId?: string; // espace de travail présélectionné, saute la page de sélection d'organisation
storage?: StorageLike; // par défaut sessionStorage
redirect?: (url: string) => void; // par défaut location.assign
navigate?: boolean; // false = construit seulement l'URL sans rediriger (popup/tests)
}
interface WorkspaceLoginRequest { url: string; state: string; codeVerifier: string; }
readAuthorizeCallback(search?, storage?): AuthorizeCallback | null
Sur la page d'atterrissage du callback : lit le code + state, vérifie le state (CSRF), retourne le code + le codeVerifier stocké. Ne consomme pas la requête stockée (la consommation est différée jusqu'à un échange réussi), afin qu'un échec transitoire puisse être réessayé par actualisation. Retourne null en l'absence de code et d'error.
interface AuthorizeCallback { code: string; state: string | null; codeVerifier: string; }
stripAuthorizeCallback(ctx?): void
Supprime le code / state de l'URL courante.
completeWorkspaceLogin(options): Promise<WorkspaceIdentity>
Flux pratique du niveau use : lit et vérifie le callback → POST {code, codeVerifier} vers votre backend → après succès, efface l'URL → retourne l'identité.
interface CompleteWorkspaceLoginOptions {
exchangeUrl: string; // votre propre interface d'échange backend
fetch?: typeof fetch;
search?: string; // par défaut location.search
storage?: StorageLike; // par défaut sessionStorage
strip?: boolean; // par défaut true
}
Valeurs de WorkspaceLoginError.code
| code | Signification |
|---|---|
NoCallback |
Pas de code d'autorisation dans l'URL |
MissingRequest |
Requête de connexion stockée absente/corrompue (appelez d'abord startWorkspaceLogin) |
StateMismatch |
Échec de la vérification CSRF du state |
AuthorizeError |
Le callback est une redirection d'erreur OAuth (?error=...) |
NoFetch |
Aucune implémentation de fetch disponible |
ExchangeFailed |
L'interface d'échange a retourné un code non 2xx |
InvalidResponse |
L'interface d'échange a retourné un JSON invalide |
CryptoUnavailable |
Pas de Web Crypto (nécessite un contexte sécurisé HTTPS/localhost) |
StorageUnavailable |
Pas de sessionStorage (impossible de stocker le verifier PKCE) |
InvalidAuthorizeUrl |
authorizeUrl n'est pas une URL absolue |
Trois. Installation locale depuis l'archive
unzip workspace-extension-sdk-0.1.0.zip
# Les deux paquets ont un dist pré-compilé (main=dist/index.js, types=dist/index.d.ts)
npm i ./workspace-extension-sdk/packages/verify # backend
npm i ./workspace-extension-sdk/packages/browser # frontend
Pour compiler / exécuter les tests vous-même :
cd workspace-extension-sdk
npm install
npm run build # tsc → dist de chaque paquet
npm test # node --test (aucune dépendance de test externe, nécessite Node ≥ 22.6 pour exécuter directement les .ts)
npm run type-check # tsc --noEmit
