akira / laravel-license-core
Modern, secure and extensible licensing engine for Laravel applications. The Core package provides the full domain logic, models, pipelines, value objects, builders and actions required to implement a complete licensing system inside Laravel — without forcing any UI, API or dashboard layer.
Fund package maintenance!
kidiatoliny
Installs: 7
Dependents: 1
Suggesters: 0
Security: 0
Stars: 2
Watchers: 1
Forks: 0
Open Issues: 0
pkg:composer/akira/laravel-license-core
Requires
- php: ^8.4
- illuminate/contracts: ^12.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- akira/laravel-debugger: ^1.3
- driftingly/rector-laravel: ^2.1
- larastan/larastan: ^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.8
- orchestra/testbench: ^10.0|^11.0
- peckphp/peck: ^0.2
- pestphp/pest: ^4.0
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- pestphp/pest-plugin-type-coverage: ^4.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- rector/rector: ^2.2
This package is auto-updated.
Last update: 2025-11-29 23:19:55 UTC
README
A modern, secure and extensible licensing engine for Laravel applications. This package provides the complete domain logic, models, and business rules required to implement a full-featured licensing system inside Laravel applications.
Requirements
- PHP 8.4 or higher
- Laravel 12.x or higher
Features
- Multiple license types: Lifetime, Annual, Subscription, Trial, and Credits-based
- License status management: Active, Expired, Suspended, and Revoked
- Activation tracking with domain, machine hash, IP, and user agent
- Usage monitoring with consumed units and limits
- Event logging for complete audit trail
- Grace period support for expired licenses
- Encrypted metadata storage
- Comprehensive configuration system for all business rules
- Configurable table names and models
- Dynamic pipeline stage loading
- Custom key generation formats (UUID and sequential)
- Full factory support for testing
- 100% test coverage (438 tests, 764 assertions)
Installation
You can install the package via composer:
composer require akira/laravel-license-core
You can publish and run the migrations with:
php artisan vendor:publish --tag="laravel-license-core-migrations"
php artisan migrate
You can publish the config file with:
php artisan vendor:publish --tag="laravel-license-core-config"
This is the contents of the published config file:
return [ 'tables' => [ 'licenses' => 'licenses', 'activations' => 'license_activations', 'usages' => 'license_usages', 'events' => 'license_events', ], 'models' => [ 'license' => License::class, 'activation' => LicenseActivation::class, 'usage' => LicenseUsage::class, 'event' => LicenseEvent::class, ], ];
Usage
Using the License Facade
The simplest way to work with licenses is through the License facade:
use Akira\LaravelLicense\Facades\License; use Akira\LaravelLicense\ValueObjects\LicenseData; use Akira\LaravelLicense\Enums\LicenseType; use Akira\LaravelLicense\Enums\LicenseStatus; // Create a license with auto-generated key $license = License::createWithAutoKey( new LicenseData( key: '', type: LicenseType::ANNUAL, status: LicenseStatus::ACTIVE, maxActivations: 5, maxSeats: 10, fallback: false, scopes: ['feature:premium'], meta: ['customer_email' => 'john@example.com'], expiresAt: now()->addYear(), graceEndsAt: null, ) ); // Validate license usage $isValid = License::validateUsage( key: $license->key, machine: 'unique-machine-fingerprint', domain: 'example.com', activate: true ); // Validate license for updates $canUpdate = License::validateUpdate( key: $license->key, releaseDate: now(), domain: 'example.com', machine: 'unique-machine-fingerprint' ); // Consume credits $success = License::consumeCredits( key: $license->key, amount: 10 ); // Rotate license key $newKey = License::rotateKey($license->key);
Creating a License Directly
You can also create licenses using the model:
use Akira\LaravelLicense\Models\License; use Akira\LaravelLicense\Enums\LicenseType; use Akira\LaravelLicense\Enums\LicenseStatus; $license = License::create([ 'key' => 'XXXX-XXXX-XXXX-XXXX', 'type' => LicenseType::ANNUAL->value, 'status' => LicenseStatus::ACTIVE->value, 'max_activations' => 5, 'max_seats' => 10, 'expires_at' => now()->addYear(), ]);
Using Factories
// Create a basic license $license = License::factory()->create(); // Create an active annual license $license = License::factory() ->active() ->annual() ->create(); // Create a license with grace period $license = License::factory() ->withGracePeriod() ->create(); // Create a license with metadata $license = License::factory() ->withMeta(['customer_id' => 123]) ->create();
License Activation
use Akira\LaravelLicense\Models\LicenseActivation; $activation = LicenseActivation::create([ 'license_id' => $license->id, 'domain' => 'example.com', 'machine_hash' => hash('sha256', 'unique-machine-id'), 'ip' => request()->ip(), 'user_agent' => request()->userAgent(), ]); // Using factory $activation = LicenseActivation::factory() ->forLicense($license) ->withDomain('example.com') ->create();
Usage Tracking
use Akira\LaravelLicense\Models\LicenseUsage; $usage = LicenseUsage::create([ 'license_id' => $license->id, 'consumed_units' => 0, 'limit' => 1000, ]); // Check remaining units $remaining = $usage->remaining(); // 1000 // Consume units $usage->update(['consumed_units' => 250]); $remaining = $usage->remaining(); // 750 // Using factory $usage = LicenseUsage::factory() ->forLicense($license) ->withLimit(1000) ->fresh() // 0 consumed units ->create();
Event Logging
use Akira\LaravelLicense\Models\LicenseEvent; use Akira\LaravelLicense\Enums\LicenseEventType; $event = LicenseEvent::create([ 'license_id' => $license->id, 'type' => LicenseEventType::ACTIVATED->value, 'payload' => [ 'ip' => request()->ip(), 'user_agent' => request()->userAgent(), ], 'created_at' => now(), ]); // Using factory $event = LicenseEvent::factory() ->forLicense($license) ->activated() ->withPayload(['user_id' => 123]) ->create();
Working with License Status
// Check if license is expired if ($license->isExpired()) { // Handle expired license } // Check if license is in grace period if ($license->inGracePeriod()) { // Show warning to user } // Get license status as enum $status = $license->statusEnum(); // LicenseStatus enum // Get license type as enum $type = $license->typeEnum(); // LicenseType enum
Relationships
// Get all activations for a license $activations = $license->activations; // Get all usage records for a license $usages = $license->usages; // Get all events for a license $events = $license->events; // Get license from activation $license = $activation->license;
Configuration System
The package includes a comprehensive configuration system that controls all business rules without code changes. Configuration is centralized in config/license.php.
Key Configuration Features
Key Generation:
'key_generation' => [ 'prefix' => 'LIC', // Key prefix 'format' => 'uuid', // 'uuid' or 'sequential' ],
Grace Period:
'grace_period' => [ 'lifetime' => null, // Days after lifetime expiration 'annual' => null, // Days after annual expiration 'subscription' => 30, // Days after subscription expiration 'trial' => 7, // Days after trial expiration 'credits' => null, // Days after credits expiration ],
Abuse Detection:
'abuse_detection' => [ 'enabled' => true, 'window_minutes' => 10, 'activation_threshold' => 10, 'events_to_monitor' => ['activated'], 'action_on_abuse' => 'log', // 'log' or 'suspend' ],
Pipeline Configuration:
'pipeline' => [ 'usage' => [ 'resolve_license', 'status_check', 'expiration_usage', 'grace_period', 'domain_check', 'machine_check', 'credits_usage', 'abuse_heuristics', ], 'update' => [ 'resolve_license', 'status_check', 'expiration_usage', 'grace_period', 'update_window', ], ],
Credits Configuration:
'credits' => [ 'allow_partial_consumption' => false, 'allow_refund' => false, ],
See the Configuration Documentation for complete details on all configuration options.
Custom Table Names
You can customize table names in the config file:
'tables' => [ 'licenses' => 'my_licenses', 'activations' => 'my_activations', 'usages' => 'my_usages', 'events' => 'my_events', ],
Encrypted Metadata
License metadata is automatically encrypted:
$license = License::create([ 'key' => 'XXXX-XXXX-XXXX-XXXX', 'type' => LicenseType::ANNUAL->value, 'status' => LicenseStatus::ACTIVE->value, 'meta' => [ 'customer_email' => 'user@example.com', 'plan_name' => 'Professional', 'features' => ['api_access', 'priority_support'], ], ]); // Metadata is automatically encrypted in database // and decrypted when accessed $email = $license->meta['customer_email'];
Available License Types
The package includes the following license types through the LicenseType enum:
LIFETIME- Permanent license with no expirationANNUAL- Annual subscription that expires after one yearSUBSCRIPTION- Recurring subscription-based licenseTRIAL- Trial license with limited time periodCREDITS- Credit-based license for usage tracking
Available License Statuses
License statuses are managed through the LicenseStatus enum:
ACTIVE- License is active and can be usedEXPIRED- License has passed its expiration dateSUSPENDED- License is temporarily suspendedREVOKED- License has been permanently revoked
Available Event Types
Events are tracked using the LicenseEventType enum:
CREATED- License was createdACTIVATED- License was activated on a device/domainDEACTIVATED- License was deactivatedROTATED- License key was rotatedREVOKED- License was revokedUSAGE_CONSUMED- Usage units were consumedEXPIRED- License expiredABUSE_DETECTED- Potential abuse was detected
Testing
Run the test suite:
composer test
Run tests with coverage:
composer test:coverage
The package includes 438 tests with 100% code coverage across all components:
Test Coverage
- Commands: LaravelLicenseCommand
- Enums: LicenseType, LicenseStatus, LicenseEventType
- Facades: License
- Models: License, LicenseActivation, LicenseEvent, LicenseUsage
- Support: ConfigManager, KeyGenerator
- Value Objects: DomainName, LicenseContext, LicenseKey, LicenseMeta, LicenseScopes, MachineFingerprint, UpdateEntitlement, UsageAmount
- Configuration Objects: AbuseDetectionConfiguration, CreditsConfiguration, DomainValidationConfiguration, GracePeriodConfiguration, KeyGenerationConfiguration, LicenseTypeConfiguration, PipelineConfiguration
- Pipeline Stages: All 9 validation stages with complete coverage
Additional Test Commands
# Run specific test file ./vendor/bin/pest tests/Models/LicenseTest.php # Run tests in specific directory ./vendor/bin/pest tests/ValueObjects/ # Run with detailed coverage ./vendor/bin/pest --coverage --min=100
Documentation
Complete documentation is available in the docs directory:
- Index - Documentation index and navigation
- Installation - Installation and setup guide
- Configuration - Comprehensive configuration reference with all options
- Models - Model documentation and relationships
- Pipelines - Pipeline architecture and custom stages
- Usage Guide - Comprehensive usage examples and patterns
- Value Objects - Immutable domain objects
- Actions - Domain actions and business logic
- Exceptions - Exception handling and error cases
- Testing - Comprehensive testing guide and examples
- Internationalization - i18n and localization
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.