TokenHandler
createTokenHandler est le coeur de la librairie. Là où beaucoup de bibliothèques exposent surtout des fonctions utilitaires à assembler, ici l'idée est inverse : on commence par créer un handler qui porte déjà la politique de gestion du token.
Ce handler regroupe au même endroit :
- la signature ;
- le chiffrement ;
- la durée de vie du token ;
- la gestions des claims (header/payload) ;
Autrement dit, le but est de construire un contrat clair que l'on peut réutiliser.
Création au démarrage
createTokenHandler est pensé pour être appelé au démarrage d'une l'application. La configuration est validée immédiatement, et une configuration invalide provoque un throw dès la création du handler.
Exemple simple
import { D, DPE } from "@duplojs/utils";
import { Signer, createTokenHandler } from "@duplojs/json-web-token";
const tokenHandler = createTokenHandler({
maxAge: D.createTime(15, "minute"),
signer: Signer.createHS256({ secret: "my-secret" }),
issuer: "my-app",
audience: ["web"],
customPayloadShape: {
userId: DPE.string(),
},
});
const token = await tokenHandler.createOrThrow({
userId: "1",
});
// send to client ...
const verifiedToken = await tokenHandler.verify("receive-token");Ce qui se passe ici
Au moment du create, le handler ajoute lui-même les claims standards comme iat et exp, puis signe le contenu.
Au moment du verify, il redécode le token, vérifie la signature, puis applique les contrôles de configuration comme l'expiration, l'issuer, le subject ou l'audience.
Pourquoi createOrThrow existe ?
En pratique, on recommande createOrThrow.
Si la création d'un token échoue, c'est généralement un problème d'implémentation ou de configuration côté serveur, pas un scénario métier attendu. Dans ce cas, lever une erreur immédiatement est un comportement sain.
À l'inverse, verify n'a pas de variante orThrow : un échec de vérification peut être parfaitement normal (signature invalide, token expiré, claims incohérents, etc.). Ce n'est pas forcément une erreur d'implémentation, donc ce cas reste géré comme un résultat métier.
Paramètres
interface TokenHandlerParams {
maxAge: D.TheTime;
signer: Signer<string> | CreateSigner<string, unknown>;
cipher?: Cipher<string> | CreateCipher<string, unknown>;
issuer?: string;
subject?: string;
audience?: string | string[];
now?: () => D.TheDate;
customPayloadShape: DP.DataParserObjectShape;
customHeaderShape?: DP.DataParserObjectShape;
};Le handler retourné expose ensuite quatre méthodes :
createcreateOrThrowverifydecode
Exemple avec custom shapes
import { D, DPE } from "@duplojs/utils";
import { Signer, createTokenHandler } from "@duplojs/json-web-token";
const tokenHandler = createTokenHandler({
maxAge: D.createTime(1, "hour"),
signer: Signer.createHS256({ secret: "my-secret" }),
issuer: "admin-app",
customPayloadShape: {
userId: DPE.string(),
role: DPE.literal("admin"),
},
customHeaderShape: {
kid: DPE.string().optional(),
},
});
const token = await tokenHandler.createOrThrow(
{
userId: "42",
role: "admin",
},
{
header: {
kid: "main",
},
},
);
// send to client ...
const decodedToken = await tokenHandler.decode("receive-token");Ce qui se passe ici
customPayloadShape et customHeaderShape définissent ce que ton application a le droit de mettre dans le token.
Les clés réservées du JWT, comme exp, iat, iss, sub, aud, typ ou alg, restent gérées par le handler lui-même.
Exemple avec des "creators"
import { D, DPE } from "@duplojs/utils";
import { Cipher, Signer, createTokenHandler } from "@duplojs/json-web-token";
const tokenHandler = createTokenHandler({
maxAge: D.createTime(10, "minute"),
signer: Signer.createHS256,
cipher: Cipher.createRSAOAEP,
customPayloadShape: {
userId: DPE.string(),
},
});
const token = await tokenHandler.createOrThrow(
{
userId: "1",
},
{
signer: {
secret: "my-secret",
},
cipher: {
privateKey: "private-key",
publicKey: "public-key",
},
},
);
// send to client ...
const verifiedToken = await tokenHandler.verify("receive-token", {
signer: {
secret: "my-secret",
},
cipher: {
privateKey: "private-key",
publicKey: "public-key",
},
});Ce qui se passe ici
Quand tu passes un CreateSigner ou un CreateCipher au lieu d'une instance déjà configurée, les paramètres sont déplacés vers create, createOrThrow, verify et decode.
Cela permet de créer le handler une seule fois, tout en injectant plus tard les secrets, les clés ou d'autres paramètres nécessaires.
