Skip to content

stsepelin/lukk

Repository files navigation

lukk

Latest Version Tests Coverage PHP Version License Total Downloads

Minimal-dependency JWT authentication for first-party Laravel apps (Laravel 12/13) — "first-party" meaning you own both the client and the API, so there's no third party to delegate to and no OAuth ceremony to perform.

Unofficial, independent package. Not affiliated with, endorsed by, or maintained by the Laravel team. "Laravel", "Sanctum", and "Fortify" are referenced only to describe compatibility and design influence; they are trademarks of their respective owners.

Features

  • Short-lived access JWTs (HS256, 15 min) — stateless, verified on every request with the algorithm pinned and iss/aud asserted.
  • Opaque rotating refresh tokens (30 days) — stored only as a sha256 hash, rotated on every use.
  • Reuse detection — replaying a consumed token revokes the whole session (token family).
  • Concurrency grace window — multiple tabs / SSR refresh without false logouts.
  • Instant revocation — a cache-backed denylist kills an access token or a whole session within one request.
  • Optional two-factor auth (TOTP + recovery codes) and passkeys (WebAuthn / FIDO2), each opt-in and feature-gated.
  • Sanctum/Fortify-style design — a contract per swappable piece, single-purpose Actions, a static Lukk config hub, a dedicated guard, and Responsable response contracts.

The single runtime dependency is firebase/php-jwt, the audited JWS primitive — never hand-roll JWT. Everything else is Laravel core.

Token model

Access token HS256 JWT, 15 min. Claims iss/aud/sub/fid/jti/iat/nbf/exp, header typ=at+jwt. Verified every request: alg pinned, iss/aud asserted, denylist checked by jti and fid.
Refresh token Opaque 256-bit secret, 30 days. Returned once; stored only as sha256. Rotated on every refresh; reuse after the grace window revokes the whole family.

HS256 is correct while this app is its own sole verifier. RS256/ES256 + a JWKS endpoint + kid key rotation are built in (behind the same contracts) for when an independent service must verify tokens — flip LUKK_ALGORITHM and run php artisan lukk:keygen. See Architecture & Security.

Requirements

  • PHP ^8.3
  • Laravel ^12.0 | ^13.0
  • firebase/php-jwt ^7.0

Quick start

composer require lukk/lukk

php artisan vendor:publish --tag=lukk-config       # config/lukk.php
php artisan vendor:publish --tag=lukk-migrations   # refresh_tokens migration
php artisan migrate
php artisan lukk:secret                            # writes LUKK_SECRET to .env

Map a guard to the lukk-jwt driver in config/auth.php:

'guards' => [
    'api' => ['driver' => 'lukk-jwt', 'provider' => 'users'],
],

Then protect routes with auth:api as usual:

Route::middleware('auth:api')->get('/me', fn (Request $r) => $r->user());

The package registers login, refresh, logout, and session-revocation (DELETE /sessions, DELETE /sessions/others) routes automatically. See Installation and Authentication for the full walkthrough.

Documentation

📚 Full documentation: stsepelin.github.io/lukk-docs

lukk (the Laravel package) and lukk-js (the TypeScript/Nuxt client) are documented together on one site — each feature page covers both the server and the client. Start with the Introduction or jump to Installation.

For AI assistants: the docs are exposed as /llms.txt + /llms-full.txt (llms.txt convention), and AGENTS.md has integration + contribution rules.

Testing

composer install
vendor/bin/pest

License

MIT.

About

First-party JWT auth for Laravel 12/13 — short-lived access JWTs + opaque rotating refresh tokens with reuse detection, no OAuth ceremony. The Laravel (server) half of lukk; pairs with the lukk-js client.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages