Download the PHP package ozankurt/laravel-modules-licensing without Composer
On this page you can find all versions of the php package ozankurt/laravel-modules-licensing. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download ozankurt/laravel-modules-licensing
More information about ozankurt/laravel-modules-licensing
Files in ozankurt/laravel-modules-licensing
Package laravel-modules-licensing
Short Description Self-hosted software licensing for Laravel: issue/validate license keys, Ed25519 signed offline keys, seat activations, private Composer gating, and a Core-free client SDK.
License MIT
Informations about the package laravel-modules-licensing
Licensing
Self-hosted software licensing for Laravel. Issue and validate license keys, sign offline license files, enforce per-machine seat limits, and gate private Composer downloads — everything you need to sell a premium Laravel/Filament package, running on your own infrastructure.
Part of the KurtModules family. Headless by design, with an optional Filament admin (Filament 3, 4 & 5) and a Core-free client SDK you embed in the package you sell.
Features
- License keys — human-friendly, crypto-random keys (
ABCD-EF23-GH45-JK67). Only a keyed HMAC of the key is stored, never the plaintext. - Three policies —
perpetual,subscription(time-limited), andupdates_window(runs forever, but only downloads releases published before a cutoff — the "license expires, software keeps working" model). - Seat activations — per-machine fingerprints with a configurable limit. Re-activating the same machine is idempotent; deactivation frees the seat.
- Online + offline — a JSON API for live validation, and Ed25519-signed license files that verify entirely offline with only a public key.
- Composer gating — an HTTP-Basic bridge (email + key) that authorizes Composer
downloads against the license, front your private Satis or use the bundled
auth_requestendpoint. - Audit trail — every issue / activate / validate / composer decision is logged.
- Client SDK —
Kurt\Modules\Licensing\Client\*depends only onilluminate/*(no Core), so you can embed it in the package you sell. Includes an offline grace window so a network blip never bricks a paying customer.
Requirements
- PHP
^8.4 - Laravel
^13.0 ozankurt/laravel-modules-core^2.0
Installation
Core is not on Packagist yet, so add it as a VCS repository in your app's
composer.json:
Publish config + migrations and migrate:
Generate a signing keypair and add it to .env (keep the signing key on the server only):
Server usage
Define a product
Issue a license
…or from the CLI:
Sign a downloadable license file (offline activation)
Every signed file embeds a not_after timestamp (inside the signed claims, so it
cannot be tampered out) set licensing.offline.reissue_ttl_days in the future
(default 7 days). The client refuses a file once that moment passes and must
re-download a fresh one. This is the offline revocation / re-issue cadence:
because an offline file never phones home, withdrawing entitlement (revoke,
downgrade, non-renewal) simply means not re-signing a new file — the old one
lapses within one TTL window. Point customers at a re-download endpoint (or ship
a new .lic on renewal) and pick a TTL that trades revocation latency against
how often clients must re-fetch. Clients whose clock is slightly off are covered
by licensing.offline.skew_tolerance (seconds) so a valid file is not rejected
on the boundary.
REST API
An out-of-the-box JSON REST API, built on the shared Core API kit and
safe-by-default: nothing is registered until you opt in. Enable it by setting
the mode to api (or ui):
Everything is configured under licensing.http in config/licensing.php:
| Key | Default | Purpose |
|---|---|---|
mode |
headless |
headless (nothing registered) | api | ui. |
prefix |
api/licensing |
URL prefix for the route group. |
middleware |
['api'] |
Base middleware for every route. |
auth_middleware |
['auth'] |
Added to the admin (write) routes. |
rate_limit |
'60,1' |
maxAttempts,decayMinutes for the licensing-api throttle. |
ability |
licensing:manage |
Gate ability the admin policies check (deny-by-default). |
Authentication model
The API has two tiers with different authentication:
- Machine endpoints (
validate/activate/deactivate) authenticate by the license key in the request body — there is no logged-in user. They are the public-ish surface the client SDK talks to, run through the domain services (so seat accounting and expiry /not_aftersemantics are preserved), and are throttled by thelicensing-apilimiter. They return the flat{ valid, reason, claims }shape and never expose internal fields. There is no way to validate or forge without the real key. -
Admin endpoints (licenses, products, activations) additionally require the
auth_middlewareplus a Policy. TheLicensePolicy/ProductPolicygate on thelicensing:manageability, which is deny-by-default: define it in your app to grant access.Guests get
401; authenticated-but-unauthorized users get403.
Endpoints
Mounted under prefix (default api/licensing). Machine endpoints:
| Method | Path | Auth | Body | Response |
|---|---|---|---|---|
| POST | validate |
key | { key, fingerprint? } |
{ valid, reason, claims } |
| POST | activate |
key | { key, fingerprint, label? } |
{ valid, claims } / 422 / 404 |
| POST | deactivate |
key | { key, fingerprint } |
{ deactivated } |
Admin endpoints (auth + licensing:manage), enveloped as { data, meta }:
| Method | Path | Purpose |
|---|---|---|
| GET | licenses |
List (sort/filter/paginate). |
| POST | licenses |
Issue a license; returns the plaintext key once. |
| GET | licenses/{license} |
Show. |
| PATCH | licenses/{license} |
Update status / policy / seats. |
| POST | licenses/{license}/revoke |
Revoke ({ reason? }). |
| GET | licenses/{license}/activations |
List a license's seat activations. |
| GET | products |
List. |
| POST | products |
Create. |
| GET | products/{product} |
Show. |
| PATCH | products/{product} |
Update. |
| DELETE | products/{product} |
Delete. |
Index endpoints accept ?sort=, ?filter[field]=, ?per_page= / ?page= per
the Core API kit conventions.
Composer authorize endpoint
Separate from the REST API kit and enabled by default (it is auth_request
infrastructure, not a user-facing API), mounted under licensing.routes.prefix:
| Method | Path | Body | Response |
|---|---|---|---|
| GET | /licensing/composer/authorize/{pkg} |
HTTP Basic (email\:key) | 204 / 401 / 403 |
Client SDK (embed in the package you sell)
Offline verification of a signed file — no server, only the public key:
The machine fingerprint is stable and opaque (no raw host data leaves the machine):
Composer download gating
Apply the licensing.composer middleware to your private repository routes, or point
an nginx auth_request at the bundled endpoint:
Composer sends the buyer's email as the username and the license key as the password;
the bridge authorizes against the license's product, status, and (for
updates_window) the release date.
Filament admin (optional)
If you run a Filament panel, register the version-dispatching plugin — the same call works on Filament 3, 4, and 5:
It adds a Products resource (full CRUD) and a Licenses resource (browse, edit status/policy/seats, and a one-click revoke action). Licenses are minted through the issuer/API, so the Licenses resource has no "create" form by design.
Configuration
Key .env values:
| Variable | Purpose |
|---|---|
LICENSING_SIGNING_KEY |
Ed25519 secret — signs license files (server only) |
LICENSING_PUBLIC_KEY |
Ed25519 public — verifies files (server + clients) |
LICENSING_KEY_HASH_SECRET |
HMAC secret for key hashing (defaults to app key) |
LICENSING_SERVER_URL |
Client: base URL of the licensing API |
LICENSING_KEY |
Client: this install's license key |
LICENSING_HTTP_MODE |
REST API mode: headless (default) / api / ui |
See config/licensing.php for the full reference.
Testing
CI runs the same checks on every push and pull request
(.github/workflows/tests.yml), against PHP 8.4 / Laravel 13. Static analysis
is held at PHPStan level 8; the suite runs on Pest 5.
License
MIT © Ozan Kurt
All versions of laravel-modules-licensing with dependencies
ext-sodium Version *
illuminate/contracts Version ^13.0
illuminate/database Version ^13.0
illuminate/http Version ^13.0
illuminate/support Version ^13.0
ozankurt/laravel-modules-core Version ^2.0
spatie/laravel-package-tools Version ^1.93
spatie/laravel-translatable Version ^6.11