laravel-license maintained by groupesti
Laravel License
Software licensing for Laravel: issue signed license tokens (JWT, EdDSA or RS256), validate them, manage products / editions / features, track per-device activations and log every validation — fully configurable and self-contained.
Installation
composer require groupesti/laravel-license
php artisan vendor:publish --tag=license-config
php artisan migrate
Signing keys are read from configuration (never the database). Generate an Ed25519 key pair and set:
LICENSE_ACTIVE_KID=default
LICENSE_ALGORITHM=EdDSA
LICENSE_PRIVATE_KEY="base64-or-PEM-private-key"
LICENSE_PUBLIC_KEY="base64-or-PEM-public-key"
LICENSE_ISSUER="https://your-app.example"
Concepts
- Product / Edition / Feature — your catalogue. An edition bundles features (with optional per-feature limits).
- License — issued to a licensee (any model, via the
HasLicensestrait), carries atypeandstatus, validity window and device cap. - Activation — one row per device that has activated a license.
- ValidationLog — an audit trail of every validation attempt.
LicenseStatus, LicenseType, ActivationStatus and ValidationResult are
Eloquent models (reference tables) — you can add your own rows. The package
seeds the default values and exposes slug constants (e.g. LicenseStatus::ACTIVE).
Issuing a license
use License\Actions\IssueLicense;
use License\Models\LicenseStatus;
use License\Models\LicenseType;
$license = app(IssueLicense::class)->execute([
'product_id' => $product->id,
'edition_id' => $edition->id,
'license_type_id' => LicenseType::idFor(LicenseType::SUBSCRIPTION),
'license_status_id' => LicenseStatus::idFor(LicenseStatus::ACTIVE),
'name' => 'Acme Corp',
'max_devices' => 5,
'valid_from' => now(),
'valid_until' => now()->addYear(),
]);
$token = $license->plain_token; // signed JWT, returned once on creation
Or from the CLI:
php artisan license:create --product=my-app --edition=pro --type=subscription --email=customer@example.com
Validating a license
use License\Actions\ValidateLicense;
$result = app(ValidateLicense::class)->execute($token, $deviceId, [
'ip_address' => request()->ip(),
]);
// ['valid' => true, 'result' => 'valid', 'license' => [...], 'claims' => [...], 'expires_at' => '...']
Public HTTP endpoint (rate limited): POST /api/v1/license/validate.
Online (real-time) verification
Set online_verification on a license to require real-time validation. The
token then carries the flag and a heartbeat schedule (interval / grace,
from config('license.online_verification')), and the client must call the
validation endpoint at least once per interval.
- Licenses with
online_verificationare validated by the endpoint (live status, revocation and device checks); the response includes aheartbeatwith the next check-in time. - Licenses without it are meant to be validated offline — the endpoint
refuses them with
result: online_not_required(HTTP 409).
php artisan license:create --product=my-app --type=subscription --online
Attaching licenses to a model
use License\Traits\HasLicenses;
class Team extends Model
{
use HasLicenses; // $team->licenses()
}
Commands
php artisan license:create # create and sign a license
php artisan license:validate # validate a token
php artisan license:revoke # revoke by id or jti
HTTP API
POST /api/v1/license/validate— public validation./api/v1/admin/licenses/*— admin CRUD + catalogue (guarded byadmin_api_middleware).
Translations
Provided for en, fr, es.
php artisan vendor:publish --tag=license-lang
License
MIT. See license.md.