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.

Pre-1.0 — expect breaking changes. lukk is in the 0.x series. The core is production-minded and fully tested (100% coverage), but per semantic versioning for initial development, the public API, config, and database schema may change between minor versions without a major bump. Pin an exact version and read the UPGRADE guide (and the CHANGELOG) before upgrading — a release may require re-running migrations. The 1.0 release will mark API/schema stability.

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

Acknowledgements

lukk stands on the shoulders of the Laravel ecosystem, and its design is a deliberate synthesis of ideas from the first-party packages. Sincere thanks to their authors and maintainers — lukk isn't affiliated with or endorsed by any of them (see the note at the top); these are simply the works that shaped it:

  • Laravel Sanctum — the architectural model. HasRefreshTokens is the HasApiTokens analog, the static Lukk hub mirrors Sanctum's configuration style, and the publish-only migration convention is borrowed wholesale.
  • Laravel Fortify — the customization philosophy: single-purpose actions + rebindable response contracts, hooks like Lukk::registerUsing() (à la Fortify::createUsersUsing()), the Password::defaults() policy, and the configurable login identifier.
  • Laravel Passport — conventions for token issuance, publish-only migrations, and keeping models extensible.
  • Laravel Jetstream & Breeze — the reference for two-factor + single-use recovery codes and step-up ("sudo") confirmation, and — with Inertia and the Nuxt ecosystem — the first-party client-side patterns that shaped lukk-js.
  • tymon/jwt-auth — the established Laravel JWT package; its lock_subject approach to cross-guard isolation directly informed lukk's multi-guard design.

And the libraries lukk is built on: firebase/php-jwt (the sole runtime dependency), pragmarx/google2fa (TOTP), and web-auth/webauthn-lib by Spomky-Labs (passkeys) — plus the Laravel framework and community that make all of this possible. 🙏

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

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages