Skip to content

Cas d'usage

Révoquer, renouveler et gérer l'expiration

Couper l'accès, prolonger une durée sans nouvelle clé, et savoir exactement ce que voit l'application à l'expiration, pendant la période de grâce et après une révocation — ainsi que ce qui change pour une instance auto-hébergée qui se licencie elle-même.

Objectif. Vous devez mettre fin immédiatement à l’accès d’un client (une rétrofacturation, un abus, une émission par erreur), prolonger la durée d’un client payant sans réémettre sa clé, et comprendre précisément ce que l’application en cours d’exécution affiche quand une durée touche à sa fin.

Quand l’utiliser

  • Utilisez ceci si vous vendez des licences à durée déterminée (annuelles/abonnement) et les renouvelez, ou si vous avez un jour besoin de révoquer une clé.
  • Utilisez ceci si vous décidez avec quelle fermeté échouer — à quelle vitesse une révocation ou une expiration atteint une machine actuellement hors ligne.
  • Pas ceci si vous ne livrez que des licences perpétuelles qui n’expirent jamais et ne sont jamais révoquées — cette page n’est alors que le chemin de révocation « en cas d’urgence ». Déplacer un siège d’une machine à une autre relève de l’activation et désactivation, pas de la révocation.

Deux cycles de vie partagent cette page et ne doivent pas être confondus. Le cycle de vie de la licence client (les clés de vos utilisateurs finaux) se comporte de la même façon que vous soyez sur Cloud ou auto-hébergé. Le cycle de vie de l’instance auto-hébergée est une chose différente — la clé propre à l’instance, qui lui accorde le droit de s’exécuter — traité à la fin et dans Licence et éditions.

Active — sous licenceexpire bientôtExpirée → FreeIsExpiringSoon()expiryUtcrenew → expiration repousséemême clé · pas de réactivationrévocation — à tout momentl'app retombe en Free au prochain rafraîchissement de leasedélai d'application = TTL de la leaseen ligne : vite ; hors ligne : pas au-delà de la grâceUne durée de licence client, lue entièrement depuis LicenseInfoDaysRemaining décompte · IsPaid passe à false à l'expiration/révocation · Status dit pourquoi
Une licence à durée déterminée tout au long de sa vie : active, expirant bientôt, renouvelée (même clé), ou expirée/révoquée — et à quelle vitesse un changement atteint l'appareil.

Ce que vous faites (côté éditeur)

Les trois actions re-signent la licence côté serveur ; le client conserve la même clé et se contente de réactiver (généralement automatiquement au démarrage) pour récupérer le changement.

Révoquer — couper une clé :

curl -X POST $BASE/admin/licenses/LIC-…/revoke -H "X-Admin-Token: $TOKEN"
# l'action Revoke par ligne du tableau de bord fait la même chose. Plusieurs à la fois : POST /admin/licenses/bulk-revoke

Renouveler / prolonger une durée — repousser l’expiration (et éventuellement changer les sièges), sans nouvelle clé :

curl -X POST $BASE/admin/licenses/LIC-…/renew -H "X-Admin-Token: $TOKEN" -H "content-type: application/json" \
  -d '{"expiryUtc":"2028-10-12T00:00:00Z"}'
# les sièges peuvent aussi être modifiés ici ; un renouvellement re-signe la licence sur place. La clé est inchangée.

Les deux se trouvent sur la page de la licence elle-même : Renew est dans la rangée d’actions, et Revoke dans la Danger zone.

