Download the PHP package devravik/laravel-licensing without Composer
On this page you can find all versions of the php package devravik/laravel-licensing. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download devravik/laravel-licensing
More information about devravik/laravel-licensing
Files in devravik/laravel-licensing
Package laravel-licensing
Short Description A production-ready Laravel package for generating, managing, activating, and validating software licenses.
License MIT
Homepage https://github.com/devravik/laravel-licensing
Informations about the package laravel-licensing
Laravel Licensing
A production-ready Laravel package for generating, managing, activating, and validating software licenses directly inside your application.
License keys are hashed before storage (never plaintext in the database), activations are seat-controlled, and the entire lifecycle creation, validation, activation, revocation, and expiry is covered by typed exceptions and dispatchable events.
Starter Kit
New to this package? Check out the Laravel Licensing Starter a complete working example that demonstrates how to use this package in a real Laravel application.
The starter kit includes:
- Full license management dashboard
- User management with license assignment
- License creation, activation, and validation workflows
- API endpoints for license validation and activation
- Complete UI built with Laravel Breeze
- Demo data and examples
Perfect for understanding how to integrate this package into your own application!
Requirements
| Dependency | Version |
|---|---|
| PHP | ^8.1 (PHP 8.2+ required for Laravel 11 / 12) |
| Laravel | ^10.0 \| ^11.0 \| ^12.0 |
Installation
1. Install via Composer
2. Publish the config
3. Publish the migrations
4. Run the migrations
The package auto-registers its service provider via Laravel's package discovery. No manual registration is required.
Configuration
After publishing, the config file lives at config/license.php:
| Option | Type | Default | Description |
|---|---|---|---|
license_model |
string |
License::class |
Eloquent model for licenses |
activation_model |
string |
Activation::class |
Eloquent model for activations |
key_length |
int |
32 |
Length of generated license keys (chars) |
hash_keys |
bool |
true |
Hash keys with bcrypt before storage |
default_expiry_days |
int\|null |
365 |
Default license duration; null = no expiry |
grace_period_days |
int |
7 |
Days of temporary validity after expiry; 0 = disabled |
license_generation |
string |
'random' |
Generation strategy: 'random' or 'signed' |
signature.public_key |
string\|null |
null |
Ed25519 public key (file path or base64 string) |
signature.private_key |
string\|null |
null |
Ed25519 private key (file path or base64 string) |
Environment variables:
Usage
Creating a License
Use the HasLicenses trait on any Eloquent model that should own licenses, then build with the fluent API:
Builder reference:
| Method | Description | Required |
|---|---|---|
for(Model $owner) |
Bind the license to an Eloquent model | Yes |
product(string $product) |
Set the product name or tier | Yes |
seats(int $count) |
Maximum activations allowed (default: 1) | No |
expiresInDays(int $days) |
Expiry relative to now | No |
expiresAt(Carbon $date) |
Explicit expiry date | No |
create() |
Persist and return the license | Yes |
If neither
expiresInDays()norexpiresAt()is called, the value fromconfig('license.default_expiry_days')is used.
Validating a License
Activating a License
Bind a license to a domain, IP address, machine ID, or any identifier. Each binding consumes one seat.
Deactivating a License
Remove an activation to free up a seat:
Revoking a License
Immediately and permanently invalidate a license:
Checking License Status
Facade Reference
| Method | Signature | Returns | Description |
|---|---|---|---|
for |
for(Model $owner) |
LicenseBuilder |
Begin building a license |
validate |
validate(string $key) |
License |
Validate and return license; throws on failure |
activate |
activate(string $key, string $binding) |
Activation |
Activate a license against a binding |
deactivate |
deactivate(string $key, string $binding) |
bool |
Remove an activation binding |
revoke |
revoke(string $key) |
bool |
Permanently revoke a license |
find |
find(string $key) |
License\|null |
Find a license without validation |
Artisan Commands
The package provides comprehensive Artisan commands for managing licenses:
Generate License Keys
Generate Ed25519 key pairs for signed license verification:
Options:
--force- Overwrite existing keys if they already exist--show- Display the generated keys in the console--write- Automatically append keys to your.envfile
License Status
Check package configuration and status:
List Licenses
List all licenses with optional filtering:
Options:
--product- Filter by product name--owner-type- Filter by owner model class--owner-id- Filter by owner ID--status- Filter by status (active|expired|revoked)--expired- Show only expired licenses--revoked- Show only revoked licenses--per-page- Number of licenses per page (default: 15)
Show License
Display detailed information about a specific license:
Options:
--key- License key--id- License ID--full- Show full license key (unmasked)
Create License
Create a new license interactively or via options:
Options:
--owner-type- Owner model class (e.g.,App\\Models\\User)--owner-id- Owner model ID--product- Product name or tier--seats- Number of seats (default: 1)--expires-days- Days until expiration (leave empty for never)--non-interactive- Skip interactive prompts
Revoke License
Revoke a license by key or ID:
Options:
--key- License key--id- License ID--force- Skip confirmation prompt
Activate License
Activate a license for a binding:
Options:
--key- License key--id- License ID--binding- Activation binding (domain, IP, machine ID, etc.)
Deactivate License
Remove an activation binding:
Options:
--key- License key--id- License ID--binding- Binding to remove (if omitted, shows list to choose from)
License Statistics
Display license and activation statistics:
Options:
--product- Filter statistics by product
Output includes:
- Total, active, expired, and revoked license counts
- Total, used, and available seat counts
- Total activation count
- Seat usage percentage
Middleware
The package ships two middleware aliases that are registered automatically.
Protect routes requiring a specific product
Protect routes requiring any valid license
The middleware reads the license key from the X-License-Key request header (or license_key query/body parameter).
Middleware Responses
| Failure Reason | HTTP Status |
|---|---|
| No key provided | 401 Unauthorized |
| Key not found | 404 Not Found |
| Revoked or expired | 403 Forbidden |
| Wrong product tier | 403 Forbidden |
| Seat limit exceeded | 422 Unprocessable Entity |
For Accept: application/json requests the middleware returns:
For web requests, abort() is called with the appropriate status code.
You can customise the response by extending AbstractLicenseMiddleware and overriding denyResponse().
Events
| Event | Fired When | Properties |
|---|---|---|
LicenseCreated |
create() is called |
$event->license |
LicenseActivated |
activate() is called |
$event->license, $event->activation |
LicenseDeactivated |
deactivate() is called |
$event->license, $event->binding |
LicenseRevoked |
revoke() is called |
$event->license |
LicenseExpired |
Dispatched manually from a scheduled command | $event->license |
LicenseExpired is intentionally not dispatched automatically it should be fired from a scheduled command so you control when and how expiration is processed:
Registering Listeners
Exceptions
All exceptions extend LicenseManagerException, so you can catch them collectively or individually.
| Exception | Thrown When | getStatusCode() |
|---|---|---|
InvalidLicenseException |
Key does not match any record | 404 |
LicenseExpiredException |
Expired beyond grace period | 403 |
LicenseRevokedException |
License has been revoked | 403 |
SeatLimitExceededException |
All activation seats occupied | 422 |
LicenseAlreadyActivatedException |
Binding already exists for this license | 409 |
LicenseManagerException |
Base exception (catch-all) | 500 |
Global Exception Handler
Database Schema
licenses
| Column | Type | Notes |
|---|---|---|
id |
bigint PK |
Auto-increment |
key |
varchar(255) |
Bcrypt hash of the raw key (or plaintext if hash_keys=false) |
lookup_token |
varchar(64) nullable, indexed |
SHA-256 of raw key; used for O(log n) pre-filtering before bcrypt check |
product |
varchar(255) indexed |
Product name or tier |
owner_id |
bigint indexed |
Polymorphic FK |
owner_type |
varchar(255) |
Polymorphic type |
seats |
int default 1 |
Maximum activations allowed |
expires_at |
timestamp nullable |
Expiration timestamp |
revoked_at |
timestamp nullable |
Set when revoked; null = active |
created_at / updated_at |
timestamp |
Laravel timestamps |
license_activations
| Column | Type | Notes |
|---|---|---|
id |
bigint PK |
Auto-increment |
license_id |
bigint FK |
Cascades on delete |
binding |
varchar(255) |
Domain, IP, machine ID, or custom string |
activated_at |
timestamp |
When activation occurred |
created_at / updated_at |
timestamp |
Laravel timestamps |
A unique composite index on (license_id, binding) prevents duplicate activations.
Advanced Usage
Polymorphic Ownership
Licenses can belong to any model not just users. Add the HasLicenses trait:
Querying Licenses
Custom License Model
Update config/license.php:
Custom Activation Model
Using in Controllers
Security
- Key generation uses
random_bytes()a cryptographically secure CSPRNG. Noopensslextension required. - Key storage keys are hashed with bcrypt via Laravel's
Hashfacade before being written to the database. The raw key is never persisted. A SHA-256lookup_tokenis stored alongside to enable fast lookups without a full-table bcrypt scan. - Key comparison uses
Hash::check(), which is resistant to timing attacks. - One-time retrieval the raw key is available only during the
create()call. Transmit it to the end user immediately over a secure channel (HTTPS). - Signature-based verification (v1.1+) optional Ed25519 signature-based license verification for offline and tamper-resistant validation scenarios. When enabled, license keys contain cryptographically signed payloads that can be verified without database access.
Production checklist:
- Keep
hash_keys = truenever disable in production. - Use HTTPS for all endpoints that transmit or receive license keys.
- Rate-limit validation and activation endpoints to prevent brute-force guessing.
- Use the provided events to audit all license operations.
- Never log raw license keys.
- For signed licenses, store private keys securely and never commit them to version control.
Testing
The package test suite runs against MySQL:
Create the MySQL test database first:
Example Test
Signature-Based License Verification (v1.1+)
v1.1 adds optional Ed25519 signature-based license verification for offline and tamper-resistant validation scenarios.
Enabling Signed Licenses
Set LICENSE_GENERATION=signed in your .env file and provide Ed25519 key pair:
Or use file paths:
Generating Key Pairs
Generate an Ed25519 key pair using the Artisan command:
This will generate a new key pair and display the values to add to your .env file.
Options:
--force- Overwrite existing keys if they already exist--show- Display the generated keys in the console--write- Automatically append keys to your.envfile
Example:
Manual Generation (Alternative):
If you prefer to generate keys manually using PHP:
How It Works
When license_generation is set to 'signed':
- Generation: License keys are created by signing a JSON payload (product, seats, expiry, owner info) with the private key using Ed25519.
- Format: Keys are base64-encoded strings containing
base64(message . '.' . signature). - Verification: During validation, the signature is verified using the public key before database lookup.
- Storage: Signed licenses are still stored in the database (hashed) for seat management, activations, and revocation tracking.
Benefits
- Offline validation: Verify license authenticity without database access
- Tamper resistance: Any modification to the license key invalidates the signature
- Cryptographic proof: Ed25519 provides strong cryptographic guarantees
- Backward compatible: Default behavior remains random generation
Example
Changelog
Please see CHANGELOG.md for a full release history.
Contributing
Contributions are welcome. Please:
- Fork the repository and create a feature branch from
main. - Write tests for all new functionality.
- Follow PSR-12 and run
composer formatbefore submitting. - Ensure
composer testandcomposer analysepass. - Open a pull request with a clear description of the change.
Pull requests without tests will not be merged.
When reporting a bug, please include your PHP and Laravel version, the package version, steps to reproduce, and any relevant stack traces.
Security Vulnerabilities
Please do not report security vulnerabilities via GitHub Issues. Email [email protected] with the subject line [SECURITY] devravik/laravel-licensing <brief description>. You will receive a response within 48 hours.
See SECURITY.md for details.
Maintainer
Ravi K Gupta
- Website: devravik.github.io
- Email:
[email protected] - LinkedIn: linkedin.com/in/ravi-k-dev
- GitHub: github.com/devravik
License
The MIT License (MIT). Please see LICENSE for more information.
All versions of laravel-licensing with dependencies
illuminate/console Version ^10.0|^11.0|^12.0
illuminate/contracts Version ^10.0|^11.0|^12.0
illuminate/database Version ^10.0|^11.0|^12.0
illuminate/events Version ^10.0|^11.0|^12.0
illuminate/hashing Version ^10.0|^11.0|^12.0
illuminate/routing Version ^10.0|^11.0|^12.0
illuminate/support Version ^10.0|^11.0|^12.0