PHPackages                             masterix21/laravel-licensing-client - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. masterix21/laravel-licensing-client

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

masterix21/laravel-licensing-client
===================================

This is my package laravel-licensing-client

2.0.0(3mo ago)454474[1 PRs](https://github.com/masterix21/laravel-licensing-client/pulls)MITPHPPHP ^8.3 || ^8.4 || ^8.5CI passing

Since Sep 16Pushed 1mo agoCompare

[ Source](https://github.com/masterix21/laravel-licensing-client)[ Packagist](https://packagist.org/packages/masterix21/laravel-licensing-client)[ Docs](https://github.com/masterix21/laravel-licensing-client)[ GitHub Sponsors](https://github.com/masterix21)[ RSS](/packages/masterix21-laravel-licensing-client/feed)WikiDiscussions main Synced 2w ago

READMEChangelog (2)Dependencies (37)Versions (8)Used By (0)

Laravel Licensing Client
========================

[](#laravel-licensing-client)

[![Latest Version on Packagist](https://camo.githubusercontent.com/cb9f12f0b26c81442b16fe32febd9d8b5c89743bc1568ef393df0ac835ff23c4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d6173746572697832312f6c61726176656c2d6c6963656e73696e672d636c69656e742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/masterix21/laravel-licensing-client)[![GitHub Tests Action Status](https://camo.githubusercontent.com/dd07c49f59830d8a73bf822048d3a1e679e3ab50d51caf57d7d9f12510ab9c64/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6d6173746572697832312f6c61726176656c2d6c6963656e73696e672d636c69656e742f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/masterix21/laravel-licensing-client/actions?query=workflow%3Arun-tests+branch%3Amain)[![GitHub Code Style Action Status](https://camo.githubusercontent.com/ce76e7f45e465be95dcaa304833ea2d0abc3e04a649aa2e943ed357c1d56fcd7/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6d6173746572697832312f6c61726176656c2d6c6963656e73696e672d636c69656e742f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6272616e63683d6d61696e266c6162656c3d636f64652532307374796c65267374796c653d666c61742d737175617265)](https://github.com/masterix21/laravel-licensing-client/actions?query=workflow%3A%22Fix+PHP+code+style+issues%22+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/7a624e03b76f426b3bdfbb9c28cd7feda3b9a74a70e3db465d027ae812c8ce13/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6d6173746572697832312f6c61726176656c2d6c6963656e73696e672d636c69656e742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/masterix21/laravel-licensing-client)

A Laravel package for integrating license validation in your applications. Works with the [Laravel Licensing](https://github.com/masterix21/laravel-licensing) server to provide secure, offline-capable license management using PASETO v4 tokens with Ed25519 signatures.

Related Packages
----------------

[](#related-packages)

- **[Laravel Licensing Server](https://github.com/masterix21/laravel-licensing)** - Server-side license management
- **[Laravel Licensing Filament Manager](https://github.com/masterix21/laravel-licensing-filament-manager)** - Admin panel built with Filament

Requirements
------------

[](#requirements)

- PHP 8.3+
- Laravel 12 or 13

Installation
------------

[](#installation)

```
composer require masterix21/laravel-licensing-client
```

Publish the configuration:

```
php artisan vendor:publish --tag="licensing-client-config"
```

Run the migrations:

```
php artisan migrate
```

Configuration
-------------

[](#configuration)

Add these variables to your `.env`:

```
LICENSING_SERVER_URL=https://your-licensing-server.com
LICENSING_PUBLIC_KEY=your-base64-encoded-ed25519-public-key
LICENSING_KEY=LIC-XXXX-XXXX-XXXX-XXXX
```

The full configuration is in `config/licensing-client.php`:

```
return [
    'server_url' => env('LICENSING_SERVER_URL', 'https://licensing.example.com'),
    'api_version' => env('LICENSING_API_VERSION', 'v1'),
    'license_key' => env('LICENSING_KEY'),
    'public_key' => env('LICENSING_PUBLIC_KEY'),
    'issuer' => env('LICENSING_ISSUER', 'laravel-licensing'),

    'cache' => [
        'enabled' => env('LICENSING_CACHE_ENABLED', true),
        'store' => env('LICENSING_CACHE_STORE', 'file'),
        'ttl' => env('LICENSING_CACHE_TTL', 3600),
    ],

    'heartbeat' => [
        'enabled' => env('LICENSING_HEARTBEAT_ENABLED', true),
        'interval' => env('LICENSING_HEARTBEAT_INTERVAL', 3600),
    ],

    'grace_period_days' => env('LICENSING_GRACE_PERIOD_DAYS', 7),
    'timeout' => env('LICENSING_TIMEOUT', 30),
    'debug' => env('LICENSING_DEBUG', false),
    'storage_path' => storage_path('app/licensing'),

    'excluded_routes' => [
        'login',
        'register',
        'password/*',
        'licensing/*',
    ],
];
```

Usage
-----

[](#usage)

### Facade

[](#facade)

```
use LucaLongo\LaravelLicensingClient\Facades\LaravelLicensingClient;

// Activate
LaravelLicensingClient::activate('LIC-XXXX-XXXX-XXXX-XXXX');

// Check validity (offline, from stored PASETO token)
LaravelLicensingClient::isValid();

// Validate with exception on failure
$claims = LaravelLicensingClient::validate();

// Get license info from token claims
$info = LaravelLicensingClient::getLicenseInfo();
// Returns: [
//     'license_id' => 1,
//     'license_key_hash' => 'sha256...',
//     'status' => 'active',
//     'max_usages' => 5,
//     'expires_at' => '2027-01-07T00:00:00+00:00',
//     'issued_at' => '2027-01-01T00:00:00+00:00',
//     'license_expires_at' => '2027-12-31T23:59:59+00:00',
//     'force_online_after' => '2027-01-14T00:00:00+00:00',
//     'grace_until' => null,
//     'usage_fingerprint' => 'sha256...',
// ]

// Check expiration warnings
LaravelLicensingClient::isExpiringSoon(7);

// Check if online refresh is required (force_online_after exceeded)
LaravelLicensingClient::requiresOnlineRefresh();

// Proactive refresh check (based on refresh_after from server)
LaravelLicensingClient::shouldRefreshProactively();

// Refresh the token
LaravelLicensingClient::refresh();

// Deactivate (with optional reason)
LaravelLicensingClient::deactivate('LIC-XXXX-XXXX-XXXX-XXXX', 'switching device');

// Server health
LaravelLicensingClient::isServerHealthy();
```

### Dependency Injection

[](#dependency-injection)

```
use LucaLongo\LaravelLicensingClient\LaravelLicensingClient;

class LicenseController extends Controller
{
    public function status(LaravelLicensingClient $licensing)
    {
        return response()->json([
            'valid' => $licensing->isValid(),
            'info' => $licensing->getLicenseInfo(),
            'requires_refresh' => $licensing->requiresOnlineRefresh(),
        ]);
    }
}
```

Middleware
----------

[](#middleware)

Protect routes with the `license` middleware:

```
// Single route
Route::get('/dashboard', DashboardController::class)->middleware('license');

// Route group
Route::middleware('license')->group(function () {
    Route::get('/reports', ReportsController::class);
    Route::get('/analytics', AnalyticsController::class);
});
```

### Middleware Behavior

[](#middleware-behavior)

The middleware follows this flow:

1. Check if the route is excluded
2. Validate the stored token offline
3. If valid, check `force_online_after` — refresh if past date
4. If token invalid, attempt refresh from server
5. If refresh fails, check client-side grace period
6. If not in grace period, check server health
7. If server unreachable, start grace period and allow access
8. If server healthy and no valid license, block with 403

On valid requests, the middleware also:

- Sends heartbeat if interval has elapsed
- Sets `license_expiring_soon` and `license_expires_at` as request attributes if expiration is near

### Accessing Expiration Warnings

[](#accessing-expiration-warnings)

```
public function dashboard(Request $request)
{
    if ($request->attributes->get('license_expiring_soon')) {
        $expiresAt = $request->attributes->get('license_expires_at');
        // Show renewal warning
    }
}
```

### Excluding Routes

[](#excluding-routes)

Configure in `config/licensing-client.php`:

```
'excluded_routes' => [
    'login',
    'register',
    'password/*',
    'api/health',
],
```

Grace Period
------------

[](#grace-period)

The client manages a local grace period when the licensing server is unreachable:

```
// Check if in grace period
LaravelLicensingClient::isInGracePeriod();

// Manually start (useful for testing)
LaravelLicensingClient::startGracePeriod();
```

The default grace period is 7 days, configurable via `LICENSING_GRACE_PERIOD_DAYS`.

The middleware automatically enters grace period when the server is unreachable, allowing the application to continue working.

Artisan Commands
----------------

[](#artisan-commands)

```
# Activate a license (interactive if no key provided)
php artisan license:activate LIC-XXXX-XXXX-XXXX-XXXX

# Validate current license
php artisan license:validate

# Display license details
php artisan license:info

# Refresh token from server
php artisan license:refresh

# Deactivate license (with confirmation prompt)
php artisan license:deactivate
```

Heartbeat
---------

[](#heartbeat)

When enabled, the package automatically sends heartbeats to the licensing server at the configured interval. The heartbeat reports:

- Laravel version
- Application environment

Configure in `.env`:

```
LICENSING_HEARTBEAT_ENABLED=true
LICENSING_HEARTBEAT_INTERVAL=3600  # seconds
```

The heartbeat is registered as a scheduled task in the service provider and runs via Laravel's scheduler.

Token Validation
----------------

[](#token-validation)

The client validates PASETO v4 tokens offline using the Ed25519 public key. The following claims are validated:

ClaimValidation`usage_fingerprint`Must match the current device fingerprint`exp`Token must not be expired`status`Must be `active` or `grace``force_online_after`If past, an online refresh is requiredThe client also stores the `public_key_bundle` received from the server during activation and refresh, enabling future key rotation support.

Device Fingerprinting
---------------------

[](#device-fingerprinting)

The client generates a stable SHA-256 fingerprint from:

- Hostname
- Machine ID (platform-specific: `/etc/machine-id`, `IOPlatformUUID`, WMI UUID)
- PHP version
- Laravel version
- Application key

This fingerprint is sent to the server during activation to bind the license to the device.

### Custom Fingerprint Generator

[](#custom-fingerprint-generator)

```
use LucaLongo\LaravelLicensingClient\Services\FingerprintGenerator;

class CustomFingerprintGenerator extends FingerprintGenerator
{
    public function generate(): string
    {
        $components = [
            $this->getHostname(),
            $this->getMachineId(),
            config('app.deployment_id'),
        ];

        return hash('sha256', implode('|', array_filter($components)));
    }
}

// Register in a service provider
$this->app->bind(FingerprintGenerator::class, CustomFingerprintGenerator::class);
```

Error Handling
--------------

[](#error-handling)

The package throws `LicensingException` with specific factory methods:

```
use LucaLongo\LaravelLicensingClient\Exceptions\LicensingException;

try {
    LaravelLicensingClient::validate();
} catch (LicensingException $e) {
    // Possible messages:
    // - "The provided license key is invalid."
    // - "The license has expired."
    // - "The license has not been activated."
    // - "The license has been suspended."
    // - "The license has been cancelled."
    // - "Device fingerprint does not match the licensed device."
    // - "The fingerprint is already in use by another device."
    // - "License usage limit has been exceeded."
    // - "Offline tokens are not enabled for this license."
    // - "Too many requests to the licensing server. Please try again later."
    // - "Online verification is required. Please connect to the internet."
    // - "Unable to reach the licensing server."
    // - "The license token is invalid or corrupted."
    // - "Public key for token verification is not configured."
}
```

API Communication
-----------------

[](#api-communication)

The client communicates with the server at `/api/licensing/v1/` using these endpoints:

MethodEndpointDescriptionPOST`/activate`Activate a license with fingerprintPOST`/deactivate`Deactivate a licensePOST`/refresh`Refresh the PASETO tokenPOST`/heartbeat`Send heartbeat with usage dataPOST`/validate`Validate license server-sidePOST`/licenses/show`Get license informationGET`/health`Check server healthAll responses follow the format:

```
{
    "success": true,
    "data": { ... }
}
```

Error responses:

```
{
    "success": false,
    "error": {
        "code": "ERROR_CODE",
        "message": "Human-readable message"
    }
}
```

The client handles these HTTP error codes: 404 (invalid key), 403 (fingerprint mismatch / not active), 409 (usage limit / fingerprint conflict / offline disabled), 410 (expired), 422 (validation failed), 423 (suspended / cancelled), 429 (rate limited).

Testing
-------

[](#testing)

### In Your Application Tests

[](#in-your-application-tests)

```
use Illuminate\Support\Facades\Http;
use LucaLongo\LaravelLicensingClient\Facades\LaravelLicensingClient;

public function test_protected_route(): void
{
    Http::fake([
        '*/api/licensing/v1/activate' => Http::response([
            'success' => true,
            'data' => [
                'token' => 'v4.public.test-token...',
                'license' => ['id' => 'ulid', 'status' => 'active'],
            ],
        ]),
    ]);

    LaravelLicensingClient::activate('TEST-KEY');

    $this->get('/protected-route')->assertStatus(200);
}
```

### Mocking the Client

[](#mocking-the-client)

```
use LucaLongo\LaravelLicensingClient\LaravelLicensingClient;

$mock = Mockery::mock(LaravelLicensingClient::class);
$mock->shouldReceive('isValid')->andReturn(true);
$mock->shouldReceive('getLicenseInfo')->andReturn([
    'status' => 'active',
    'max_usages' => 5,
]);

$this->app->instance(LaravelLicensingClient::class, $mock);
```

### Running Package Tests

[](#running-package-tests)

```
composer test              # Run all tests
composer test-coverage     # Run with coverage
composer analyse           # PHPStan static analysis
composer format            # Laravel Pint formatting
```

Development Roadmap
-------------------

[](#development-roadmap)

The following features are planned for future releases:

### Phase 1 — Token Security

[](#phase-1--token-security)

- `iss` (issuer) claim validation
- `nbf` (not before) claim validation
- Clock skew tolerance (configurable, default ±60s)

### Phase 2 — Features &amp; Entitlements

[](#phase-2--features--entitlements)

- `hasFeature(string $feature): bool` and `getFeatures(): array`
- `getEntitlement(string $key, mixed $default = null): mixed`
- Feature-gating middleware: `Route::middleware('license:premium_export')`
- Features and entitlements are stored from the API response (not in the token)

### Phase 3 — Network Resilience

[](#phase-3--network-resilience)

- Automatic retry with exponential backoff via `Http::retry()`

### Phase 4 — License Information

[](#phase-4--license-information)

- Seat info: `getSeatsInfo()` (active/available/max usages)
- License vs token expiry distinction: `isLicenseExpiringSoon()`
- Server-side grace period awareness from `grace_until` token claim

### Phase 5 — Key Rotation

[](#phase-5--key-rotation)

- Public key selection via `kid` from token footer
- Proactive scheduled token refresh based on `refresh_after`

Contributing
------------

[](#contributing)

Contributions are welcome! Please submit a Pull Request.

License
-------

[](#license)

MIT License. See [LICENSE.md](LICENSE.md).

Credits
-------

[](#credits)

- [Luca Longo](https://github.com/masterix21)

###  Health Score

50

—

FairBetter than 95% of packages

Maintenance86

Actively maintained with recent releases

Popularity30

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity59

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 77.1% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~204 days

Total

2

Last Release

112d ago

Major Versions

v1.0.0 → 2.0.02026-04-08

PHP version history (2 changes)v1.0.0PHP ^8.2

2.0.0PHP ^8.3 || ^8.4 || ^8.5

### Community

Maintainers

![](https://www.gravatar.com/avatar/177020fc4adb5c08acee3e6fe0b65002a96665c5d5c522a3ef009b4105fd634f?d=identicon)[masterix](/maintainers/masterix)

---

Top Contributors

[![masterix21](https://avatars.githubusercontent.com/u/6555012?v=4)](https://github.com/masterix21 "masterix21 (27 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (6 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (2 commits)")

---

Tags

laravelLuca Longolaravel-licensing-client

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/masterix21-laravel-licensing-client/health.svg)

```
[![Health](https://phpackages.com/badges/masterix21-laravel-licensing-client/health.svg)](https://phpackages.com/packages/masterix21-laravel-licensing-client)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.3M348](/packages/psalm-plugin-laravel)[simplestats-io/laravel-client

Server-side analytics for Laravel that follows the full funnel from visit to registration to payment, attributed to the channel that drove it. Revenue, MRR, churn and ad-spend profit (ROAS/CAC) per channel. GDPR compliant, ad-blocker proof.

5022.6k](/packages/simplestats-io-laravel-client)[spatie/laravel-export

Create a static site bundle from a Laravel app

674146.0k6](/packages/spatie-laravel-export)[defstudio/telegraph

A laravel facade to interact with Telegram Bots

813336.8k3](/packages/defstudio-telegraph)[nativephp/mobile

NativePHP for Mobile

1.1k75.1k113](/packages/nativephp-mobile)[masterix21/laravel-licensing

Laravel licensing package with polymorphic assignment to any model, activation keys, expirations/renewals, and seat control via LicenseUsage. Supports offline verification with public-key–signed tokens, a CLI to generate/rotate/revoke keys, and an extensible architecture via config and contracts.

1613.3k4](/packages/masterix21-laravel-licensing)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