La page de licence Stark Industries dans Keyright : un bouton Renew (avec Add seats, License file et Send portal link) dans la rangée d'actions en haut, et une carte Danger zone en bas à droite contenant « Transfer ownership… » et un bouton rouge « Revoke… » ; la carte Details affiche l'édition pro, une durée perpétuelle et les appareils liés.
Renew (rangée d'actions) prolonge la durée sur place avec la même clé ; Revoke (Danger zone) la coupe — les deux re-signent la licence, et l'application récupère le changement à son prochain rafraîchissement de lease.

L’expiration n’est rien d’autre que l’arrivée de l’expiryUtc de la licence sans renouvellement — vous n’avez rien à faire ; le comportement ci-dessous se déclenche de lui-même. (Un remboursement/une annulation reçu via un webhook de boutique révoque automatiquement — voir Émettre automatiquement des clés depuis une boutique.)

Chaque état de ce cycle de vie apparaît dans la liste Licenses, de sorte que vous repérez d’un coup d’œil une clé révoquée, expirée ou sur le point d’expirer :

La liste Licenses de Keyright affichant un mélange de statuts dans la colonne STATUS : des pastilles « active » sur Stark Industries, Globex Corporation et Acme Inc. ; une pastille rouge « revoked » sur Wayne Enterprises ; une pastille grise « expired » sur Umbrella Ltd (expiration le 1er mars 2026) ; et un avertissement ambre « in 10 days » d'expiration imminente sur Initech LLC (expiration le 22 oct. 2026), avec les dates d'expiration et le nombre de sièges par ligne.
La liste Licenses fait apparaître tout le cycle de vie d'un coup — active, revoked, expired, et un avertissement d'expiration imminente (« in 10 days ») — les mêmes états que votre application lit dans LicenseInfo.Status.

À quelle vitesse un changement atteint la machine

Une révocation ou un renouvellement est appliqué à la prochaine vérification en ligne de l’appareil, car entre deux vérifications l’application s’exécute hors ligne avec une lease en cache. Le TTL de la lease (14 jours par défaut, KEYRIGHT_LEASE_TTL_DAYS) est exactement le bouton de réglage : une application connectée qui réactive au démarrage récupère une révocation dans sa cadence de rafraîchissement ; une machine restée hors ligne ne la verra pas avant de revenir en ligne, et au plus tard lorsque la fenêtre de grâce de sa lease s’écoule et qu’elle est forcée de revérifier. Raccourcissez le TTL pour que les révocations et les changements de sièges prennent effet plus tôt, au prix d’une tolérance hors ligne réduite. Pour une application des règles hors ligne sans aucun réseau, livrez une liste de révocation signée avec votre build (RevocationListJson / RevocationListPath) afin qu’une application purement hors ligne respecte tout de même une révocation.

Dans votre code

Votre application lit tout dans LicenseInfo — elle n’analyse jamais une clé. Les membres pertinents, dans chaque SDK et en HTTP brut :

.NET

LicenseInfo info = await License.ActivateAsync(key, ct);   // ou License.Validate() hors ligne ; les deux échouent en mode fermé

// Status est la source unique de vérité — branchez dessus.
switch (info.Status)
{
    case LicenseStatus.Valid:    break;                     // sous licence ; on continue vers le badge ci-dessous
    case LicenseStatus.Expired:  return ShowRenewPrompt(info.Message);   // durée terminée, ou essai fini
    case LicenseStatus.Revoked:  return ShowUnlicensed(info.Message);    // la clé a été révoquée
    default:                     return ShowUnlicensed(info.Message);    // NoLicense, SeatLimit, SignatureInvalid, …
}

// Tant que la licence est valide, affichez le compte à rebours et incitez au renouvellement.
if (info.IsExpiringSoon())                                   // true dans la fenêtre de renouvellement
    ShowRenewBanner($"{info.DaysRemaining} days left");      // DaysRemaining décompte jusqu'à expiryUtc
string badge = info.ExpiryUtc is null
    ? "Licensed — perpetual"                                 // pas d'expiration
    : $"Licensed — expires {info.ExpiryUtc:d}";

Node.js

const { info } = license.validate();                 // ou : info = await license.activate(key)
switch (info.status) {
  case 'valid':    break;                                      // sous licence
  case 'expired':  return showRenewPrompt(info.message);       // durée terminée, ou essai fini
  case 'revoked':  return showUnlicensed(info.message);        // la clé a été révoquée
  default:         return showUnlicensed(info.message);        // no_license, machine_mismatch, …
}
if (info.daysRemaining != null && info.daysRemaining <= 14)    // inciter avant le renouvellement
  showRenewBanner(`${info.daysRemaining} days left`);
const badge = info.expiryUtc ? `Licensed — expires ${info.expiryUtc.toLocaleDateString()}`
                             : 'Licensed — perpetual';

Python

info = license.validate_info()                       # ou : info = license.activate(key)
if info.status == LicenseStatus.VALID:
    pass                                             # sous licence
elif info.status == LicenseStatus.EXPIRED:
    return show_renew_prompt(info.message)           # durée terminée, ou essai fini
elif info.status == LicenseStatus.REVOKED:
    return show_unlicensed(info.message)             # la clé a été révoquée
else:
    return show_unlicensed(info.message)             # NO_LICENSE, MACHINE_MISMATCH, …
if info.days_remaining is not None and info.days_remaining <= 14:
    show_renew_banner(f"{info.days_remaining} days left")
badge = "Licensed — perpetual" if info.expiry_utc is None else f"Licensed — expires {info.expiry_utc:%x}"

Java

LicenseInfo info = client.validateInfo();            // ou : info = client.activate(key)
switch (info.status) {
    case VALID:   break;                                   // sous licence
    case EXPIRED: return showRenewPrompt(info.message);    // durée terminée, ou essai fini
    case REVOKED: return showUnlicensed(info.message);     // la clé a été révoquée
    default:      return showUnlicensed(info.message);     // NO_LICENSE, MACHINE_MISMATCH, …
}
if (info.isExpiringSoon(14))                               // inciter avant le renouvellement
    showRenewBanner(info.daysRemaining() + " days left");
String badge = info.expiryUtc == null ? "Licensed — perpetual"
                                      : "Licensed — expires " + info.expiryUtc;

Tout langage (HTTP brut)

curl -s -X POST "$BASE/v1/validate" -H "content-type: application/json" \
  -d '{"key":"LIC-…","machineId":"<stable-machine-id>","product":"acme-app"}'
# status "revoked" -> retomber en Free ; "expired" -> inviter à renouveler ; "ok" -> vérifier la lease et lire
# licenseExpiryUtc pour le compte à rebours. Échouez en mode fermé sur tout sauf une lease valide et non expirée.

Ce que chacun fait apparaître à l’approche de la fin de la durée :

  • DaysRemaining décompte jusqu’à expiryUtc ; IsExpiringSoon() passe à true dans la fenêtre de renouvellement, pour que vous puissiez prévenir avant la fin de l’accès.
  • À l’expiration ou après une révocation, IsPaid passe à false et l’application retombe dans son état Free/sans licence — Keyright échoue en mode fermé, il ne lève pas d’exception. Status vous dit lequel des deux (Expired ou Revoked) pour que vous puissiez formuler l’invite (« renouveler » ou « contactez-nous »).
  • Après un renouvellement, le prochain ActivateAsync/Validate() renvoie l’ExpiryUtc plus lointain — sans nouvelle saisie de clé, sans boîte de dialogue de réactivation.

Il n’existe aucune « fenêtre de grâce » dans l’application pour une licence à durée déterminée : dès que expiryUtc est dépassé (et que la machine valide à nouveau), l’application est Expired. La fenêtre de 14 jours de la lease est un coussin de connectivité — elle permet à une machine de fonctionner hors ligne avec une durée encore valide — et non une grâce supplémentaire après la fin de la durée payée. Si vous voulez que les anciennes versions continuent de fonctionner après l’échéance d’un abonnement, c’est l’abonnement avec repli de la couverture des versions, pas une grâce d’expiration.

Les consommateurs en HTTP brut voient le même cycle de vie via le champ status de /v1/validate (revoked, expired) et le licenseExpiryUtc de la lease — vérifiez la lease et échouez en mode fermé sur tout sauf une lease valide et non expirée, comme dans Utiliser l’API HTTP directement.

Le cycle de vie de la licence client et celui de l’instance auto-hébergée

Ce sont deux clés distinctes avec des règles différentes. Gardez-les bien séparées :

Licence client (vos utilisateurs finaux)Licence d’instance auto-hébergée (votre propre clé)
À quiLes clés de vos clients, émises par vousLe droit de votre instance à s’exécuter, émis par Delta1
S’applique àCloud et auto-hébergé indifféremmentAuto-hébergé uniquement
Grâce à l’expirationAucune — Expired dès que la durée est dépasséePayante : 15 jours de grâce en lecture seule après l’expiration ; essai : aucune
À l’arrêtL’application échoue en mode fermé vers FreeL’instance se verrouille — 402 sur la plupart des chemins ; les endpoints de statut restent actifs
Vous la contrôlez avec/revoke, /renew, expiryUtcRemplacer KEYRIGHT_SELF_LICENSE + redémarrer

Tout ce qui précède le tableau concerne le cycle de vie client — identique sur Cloud et en auto-hébergé. La clé propre à l’instance est une autre histoire : un déploiement auto-hébergé se licencie lui-même, une instance payante bénéficie de 15 jours de grâce en lecture seule après sa propre expiration avant de se verrouiller, et une instance d’essai s’arrête dès qu’elle expire. Ce cycle de vie — installation, renouvellement, le champ phase de /admin/self-license, et ce que « verrouillée » signifie — est traité en détail dans Licence et éditions. Ne confondez pas l’échéance de l’abonnement d’un client (son application passe en Free) avec l’échéance de la licence de votre instance (tout votre service d’émission passe en lecture seule, puis s’arrête).

Cloud ou auto-hébergé

  • $BASE / $TOKEN. Cloud : https://keyright.delta1labs.com + un jeton de session. Auto-hébergé : l’URL de votre instance + KEYRIGHT_ADMIN_TOKEN.
  • Révocation, renouvellement et expiration des licences client sont identiques dans les deux modes — mêmes endpoints, même comportement du SDK.
  • Le TTL de la lease est à vous de régler sur une instance auto-hébergée (KEYRIGHT_LEASE_TTL_DAYS) ; sur Cloud, c’est la valeur par défaut du service.
  • Le cycle de vie de l’instance n’existe qu’en auto-hébergé (voir ci-dessus).

Vérifier

  1. Émettez-vous une clé à durée déterminée expirant dans un jour ou deux ; activez-la. Le badge affiche l’expiration et DaysRemaining.
  2. Révoquez-la, reconnectez-vous et laissez la lease se rafraîchir (ou appelez ActivateAsync) : l’application retombe en Free avec Status == Revoked.
  3. Émettez une nouvelle clé, activez-la, puis renouvelez-la à une date ultérieure ; réactivez — ExpiryUtc est repoussé, même clé, aucune boîte de dialogue.
  4. Laissez une clé de courte durée expirer, revalidez : Status == Expired, IsPaid == false, l’invite de renouvellement s’affiche.
  5. Synchronisation hors ligne : révoquez une clé pendant que cette machine est hors ligne — confirmez qu’elle continue de fonctionner jusqu’à sa reconnexion (ou la fin de sa fenêtre de lease), puis retombe en Free. Raccourcissez KEYRIGHT_LEASE_TTL_DAYS si c’est trop lent.

Voir aussi