Intégration du SDK
Intégration du SDK .NET
Un parcours complet, de zéro à sous licence : créez un produit dans Keyright, embarquez votre clé publique avec Keyright.NET, verrouillez les fonctionnalités hors ligne, activez en ligne et émettez des clés à vos clients — en échouant en mode fermé par conception.
Voici le parcours complet — d’un espace de travail Keyright vide à une application .NET livrée qui débloque des fonctionnalités payantes contre une vraie clé de licence. Il couvre les deux côtés : la configuration éditeur que vous faites une fois dans le tableau de bord Keyright, et le code client que vous embarquez avec le SDK Keyright.NET. Chaque bloc de code utilise la vraie surface du SDK ; copiez-les tels quels.
Si vous ne voulez que le parcours éditeur condensé, voir Premiers pas. Cette page est la version de bout en bout destinée au développeur.
Ce que vous allez construire
Vous émettez des clés de licence côté serveur dans Keyright — chaque tenant (votre espace de travail) les signe avec sa propre clé privée RSA, qui ne quitte jamais le serveur. Votre application n’embarque que la clé publique correspondante et vérifie les licences hors ligne avec celle-ci ; une vérification de licence n’a donc besoin d’aucun réseau. Pour l’application des sièges et la révocation, vous activez aussi en ligne : l’application échange une clé de licence contre une lease signée de courte durée, liée à la machine, puis continue de fonctionner hors ligne jusqu’à l’expiration de cette lease. Tout ce qui ne passe pas la vérification — mauvaise signature, mauvais produit, expiration, révocation, horloge reculée — se résout en édition Free plutôt que de lever une exception. Le SDK échoue en mode fermé (fail closed).
Étape 1 — Créez votre produit dans Keyright
Connectez-vous au tableau de bord à /dashboard (p. ex. https://keyright.delta1labs.com/dashboard) et ouvrez Products → New product (Produits → Nouveau produit). Donnez-lui un nom et un slug — le slug est l’identifiant que le SDK de votre application envoie en tant que Product, choisissez donc quelque chose de stable et en minuscules comme acme-app. Notez-le ; vous le collerez dans le SDK à l’étape 5. (Le tableau de bord s’ouvre dans sa vue Basique, qui affiche exactement les pages utilisées dans ce parcours ; la référence rapide du tableau de bord indique où se trouve chaque tâche.)
Votre espace de travail possède déjà une clé de signature RSA, générée à la création du tenant, et New product génère par défaut une clé par produit. Chaque licence et chaque lease d’un produit sont signées avec la moitié privée, qui est stockée chiffrée sur le serveur et ne le quitte jamais. Vous ne manipulez jamais que la moitié publique.
La même chose via l’API :
curl -X POST $BASE/admin/products -H "X-Admin-Token: $TOKEN" -H "content-type: application/json" \
-d '{"name":"Acme App","slug":"acme-app"}'
($BASE est l’URL de votre service d’émission, $TOKEN un jeton admin/de session de tenant — voir Premiers pas.)
Étape 2 — Récupérez votre clé publique
Ouvrez l’onglet Signing key (clé de signature) du produit (ou Developers → Keys, qui liste la clé de l’espace de travail et chaque clé de produit) et copiez la clé publique — une chaîne SubjectPublicKeyInfo en base64. La page Developers → Quickstart fait encore mieux et préremplit pour vous tout l’extrait de l’étape 5. Ou récupérez la clé de l’espace de travail via l’API :
curl $BASE/admin/public-key -H "X-Admin-Token: $TOKEN"
Cette clé n’est pas un secret. Elle est livrée dans votre binaire compilé. Toute la sécurité vient du fait que la clé privée reste sur le serveur : la clé publique ne peut que vérifier des signatures, jamais en produire. L’embarquer, décompiler votre application pour la lire, même la publier — rien de tout cela ne permet à quiconque de forger une licence.
Étape 3 — Définissez vos plans et vos droits
Un produit a des niveaux (tiers) — le tableau de bord les appelle des éditions (p. ex. pro, enterprise). Chaque édition porte un nombre de sièges et un modèle de droits — les indicateurs nommés et les limites numériques qui sont intégrés dans chaque licence de cette édition. Les droits sont la façon dont votre application demande « cette fonctionnalité est-elle autorisée ? » à l’exécution. (Une édition peut aussi porter une politique de couverture des versions — quelles versions ses licences peuvent exécuter — traitée à l’étape 11.)
Ajoutez-en une depuis l’onglet Editions du produit dans le tableau de bord (Add edition), ou via l’API :
curl -X POST $BASE/admin/products/acme-app/tiers -H "X-Admin-Token: $TOKEN" -H "content-type: application/json" \
-d '{"name":"pro","seats":3,"entitlements":{"export":"true","max-projects":"10"}}'
Les valeurs de droits sont des chaînes sur le réseau : "true"/"false" pour les indicateurs, un entier ou le littéral "unlimited" pour les limites. Une chaîne de niveau correspond à une édition sur laquelle votre application peut faire un switch — enterprise → Enterprise, tout le reste → Licensed, et aucune licence du tout → Free.
Étape 4 — Installez le SDK
Keyright.NET est sur NuGet. Il cible à la fois netstandard2.0 et net8.0, il fonctionne donc sur .NET Framework 4.8 et .NET 6–10.
dotnet add package Keyright.NET
Les SDK frères vérifient exactement les mêmes formats de licence et de lease pour d’autres runtimes — Node.js, Python et Java — de sorte qu’une gamme de produits multi-langages peut partager un seul tenant Keyright et une seule clé publique. Pas de SDK pour votre langage ? Appelez l’API HTTP directement. Cette page couvre le client .NET.
Étape 5 — Initialisez le client
Construisez un seul KeyrightClient au démarrage avec le slug du produit de l’étape 1, la clé publique de l’étape 2 et (pour l’activation en ligne) l’URL de votre service. Utilisez la fabrique statique Initialize — elle valide les options et charge la clé dès le départ :
using Keyright.Client;
static readonly KeyrightClient License = KeyrightClient.Initialize(new KeyrightOptions
{
Product = "acme-app", // doit correspondre au slug du produit pour lequel vous émettez des clés
PublicKeyBase64 = "MIIBIjANBgkq...", // la clé publique en base64 de l'étape 2
ServiceUrl = "https://licensing.acme.example", // VOTRE service d'émission Keyright — voir la note ci-dessous ; omettez-le en hors ligne uniquement
// Facultatif : garder une ancienne clé valide pendant une fenêtre de rotation (étape 9)
// AdditionalPublicKeysBase64 = { "<previous public key>" },
});
ServiceUrl est votre service d’émission Keyright, pas le nôtre — définissez-le sur l’URL de base de l’API de votre tenant managé ou, si vous exécutez Keyright en auto-hébergement, sur l’URL de base de votre propre instance (p. ex. https://licensing.acme.example). Le même SDK fonctionne avec l’un comme l’autre ; rien n’est codé en dur vers un endpoint Delta1. Seuls Product et PublicKeyBase64 sont obligatoires. Le SDK cherche une licence dans plusieurs sources, par ordre de priorité (la plus haute en premier) : une LicenseString explicite, puis un LicenseFilePath explicite, puis la variable d’environnement KEYRIGHT_LICENSE (un chemin vers un fichier de licence), puis ConfigLicensePath, puis le chemin app-data du système ({LocalApplicationData}/Keyright/{product}/license.json), et enfin la lease d’activation en cache. En général, vous ne définissez aucune de ces options — l’activation (étape 7) écrit le cache de lease pour vous.
Étape 6 — Verrouillez les fonctionnalités hors ligne
Appelez Validate(). Il résout la meilleure licence parmi les sources ci-dessus, vérifie la signature RSA, la correspondance du produit, la liaison au nœud, l’expiration, la liste de révocation livrée facultative et l’état d’essai/de manipulation de l’horloge — le tout hors ligne, et il ne lève jamais d’exception. En cas d’échec, il renvoie une LicenseInfo en édition Free portant la raison.
LicenseInfo info = License.Validate();
if (info.IsPaid) // true pour toute édition au-dessus de Free
{
// débloquer les fonctionnalités payantes
}
if (info.Edition == Edition.Enterprise)
{
// débloquer les fonctionnalités réservées à Enterprise
}
Verrouillez les fonctionnalités individuelles sur les droits plutôt que sur l’édition, pour que modifier le modèle d’un niveau n’oblige pas à livrer du nouveau code :
// Indicateur booléen
if (License.IsEnabled("export"))
{
ShowExportCommand();
}
// Limite numérique — passez vous-même la valeur de repli en mode fermé
long maxProjects = License.GetLimit("max-projects", fallback: 1);
if (currentProjectCount >= maxProjects)
{
PromptToUpgrade();
}
IsEnabled et GetLimit valident chacun sur le moment et échouent en mode fermé : un indicateur absent se lit comme désactivé, une limite absente ou non analysable renvoie votre valeur de repli. Si vous vérifiez plusieurs droits à la fois, validez une seule fois et réutilisez le résultat pour éviter du travail répété :
LicenseInfo info = License.Validate();
bool canExport = info.Entitlements.IsEnabled("export");
long maxSeats = info.Entitlements.GetLimit("max-seats", 1);
Pour savoir pourquoi une vérification a échoué (pour une boîte de dialogue « Enregistrer » ou des diagnostics), lisez info.Status et le info.Message destiné aux humains, et Validate(out LicenseSourceKind source) vous indique quelle source l’a emporté.
Étape 7 — Activez en ligne avec une clé de licence
Quand un client saisit une clé, appelez ActivateAsync. Il envoie la clé plus un identifiant de machine stable à votre service, qui consomme un siège et renvoie une lease signée de courte durée liée à cette machine. Le SDK vérifie la lease avec votre clé publique embarquée et la met en cache localement, de sorte que chaque Validate() ultérieur réussit sans réseau jusqu’à l’expiration de la fenêtre de grâce de la lease.
ActivateAsync ne lève pas d’exception pour les chemins d’échec ordinaires (mauvaise clé, limite de sièges, hors ligne, révoquée) — il renvoie une LicenseInfo en mode fermé, exactement comme Validate(). Inspectez le résultat :
LicenseInfo info = await License.ActivateAsync(customerEnteredKey, ct);
if (info.IsValid && info.IsPaid)
{
// Activée. La lease est en cache ; l'application fonctionne désormais hors ligne jusqu'à son expiration.
ShowLicensedUi(info.StatusBadge); // p. ex. "Enterprise" ou "Enterprise Trial"
}
else
{
// Affichez info.Message ; l'application reste en mode Free.
ShowActivationError(info.Message); // "All seats for this license are in use.", etc.
}
- Les sièges sont appliqués côté serveur. Activer plus de machines que la licence ne l’autorise renvoie un résultat de limite de sièges et aucune lease. Réactiver une machine déjà liée est idempotent — aucun siège supplémentaire n’est consommé.
- Grâce hors ligne. Si le service est injoignable,
ActivateAsyncse replie sur toute lease en cache encore valide, de sorte qu’une brève panne ne bloque pas l’utilisateur. Quand la lease approche de l’expiration, l’application doit de nouveau joindre le serveur pour la rafraîchir. - La révocation prend effet au prochain rafraîchissement — voir l’étape 9.
ActivateAsync ne lève une exception que pour des erreurs de programmation : un ServiceUrl manquant ou une clé vide.
Machines isolées du réseau (air-gapped). Pour une machine qui ne pourra jamais joindre le service, un opérateur signe une lease hors ligne pour son identifiant de machine (License file → Offline activation de la licence, ou POST /admin/licenses/{id}/offline-lease) et livre le JSON par fichier. Importez-le — ceci lève une exception si la lease est invalide, gérez-la donc :
try
{
LicenseInfo info = License.ImportOfflineLease(File.ReadAllText("acme.lease.json"));
}
catch (InvalidOperationException ex)
{
// mauvaise signature / produit / machine, ou expirée
}
Étape 8 — Émettez des clés de licence à vos clients
Vous pouvez distribuer des clés de trois façons :
- Depuis le tableau de bord. Licenses → Issue license (Licences → Émettre une licence) : choisissez le produit et l’édition, définissez le titulaire, l’e-mail de contact, les sièges et la durée, et Keyright génère la clé et l’affiche une seule fois. Le volet comporte aussi un commutateur Trial pour générer la clé comme un essai à durée limitée (voir l’étape 9 et Essais gratuits en libre-service), et une section Advanced pour les surcharges de fonctionnalités, les notes et une clé personnalisée.
- Automatiquement depuis votre fournisseur de facturation. Connectez le traitement des commandes de votre boutique à
POST /webhooks/fulfill/{slug}(signé en HMAC). Un événement « payé » génère une licence et envoie la clé par e-mail ; un événement « remboursement »/« annulation » la révoque — aucune étape manuelle. - Depuis l’API d’administration.
POST /admin/licenses(génère automatiquement une clé sauf si vous en passez une). Voir la référence de l’API HTTP pour la forme complète de la requête.
Quelle que soit la façon dont vous émettez, la clé est ce que le client colle dans votre application pour ActivateAsync à l’étape 7.
Étape 9 — Essais, liaison au nœud, révocation et rotation des clés
- Essais. Activez les essais en libre-service par produit et laissez les clients réclamer une clé depuis votre propre site ; une clé d’essai s’active par exactement le même chemin
ActivateAsyncqu’une clé payante. Affichez l’état directement depuisLicenseInfo—info.IsTrial,info.StatusBadge(p. ex. « Enterprise Trial »),info.ExpiryUtc, etinfo.DaysRemainingpour un badge « 27 jours restants ». La durée d’un essai est comptée à partir de la première activation, et il est remplacé en douceur quand le client active plus tard une clé payante. Flux complet : Essais gratuits en libre-service. - Liaison au nœud. Le SDK dérive une empreinte de machine stable, avec une petite
NodeLockTolerance(par défaut1) pour qu’une carte réseau ou un disque remplacé ne bloque pas l’utilisateur. Pour contrôler ce qui identifie une machine, implémentezIMachineComponentset définissezMachineComponentsdans les options. La requête d’activation envoie cet identifiant de machine pour que les sièges soient comptés par appareil. - Révocation. Révoquez une clé avec
POST /admin/licenses/{id}/revoke(ou l’action par ligne du tableau de bord). Le client retombe enFree(statutRevoked) au prochain rafraîchissement de lease. Vous pouvez aussi livrer une liste de révocation signée avec votre build (RevocationListJson/RevocationListPath) pour qu’une application purement hors ligne honore quand même les révocations. - Rotation des clés. Quand vous faites tourner la clé de signature du tenant, livrez un build avec la nouvelle clé publique dans
PublicKeyBase64et la clé sortante dansAdditionalPublicKeysBase64— les licences et leases signées par l’une ou l’autre continuent de se valider pendant la transition. Retirez l’ancienne clé de la liste une fois que chaque lease signée par elle a expiré.
Étape 10 — Testez de bout en bout
- Dans le tableau de bord, activez les essais pour
acme-app(une courte durée suffit), puis émettez-vous une clé d’essai. - Lancez votre application. Avant l’activation,
Validate()renvoieFree— vos fonctionnalités payantes restent verrouillées. - Appelez
ActivateAsyncavec la clé d’essai. Observez l’application basculer vers l’état sous licence et le badge passer à p. ex. « Pro Trial ». La lease est maintenant en cache sur le disque. - Testez hors ligne. Déconnectez le réseau et redémarrez l’application.
Validate()renvoie toujours laLicenseInfosous licence depuis la lease en cache — sans aller-retour serveur — jusqu’à la fin de la fenêtre de grâce de la lease. - Testez la révocation. Révoquez la licence, reconnectez-vous et laissez la lease se rafraîchir ; l’application doit retomber en
Free.
Étape 11 — Couverture des versions (facultatif)
Si vous vendez des mises à jour — « un an de mises à jour », « toutes les versions 2.x », un abonnement — Keyright peut enregistrer quelles versions chaque licence couvre, le signer, et laisser votre build décider localement si cette version est couverte : pas de réactivation, pas de nouvelle saisie de clé, et cela fonctionne hors ligne. Le guide complet est Couverture des versions ; le côté client tient en deux étapes.
Indiquez au build quelle version il est. Le paquet Keyright.NET livre des cibles MSBuild qui lisent ces propriétés et les intègrent dans l’assembly (définissez-les depuis votre pipeline de release, p. ex. -p:KeyrightCoverageVersion=2.4.0) :
<PropertyGroup>
<KeyrightCoverageVersion>2.4.0</KeyrightCoverageVersion> <!-- la version de ce build -->
<KeyrightCoverageEntitlementDate>2026-10-01</KeyrightCoverageEntitlementDate> <!-- la date à laquelle la couverture est jugée ; un correctif utilise la date de sa version de base -->
<KeyrightCoverageChannel>stable</KeyrightCoverageChannel> <!-- ou beta -->
<KeyrightRequireCoverage>true</KeyrightRequireCoverage> <!-- appliquer dans ce build ; fait échouer le build (KR0001) si la date manque -->
</PropertyGroup>
Vérifiez au démarrage. L’activation livre déjà et met en cache le bloc de couverture signé avec la lease. Sur un build qui applique la couverture, demandez une seule fois ; le SDK décide à partir du bloc en cache, rafraîchit silencieusement la licence si celui-ci dit « non », et ne lève jamais d’exception pour un problème réseau :
using Keyright.Coverage;
if (CoverageBuildInfo.Current.RequireCoverage)
{
CoverageCheckResult check = await License.CheckCoverageAsync(ct: ct); // version + date d'éligibilité de ce build
if (!check.IsCovered) // Covered et NotConfigured passent tous les deux
{
// check.Status : NotCovered (check.Reason = WindowLapsed → renouveler, OutsideVersionRange → mettre à niveau)
// ou UnavailableOffline (rien en cache et pas de réseau → importer un fichier de couverture)
// CoverageMessaging.Build(...) vous donne la phrase et l'action unique (renouveler / mettre à niveau / importer).
RunReadOnlyOrBlock(check);
}
}
bool can30 = License.IsCovered("3.0.0"); // pour votre propre bannière de mise à jour — local, sans réseau
CoverageInfo cov = License.GetCoverage(); // les conditions, la date de fin de support, enforced / unenforced
Pour les clients isolés du réseau, importez le fichier de couverture exporté depuis le tableau de bord avec License.ImportCoverageBlock(json). Votre propre page de téléchargement pose la même question avec POST /v1/coverage.
Dépannage
- L’activation dit que la clé n’a pas été reconnue. La cause la plus fréquente est une non-correspondance de produit : la clé a été émise pour un produit (ou un tenant) différent du slug
Productavec lequel votre client est configuré. Le serveur limite l’activation au produit, de sorte qu’une clé valide pouracme-appn’activera pas un client initialisé avecProduct = "other-app". Confirmez que le slug de l’étape 5 correspond au produit sous lequel vous avez émis la clé. - Tout se lit comme Free. C’est voulu — le SDK échoue en mode fermé sur tout problème de vérification plutôt que de lever une exception. Lisez
info.Status(p. ex.NoLicense,SignatureInvalid,Expired,MachineMismatch,Revoked) etinfo.Messagepour savoir lequel. UnSignatureInvalidsignifie presque toujours que la clé publique embarquée ne correspond pas au tenant qui a signé la clé. - Une licence à durée limitée refuse soudain de se valider. Si l’horloge système est reculée en arrière au-delà de
ClockTamperToleranceHours(24 h par défaut) sur un essai ou un abonnement, le SDK considère cela comme une manipulation de l’horloge et renvoie le statutClockTampered. Ce n’est pas définitif — remettez l’heure correcte et la validation se rétablit à l’appel suivant. Les licences perpétuelles ne sont jamais soumises à cette vérification.
Voir aussi
- Premiers pas — le parcours éditeur condensé et la liste de contrôle de mise en production.
- Couverture des versions — quelles versions une licence couvre, et les appels SDK derrière l’étape 11.
- Essais gratuits en libre-service — activer les essais et le flux côté client.
- Tableau de bord d’administration — chaque écran derrière ces étapes.
- Référence de l’API HTTP — la carte complète des endpoints.