Add-on Gestion de Licences
Un système de gestion de clés de licence multi-fournisseurs pour Larapen avec vérification API, suivi des activations par domaine/machine, gestion des fonctionnalités et intégration de webhooks.
Multi-fournisseurs
Clés manuelles, codes d’achat Envato et sources webhook externes : tout dans un seul système.
Suivi des activations
Suivez les activations par domaine, identifiant machine ou IP. Appliquez des limites par clé (ex. 3 domaines max).
Drapeaux de fonctionnalités
Définissez des ensembles de fonctionnalités par produit (modules, limites, niveaux) retournés dans chaque réponse de vérification.
API REST
Points de terminaison de vérification, activation et désactivation pour l’intégration client.
Cas d’utilisation
Application SaaS
Votre produit SaaS utilise des clés de licence auto-hébergées pour contrôler les niveaux d’abonnement.
- Chaque plan correspond à un Produit avec différentes fonctionnalités :
{"max_users": 5}(Starter),{"max_users": 50, "api_access": true}(Pro). - L’application appelle
GET /api/licenses/verifyau démarrage pour vérifier la validité et lire l’objetfeatures. - Pas besoin d’activation par domaine : juste la vérification.
Application de bureau
Une application de bureau est licenciée par machine.
- Au lancement, l’application appelle
POST /api/licenses/activateavec unmachine_id. - L’application appelle périodiquement
GET /api/licenses/verifypour vérifier la validité. - Lorsque l’utilisateur décommissionne une machine, il appelle
POST /api/licenses/deactivatepour libérer l’emplacement.
Plugin / Thème WordPress
Un plugin WordPress premium valide sa licence sur le site du client.
- L’administrateur entre la clé dans les paramètres WP. Le plugin appelle
POST /api/licenses/activateavecdomain = site_url(). - La vérification s’exécute quotidiennement via WP-Cron en utilisant
GET /api/licenses/verify. - Si la limite d’activation est atteinte, le client doit désactiver un ancien domaine avant d’en activer un nouveau.
Niveaux d’accès API
Vous vendez un accès API avec différentes limites de débit par plan.
- Les produits définissent des fonctionnalités :
{"rate_limit": 100, "endpoints": ["read"]}(Basic),{"rate_limit": 10000, "endpoints": ["read","write","admin"]}(Enterprise). - Votre passerelle API appelle
GET /api/licenses/verifyet lit lesfeaturespour appliquer les limites.
Produits Envato (CodeCanyon)
Vous vendez un produit sur CodeCanyon et souhaitez une vérification automatique des licences.
- Configurez le fournisseur Envato avec votre jeton API et votre nom d’utilisateur auteur.
- Les clients entrent leur code d’achat Envato. Le système le vérifie directement auprès de l’API Envato.
- Pas besoin de création manuelle de clé : le fournisseur gère tout.
Bibliothèque / Plugin JavaScript
Vous vendez un composant d’éditeur JS premium. Chaque client reçoit une clé de licence valide pour N domaines.
- Au chargement de la page, la bibliothèque appelle
POST /api/licenses/activateavec la clé et le domaine actuel. - Le serveur vérifie la clé, l’active sur le domaine (comptabilisé dans la limite) et retourne les drapeaux de fonctionnalités via
GET /api/licenses/verify(ex."toolbar_presets": true,"ai_integration": false).
Prérequis
- Larapen CMS v1.0.0 ou ultérieur
- PHP 8.3+
- MySQL 8.0+
- Une installation Larapen active avec le système d’add-ons activé
Installation
Étape 1 : Placer l’add-on
Copiez ou créez un lien symbolique du dossier licenses dans le répertoire « extensions/addons » de votre Larapen :
Ou, si vous développez en dehors du projet, créez un lien symbolique :
Étape 2 : Activer l’add-on
Allez dans Admin → Add-ons → Add-ons installés et activez Gestion de Licences.
Alternativement, insérez une ligne dans la table addons :
Étape 3 : Exécuter les migrations
Cela crée 5 tables : licenses_products, licenses_keys, licenses_activations, licenses_webhook_logs,
et licenses_key_user (pivot). Cela ajoute également supported_until à licenses_keys
et license_product_id à shop_products (si l’add-on Shop est installé).
Étape 4 : Définir les permissions
L’add-on enregistre 14 permissions (voir Permissions). Assignez-les aux rôles administrateur via Admin → Utilisateurs → Rôles & Permissions.
Étape 5 : Configurer
Naviguez vers Admin → Licences → Paramètres et définissez votre clé API, les préférences de format de clé et les identifiants fournisseur. Voir Configuration.
Configuration
Tous les paramètres peuvent être configurés de deux manières :
- Panneau d’administration : Licences → Paramètres (stockés dans la table
settings, groupelicenses) - Variables d’environnement : dans
.env(utilisées comme valeurs par défaut ; les paramètres admin les remplacent)
| Paramètre | Description | Défaut |
|---|---|---|
api_key |
Clé API requise pour tous les points de terminaison côté client. Envoyée via l’en-tête X-Api-Key ou le paramètre de requête api_key. |
(vide) |
default_key_format |
Format par défaut pour les clés générées automatiquement : uuid, alphanumeric, prefixed ou hmac_signed. |
alphanumeric |
key_prefix |
Chaîne de préfixe pour le format de clé prefixed (ex. LIC). |
LIC |
default_max_activations |
Limite d’activation par défaut lors de la création de nouvelles clés. | 1 |
hmac_key |
Clé secrète pour le format de clé signé HMAC et la vérification de signature webhook. | (vide, utilise APP_KEY par défaut) |
api_rate_limit |
Nombre maximum de requêtes API par minute par client. | 3 |
api_daily_rate_limit |
Nombre maximum de requêtes API par jour par client. | 50 |
Paramètres spécifiques aux fournisseurs
| Paramètre | Fournisseur | Description |
|---|---|---|
envato_api_token |
Envato | Jeton personnel depuis build.envato.com |
envato_author_username |
Envato | Votre nom d’utilisateur auteur Envato |
webhook_secret |
Webhook | Secret partagé pour la vérification de signature HMAC-SHA256 |
Variables d’environnement
Admin : Tableau de bord
Le tableau de bord (Licences → Tableau de bord) fournit un aperçu en temps réel :
- Cartes de statistiques : Total des clés, clés actives, total des produits, activations actives
- Répartition par statut : Nombre de clés suspendues, expirées et révoquées
- Clés récentes : Les 10 dernières clés créées avec affichage masqué et badges de statut
- Webhooks récents : Les 5 derniers événements webhook avec fournisseur et statut
Admin : Produits
Les produits représentent le logiciel ou service faisant l’objet d’une licence. Chaque clé de licence appartient à un produit.
Créer un produit
Naviguez vers Licences → Produits → Ajouter un produit.
| Champ | Requis | Description |
|---|---|---|
name |
Oui | Nom du produit (traduisible) |
slug |
Non | Identifiant compatible URL. Généré automatiquement à partir du nom si vide. |
description |
Non | Description du produit (traduisible, max 2000 caractères) |
sku |
Non | Référence article. Doit être unique. |
version |
Non | Version actuelle du produit (ex. 2.1.0) |
is_active |
— | Interrupteur. Les produits inactifs sont masqués des listes de sélection. |
features |
Non | Paires clé-valeur définissant ce que ce produit débloque. Voir Drapeaux de fonctionnalités. |
Admin : Clés de licence
Créer une clé
Naviguez vers Licences → Clés de licence → Ajouter une clé.
| Champ | Requis | Description |
|---|---|---|
product |
Oui | Le produit auquel cette clé appartient |
key |
Non | Chaîne de clé de licence. Laissez vide pour générer automatiquement. |
key_format |
Non | Format pour la génération automatique (voir Formats de clé) |
license_type |
Oui | Standard, Étendue, Essai ou À vie |
status |
Oui | Active, Suspendue, Expirée ou Révoquée |
expires_at |
Non | Date d’expiration. Laissez vide pour les clés sans expiration. |
supported_until |
Non | Date de fin de support. Distincte de l’expiration de licence : suit la fin de la période de support du client (ex. fenêtre de support de 6 mois Envato). |
max_activations |
Oui | Nombre de domaines/machines sur lesquels cette clé peut être activée simultanément |
provider |
Oui | Source de la licence : manual, envato ou webhook |
assigned_user |
Non | Lier optionnellement à un compte utilisateur |
notes |
Non | Notes internes (non exposées via l’API) |
Opérations en masse
Génération en masse
Naviguez vers Clés de licence → Génération en masse pour créer jusqu’à 1 000 clés en une fois. Sélectionnez le produit, le format, le type de licence, le nombre maximum d’activations et la date d’expiration optionnelle.
Suppression en masse
Sur la page de liste des clés, sélectionnez plusieurs clés avec les cases à cocher et cliquez sur Supprimer la sélection.
Export CSV
Cliquez sur Exporter en CSV sur la page de liste des clés. Permet le filtrage par produit et statut avant l’export.
Actions de cycle de vie
| Action | Effet |
|---|---|
| Suspendre | Définit le statut à suspended. La clé échoue à la vérification mais peut être réactivée ultérieurement. Les activations existantes restent mais ne sont pas fonctionnelles. |
| Révoquer | Définit le statut à revoked et désactive toutes les activations actives. Cela est irréversible en pratique. |
| Réactiver | Redéfinit le statut à active. La clé redevient valide (si non expirée). |
Admin : Activations
Consultez toutes les activations d’une clé spécifique en cliquant sur Activations sur la page de détail de la clé, ou en naviguant vers
/admin/licenses/keys/{id}/activations.
Chaque enregistrement d’activation affiche :
- Domaine (si fourni) — avec un badge Local pour les domaines locaux/de développement
- Identifiant machine (si fourni)
- Adresse IP
- Agent utilisateur
- Date d’activation
- Statut Actif/Désactivé
Les administrateurs peuvent manuellement désactiver toute activation active pour libérer un emplacement pour le client.
Lorsque « Enregistrer les activations de domaines locaux » est activé dans les paramètres de contournement des domaines locaux, les activations locales apparaissent dans la liste
mais ne comptent pas dans la limite max_activations de la clé. Un bouton Supprimer les activations locales
permet de supprimer en masse tous les enregistrements d’activation locale pour une clé. La page d’index des clés de licence fournit un filtre pour afficher uniquement les clés avec des activations locales.
Admin : Drapeaux de fonctionnalités
Chaque produit peut définir un ensemble de drapeaux de fonctionnalités clé-valeur sur le formulaire de création/modification. Ceux-ci sont stockés en JSON et retournés dans chaque réponse de l’API /verify.
Comment ça fonctionne
- Modifiez un produit et faites défiler jusqu’à la section Fonctionnalités.
- Cliquez sur Ajouter une fonctionnalité pour ajouter des lignes clé-valeur.
- Définissez la clé de fonctionnalité (ex.
api_access) et la valeur (ex.true). - Enregistrez. Les fonctionnalités sont retournées sous forme d’objet JSON dans les réponses API.
Exemples d’ensembles de fonctionnalités
Admin : Paramètres
La page de paramètres (Licences → Paramètres) est organisée en sections :
- Configuration API : clé API et limite de débit
- Génération de clés : format par défaut, préfixe, nombre maximum d’activations, clé HMAC
- Contournement des domaines locaux : activer/désactiver le contournement, interrupteur d’enregistrement des activations locales et motifs de domaines
- Fournisseur Envato : activer/désactiver, jeton API et nom d’utilisateur auteur
- Fournisseur Webhook : secret webhook et affichage de l’URL
La barre latérale affiche tous les points de terminaison API disponibles et les badges de statut de configuration des fournisseurs.
Admin : Journaux de webhooks
Tous les événements webhook entrants sont journalisés avec leur fournisseur, type d’événement, données brutes, données de réponse, statut (Succès / Échec / Ignoré) et messages d’erreur éventuels. Naviguez vers Licences → Journaux de webhooks pour consulter. Filtrez par fournisseur ou statut.
Mise à jour
Étape 1 : Remplacer les fichiers
Remplacez le répertoire de l’add-on par la nouvelle version (ou faites un pull de la dernière version si vous utilisez un lien symbolique vers un dépôt Git).
Étape 2 : Exécuter les migrations
Les nouvelles migrations sont automatiquement détectées. L’add-on utilise des migrations horodatées qui ne s’exécutent qu’une seule fois.
Étape 3 : Vider les caches
Étape 4 : Vérifier
Visitez Licences → Tableau de bord pour confirmer que tout se charge correctement. Vérifiez la page Paramètres pour découvrir les nouvelles options de configuration introduites par la mise à jour.
Page d’enregistrement de licence
Une page publique où les clients enregistrent leur code d’achat (Envato ou manuel) et l’activent sur leur domaine.
Disponible à /{locale}/licenses/register (ou /licenses/register sans préfixe de langue).
URL & Routes
| Méthode | URL | Nom de route | Description |
|---|---|---|---|
| GET | /{locale}/licenses/register |
front.licenses.register.localized |
Afficher le formulaire d’enregistrement |
| POST | /{locale}/licenses/register |
front.licenses.register.localized |
Traiter l’enregistrement |
| GET | /licenses/register |
front.licenses.register |
Variante non localisée |
Flux d’enregistrement
- Le client visite
/licenses/registeret remplit sa clé de licence / code d’achat et son domaine. - Le système recherche la clé dans la base de données locale.
- Si elle n’est pas trouvée localement, il essaie le fournisseur Envato : vérifie le code d’achat via l’API Envato.
Si valide, un enregistrement
LicenseKeyest automatiquement créé avecprovider = envato. - Si l’utilisateur est authentifié, la
LicenseKeyest liée à son compte utilisateur (user_id). - Le système appelle
LicenseActivationService::activate()avec le domaine fourni. - En cas de succès, le client voit un message de confirmation. En cas d’échec (clé invalide, expirée, activations maximum atteintes), une erreur est affichée.
Champs du formulaire
| Champ | Validation | Description |
|---|---|---|
license_key |
Requis, chaîne, max 255 | La clé de licence ou le code d’achat Envato |
domain |
Requis, chaîne, max 255 | Le domaine où le logiciel est installé (sans http/https) |
Vues de thème
Chaque thème fournit sa propre version stylisée du formulaire d’enregistrement à :
Thèmes : default, creative, elegant, minimalist, olive, technology.
front_menu dans addon.json. Le libellé « Enregistrer une licence » apparaît dans le menu d’en-tête.
Portail client (Mes licences)
Les clients authentifiés peuvent consulter toutes leurs licences liées et gérer les activations de domaines.
Nécessite la connexion utilisateur (utilise le middleware auth).
URL & Routes
| Méthode | URL | Nom de route | Description |
|---|---|---|---|
| GET | /{locale}/licenses/list |
front.licenses.my.localized |
Lister toutes les licences de l’utilisateur |
| GET | /{locale}/licenses/list/{id} |
front.licenses.my.show.localized |
Voir les détails de la licence & activations |
| POST | /{locale}/licenses/list/{id}/deactivate |
front.licenses.my.deactivate.localized |
Désactiver un domaine |
Des variantes non localisées (sans {locale}) sont également disponibles.
Page Mes licences
Affiche une liste/tableau de toutes les licences appartenant à l’utilisateur connecté, montrant :
- Nom du produit : produit de licence lié
- Clé de licence : masquée par défaut (ex.
XXXX-XXXX-XXXX-ab12), avec un bouton de copie - Badge de statut : Active (vert), Expirée (ambre), Suspendue (rouge), Révoquée (sombre)
- Type de licence : Standard, Étendue, Essai, À vie
- Activations : nombre / max (ex. « 2 / 3 »)
- Date d’expiration : ou « Jamais » pour les licences à vie
- Lien Voir les détails
Page de détail de la licence
Affiche les informations complètes pour une licence unique :
- Informations sur la clé : clé complète (masquée avec bouton de révélation via JavaScript natif), statut, type, dates d’émission/expiration
- Domaines actifs tableau : domaine, adresse IP, date d’activation et un bouton Désactiver pour chacun
- Historique des activations : toutes les activations (actives + désactivées) avec horodatages
Désactivation
Les clients peuvent auto-désactiver les domaines qu’ils n’utilisent plus. La désactivation :
- Vérifie que la licence appartient à l’utilisateur authentifié
- Appelle
LicenseActivationService::deactivateByDomain() - Libère un emplacement d’activation pour utilisation sur un autre domaine
- Redirige avec un message de succès
Vues de thème
user_menu dans addon.json, icône : bi-key).
Génération automatique via la boutique
Lorsque l’add-on Shop est actif et qu’un produit de la boutique est lié à un produit de licence, les clés de licence sont automatiquement générées lorsqu’une commande est payée.
Configuration
- Exécutez la migration : La migration
2026_03_07_100001_add_license_product_id_to_shop_products_table.phpajoute une colonnelicense_product_idàshop_products. - Liez les produits de la boutique aux produits de licence : Dans le formulaire d’administration du produit de la boutique,
définissez le
license_product_idpour le lier à un produit de licence créé sous Licences → Produits.
Flux de génération automatique
- Un client effectue un achat via la boutique.
- Le
payment_statusde la commande est mis à jour àPAID(viamarkAsPaid()ou le webhook de la passerelle de paiement). - Le
ShopOrderObserverdétecte le changement de statut de paiement. - Pour chaque article de commande où le produit de la boutique a un
license_product_id:- Une
LicenseKeyest créée par quantité d’article (ex. qté 2 → 2 clés) - Le fournisseur est défini à
shop - Le statut est défini à
active provider_referenceest défini àshop_order:{order_number}(empêche la génération en double)- La clé hérite du format par défaut des paramètres
- Une
- Un e-mail
LicenseKeyIssuedNotificationest envoyé au client avec :- Salutation avec le nom du client
- Toutes les clés de licence générées
- Un bouton « Enregistrer une licence » pointant vers
/licenses/register - Instructions sur la manière d’activer
Prévention des doublons
L’observateur vérifie l’existence de clés avec le même provider_reference avant de générer.
Si des clés pour shop_order:ORD-12345 existent déjà, l’observateur ignore la génération.
Cela empêche les doublons si le statut de paiement est mis à jour plusieurs fois.
Modifications de la base de données
| Table | Colonne | Type | Description |
|---|---|---|---|
| shop_products | license_product_id | BIGINT UNSIGNED NULL |
FK vers licenses_products.id (ON DELETE SET NULL) |
Addons\Shop\Models\Order existe.
updated (pas created).
Une commande créée directement avec payment_status = PAID ne déclenchera pas la génération automatique :
le statut doit passer d’un état non payé à PAID via une mise à jour.
Dépannage
L’API renvoie 503 : « License API is not configured »
Vous n’avez pas défini de clé API. Allez dans Licences → Paramètres et définissez le champ Clé API, ou définissez LICENSES_API_KEY dans
.env.
L’API renvoie 401 : « Invalid API key »
L’en-tête X-Api-Key ou le paramètre api_key ne correspond pas à la clé configurée. Vérifiez les espaces en début/fin ou les problèmes d’encodage.
L’activation échoue avec « Maximum activations reached »
La clé a atteint sa limite max_activations. Options :
- Désactivez un domaine inutilisé via
POST /deactivateou depuis le panneau d’administration - Augmentez
max_activationssur la clé dans le panneau d’administration
La vérification Envato échoue
Vérifiez que :
- Le jeton API Envato a les permissions
View Your Envato Account UsernameetVerify Purchases - Le
Nom d’utilisateur auteurcorrespond exactement à votre profil Envato (sensible à la casse) - Le code d’achat est valide et appartient à l’un de vos articles
Les événements webhook sont journalisés comme « Échec »
Causes courantes :
- Signature invalide : L’en-tête
X-Webhook-Signaturene correspond pas. Assurez-vous que les deux côtés utilisent le même secret et calculent HMAC-SHA256 sur le corps brut de la requête. - Produit manquant : Le slug
productdans les données ne correspond à aucun produit actif. Créez d’abord le produit. - Événement invalide : Le champ
eventdoit être l’un de :license.created,license.updated,license.revoked,license.expired.
La page d’enregistrement renvoie « Clé de licence invalide »
La clé n’a pas été trouvée localement et la vérification Envato a également échoué. Vérifiez :
- Le jeton API Envato et le nom d’utilisateur auteur sont correctement configurés dans Licences → Paramètres
- Le code d’achat est valide et appartient à l’un de vos articles Envato
- Si vous utilisez des clés manuelles, assurez-vous que la clé existe dans Licences → Clés de licence
Le domaine local n’est pas conttourné
Vérifiez que :
- Le contournement des domaines locaux est activé dans Licences → Paramètres (ou
LICENSES_LOCAL_DOMAIN_BYPASS=truedans.env) - Le domaine correspond à l’un des motifs configurés (les motifs utilisent la syntaxe
fnmatch()) - Le domaine n’inclut pas le protocole : utilisez
localhostet nonhttp://localhost
L’achat en boutique ne génère pas de clés de licence
Vérifiez que :
- Le produit de la boutique a un
license_product_iddéfini (lié à un produit de licence) - Le
payment_statusde la commande est changé enPAID - La migration
2026_03_07_100001_add_license_product_id_to_shop_products_tablea été exécutée - Vérifiez la colonne
provider_reference: si des clés avecshop_order:{order_number}existent déjà, l’observateur ignore la génération
La vérification côté client affiche « Licence invalide »
Vérifiez que :
LICENSE_API_BASE_URLpointe vers le bon serveur (ex.https://larapen.com/api/licenses)LICENSE_API_KEYcorrespond auLICENSES_API_KEYsur le serveur- Le code d’achat est valide et n’a pas été révoqué
- Le serveur est joignable depuis le client (pas de problèmes de pare-feu/DNS)