How to add license keys to a Laravel app
Short answer: composer require sunlicense/sunlicense, put the buyer's key in their .env, and check it in a middleware, cached for 6 hours so requests stay fast. When SunLicense says no, show a "license problem" page instead of the app; when it can't be reached, keep serving and check later.
// app/Http/Middleware/EnsureLicensed.php
use Illuminate\Support\Facades\Cache;
use SunLicense\{SunLicenseClient, SunLicenseException};
public function handle($request, Closure $next)
{
$state = Cache::remember('myapp.license', now()->addHours(6), function () {
$key = trim((string) config('myapp.license_key'));
if ($key === '') return 'NOT_CONFIGURED';
try {
$r = (new SunLicenseClient('https://api.sunlicense.com', config('myapp.api_key')))
->validate($key, ['host' => hash('sha256', config('app.url'))]);
return $r->getStatusCode() === 400 ? ($r->toArray()['code'] ?? 'INVALID') : 'OK'; // EXPIRED, REVOKED…
} catch (SunLicenseException $e) {
return 'OK'; // unreachable: keep serving, check again when the cache expires
}
});
return $state === 'OK' ? $next($request) : response()->view('license-problem', ['code' => $state], 402);
}Register it on your app's routes (not on the page where the buyer enters the key), and add 'license_key' => env('MYAPP_LICENSE_KEY') and 'api_key' => … to config/myapp.php.
Or let your AI agent do it: paste the setup prompt into Claude Code, Cursor or Codex in your project.
Free plan: 3 products, 100 licenses, no credit card. Create a free account.
Step by step
- In the dashboard: a product, a policy where a machine is an install (for example "Regular" with 1 machine, "Extended" with 5) and an API key, which can only validate.
- Install:
composer require sunlicense/sunlicense(PHP 8.0+, cURL when available). - One install = one machine. Send a hash of
APP_URLashost, so moving servers keeps the slot and a second domain counts as a second install. - Your API key is in the code you ship (
config/myapp.php), since buyers run it themselves. It can only validate, so that's safe; keep it out of your public repository and inject it when you build the release zip. - The buyer's key goes in
.env(MYAPP_LICENSE_KEY) or an installer step that writes it. When they change it,Cache::forget('myapp.license'). - Results: 200 serves the app, 400 renders
license-problemwith the reason and how to fix it (mask the key), anything else serves and checks after the cache expires. A scheduled command (php artisan myapp:license-check, hourly) can refresh the cache so no visitor waits for it. - Updates: check the license in your update endpoint too, so a revoked key stops getting new versions.
Honest limits
PHP source is readable, and SunLicense's obfuscation doesn't cover PHP. A license key controls what you provide (updates, support, hosted services) and lets you switch off a leaked or refunded copy that keeps checking; someone determined can delete the middleware. Keep a piece that matters on your side, such as a hosted API the app calls with its key, if that's a concern.
Selling it
Envato (CodeCanyon purchase codes become SunLicense licenses), Lemon Squeezy, Gumroad, Payhip and Stripe issue a key per purchase and revoke it on a refund. Selling a WordPress plugin instead? See WordPress.
