05 · Vérification du jeton et sécurité
Que ce soit en push ou en pull, le développeur finit toujours par obtenir un wsa (JWT HS256). Cet article est une lecture obligatoire pour tous les intégrateurs — une vérification laxiste = une identité falsifiable.
Liste de contrôle de vérification obligatoire
Une fois le wsa obtenu, vérifiez dans le service backend de l'application d'extension, dans l'ordre (verifyWsa intègre déjà tout cela) :
- Signature : vérifiez en HS256 avec la clé distribuée/obtenue à l'enregistrement par la plateforme. Échec → rejet.
exp: heure actuelle ≤exp(avec une légère leeway). L'expdoit exister — un jeton sansexpdoit être rejeté directement (sinon il n'expire jamais).iss: doit être égal àgptbots-workspace.aud: doit être égal au host de l'application d'extension cible. C'est la ligne de défense clé contre « le vol d'un jeton pour attaquer une autre application », à ne jamais omettre.iat/nbf(si présents) : ne doivent pas être dans le futur (au-delà de la leeway), pour empêcher qu'un jeton « dont l'heure d'émission est fixée dans un futur lointain » soit utilisable longtemps.- Isolation par
workspace_id: si l'extension fait de l'isolation multi-espaces de travail, rattachez la requête à ceworkspace_idet interdisez l'accès inter-tenant. - Effacer immédiatement le
wsa/codede l'URL après l'atterrissage :history.replaceState, pour éviter que l'utilisateur ne partage le jeton en copiant l'URL. - Établir une session propre : échangez contre la session/cookie propre à l'application d'extension ; les requêtes suivantes ne doivent plus dépendre du
wsa— il expire au bout de 5 minutes.
Le
verifyWsadu SDK officiel exige la présence deexp, vérifie la dérive future deiat/nbf, effectue une comparaison de signature à temps constant et applique une liste blanche d'algorithmes (par défaut uniquementHS256, ce qui élimine les attaques de confusion d'alg). En l'utilisant, vous satisfaites automatiquement les points 1 à 5.
Vérification recommandée avec le SDK
import { verifyWsa, WsaVerificationError } from '@gptbots/workspace-extension-verify';
try {
const id = verifyWsa(wsa, {
secret: process.env.EXTENSION_APP_SECRET,
audience: 'app.example.com',
});
// id: { accountId, role, workspaceId, username?, email?, avatar?, appName?, issuedAt?, expiresAt? }
} catch (e) {
if (e instanceof WsaVerificationError) {
// e.code: InvalidToken | InvalidSignature | Expired | NotYetValid
// | WrongIssuer | WrongAudience | MissingClaim | UnsupportedAlgorithm
}
}
Options complètes et codes d'erreur : voir Référence de l'API SDK.
Vérification sans le SDK (multi-langage)
Le wsa est un JWT HS256 standard, vérifiable par n'importe quelle bibliothèque JWT. Activez impérativement la vérification explicite de iss / aud et verrouillez algorithms=['HS256'].
Java (auth0 java-jwt)
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SHARED_SECRET))
.withIssuer("gptbots-workspace")
.withAudience("app.example.com")
.acceptLeeway(30) // tolère 30s de dérive d'horloge
.build();
DecodedJWT jwt = verifier.verify(wsaParam);
String userId = jwt.getSubject();
String workspaceId = jwt.getClaim("workspace_id").asString();
String role = jwt.getClaim("role").asString();
String username = jwt.getClaim("username").asString(); // peut être null
String email = jwt.getClaim("email").asString(); // peut être null
Node.js (jsonwebtoken)
const jwt = require('jsonwebtoken');
const payload = jwt.verify(wsaParam, SHARED_SECRET, {
algorithms: ['HS256'],
issuer: 'gptbots-workspace',
audience: 'app.example.com',
clockTolerance: 30,
});
const { sub: userId, workspace_id, role, username, email, avatar } = payload;
Python (PyJWT)
import jwt
payload = jwt.decode(
wsa_param,
SHARED_SECRET,
algorithms=["HS256"],
issuer="gptbots-workspace",
audience="app.example.com",
leeway=30,
)
user_id = payload["sub"]
workspace_id = payload["workspace_id"]
role = payload["role"]
Rappel sur l'encodage de la clé : HS256 utilise directement la chaîne de la clé, en octets UTF-8, comme clé HMAC. La clé per-app Tier 2 a la forme
wext_+64 hex ; passez-la telle quelle en chaîne comme clé (ne faites pas de décodage hex), pour rester cohérent avec le côté signature de la plateforme.
Exigences de sécurité (à appliquer point par point)
- La clé constitue tout le modèle de sécurité. Actuellement, HS256 est une clé symétrique : en cas de fuite, n'importe qui peut falsifier l'identité de n'importe quel utilisateur d'espace de travail et attaquer l'application d'extension intégrée. À garder uniquement dans le backend (variables d'environnement/KMS), à ne jamais écrire dans le code frontend, les dépôts git, les logs ou la configuration client.
- Surface d'exposition du JWT dans l'URL (push uniquement) : la query string est enregistrée dans l'historique du navigateur, les access logs du serveur web, les logs de cache CDN, les enregistrements de Referer. Même enregistré, il reste exploitable s'il est récupéré dans les 5 minutes. Effacez immédiatement avec
history.replaceStateaprès l'atterrissage (déjà fait par défaut parconsumeHandoff). Le mode pull (M-Auth) ne met par nature pas lewsadans l'URL, ce qui est plus sûr. - Ne transmettez pas le
wsaaux sous-ressources. Une fois échangé contre une session propre, les XHR/fetch/img suivants ne portent plus lewsad'origine, sinon il apparaîtrait dans le Referer de chaque sous-ressource. - Synchronisation d'horloge. HS256 juge strictement l'
exp; l'horloge du serveur doit être synchronisée par NTP ; dans l'exemple, laleewayde 30s tolère une faible dérive, ne l'étendez pas jusqu'à la minute. - Le
rolesert uniquement de mappage de permissions par défaut. Il reflète uniquement le rôle de l'utilisateur dans cet espace de travail, non ses permissions dans votre application ; votre application maintient son propre modèle de permissions. - Isolation multi-tenant. Utilisez toujours le
workspace_idcomme clé d'isolation des données, pour empêcher qu'un utilisateur de l'espace de travail A ne lise les données de B. - Procédure d'urgence de rotation/révocation de clé : dans la gestion de l'espace, effectuez une « rotation de clé » sur l'application, ce qui génère une nouvelle clé affichée une seule fois, puis reconfigurez votre backend avec la nouvelle clé.
5. Frontière de confiance du frontend (important)
- Le frontend ne fait que de l'affichage réservé, pas de décision d'autorisation. Le frontend peut décoder en base64 le payload du JWT, mais sans la clé, il ne peut pas vérifier la signature — n'importe qui peut falsifier un payload « qui a l'air correct ».
- Toute décision du type « qui est cette personne, peut-elle faire quelque chose » doit reposer sur le résultat de
verifyWsacôté backend de l'application d'extension. - La stratégie standard est donc : le frontend remet le
wsa/codeau backend de l'application d'extension → le backend vérifie → le backend établit une session → le frontend ne reconnaît que cette session.
Étape suivante : Référence de l'API SDK pour consulter l'API complète ; en cas de problème, consultez Questions fréquentes et dépannage.
