JavaScript/TypeScript clients for lukk — minimal-dependency JWT authentication for first-party Laravel apps, plus an auth-aware fetch and reactive forms for talking to your own Laravel API correctly. Nuxt first; the core is framework-agnostic, so more bindings can follow.
Unofficial companion to lukk. Not affiliated with or endorsed by the Laravel or Nuxt teams. "Laravel" and "Nuxt" are referenced only to describe compatibility and design influence.
Pre-1.0 — expect breaking changes.
lukk-coreandlukk-nuxtare in the0.xseries and versioned in lockstep. Both are fully tested (100% coverage), but per semantic versioning for initial development, the public API and composable surface may change between minor versions without a major bump. Pin exact versions and read the UPGRADE guide (and each package'sCHANGELOG.md) before upgrading. The 1.0 release will mark API stability.
- One composable API, every rendering mode — the same
useLukkAuth()works in SSR, SPA, and SSG. - Two transport modes, a config switch apart — a BFF proxy that keeps tokens server-side (the browser never sees a token), or direct calls straight to lukk (the only option for fully static sites).
- The whole lukk surface — login, token refresh, logout, session revocation, two-factor, step-up confirmation, and passkeys.
- Call your own API, correctly —
useLukkFetch()is a typed, auth-aware fetch for your Laravel API: authenticated in every context (a plain$fetchsilently 401s in SSR), single-flight 401 refresh, credentials never leak cross-origin, and a typed Laravel error ({ message, status, errors }) ready to bind to a form. - Forms, bound to Laravel validation —
useLukkForm()is a reactive form in the spirit of Inertia'suseForm: submitdata, bind a422bag to per-field errors, withprocessing/isDirty/ lifecycle hooks and automaticmultipart/form-datafor file uploads. - Silent refresh, single-flight — a 401 transparently refreshes and retries; a burst of 401s triggers exactly one refresh.
- Typed end to end — the lukk HTTP contract mirrored in TypeScript, conformance-tested against a real lukk instance so it can't drift.
- Tiny —
lukk-corehas zero runtime dependencies;lukk-nuxtadds only@nuxt/kit+defu.
| Package | What it is |
|---|---|
lukk-core |
Framework-agnostic: the lukk HTTP contract types, the auth client (token attach + refresh + single-flight), and WebAuthn helpers. Use it directly in any TS app, or as the base for a binding. |
lukk-nuxt |
A Nuxt module (Nuxt 3 and 4): auto-imported composables, useLukkFetch() + useLukkForm() for your own API, route middleware, the BFF proxy, and the transport wiring. |
mode is a config switch — your app code never changes between them.
| Mode | How it works | Reach for it when |
|---|---|---|
bff (default) |
A Nitro proxy holds tokens in a sealed, server-side cookie; the browser only ever talks to your own origin. | SSR or a served SPA — the most secure option, no token in the browser. |
direct |
The client calls lukk directly. Access token in memory, refresh token in lukk's __Host- cookie. |
A fully static site (SSG), or a simple SPA with no runtime server. |
See Transport Modes for the security trade-offs and the SSR/SPA/SSG matrix.
- A lukk-powered Laravel API (latest
0.xrecommended — the newest client features track the latest lukk; e.g. registration needs lukk>= 0.4) - Node
>= 20 - Nuxt
3or4(forlukk-nuxt)
npm i lukk-nuxt// nuxt.config.ts
export default defineNuxtConfig({
modules: ['lukk-nuxt'],
lukk: {
baseURL: 'https://api.example.com/auth', // your lukk auth routes
mode: 'bff', // 'bff' (default) or 'direct'
user: { endpoint: '/api/me' }, // your app's authenticated user route
},
})<script setup lang="ts">
const { user, loggedIn, login, logout } = useLukkAuth()
async function onSubmit() {
await login({ email: email.value, password: password.value })
}
</script>In bff mode, also set a session secret (≥ 32 chars): NUXT_LUKK_SESSION_PASSWORD=…. See Installation for the full walkthrough.
📚 Full documentation: stsepelin.github.io/lukk-docs
lukk-js (this client) and lukk (the Laravel package) are documented together on one site — each feature page covers both the server and the client. Start with the Introduction or jump to Installation.
Planned and deliberately-deferred work is tracked in ROADMAP.md.
For AI assistants: the docs are exposed as /llms.txt + /llms-full.txt (llms.txt convention), and AGENTS.md has integration + contribution rules.
pnpm install
pnpm build # lukk-core, then lukk-nuxt
pnpm test # 100% coverage gate on both packages
pnpm lint
pnpm dev # the lukk-nuxt playgroundlukk-js is the client half of lukk and mirrors its HTTP contract; it also borrows liberally from the Laravel and Nuxt ecosystems. Sincere thanks to their authors and maintainers — lukk-js is an unofficial companion, not affiliated with or endorsed by any of them (see the note at the top); these are simply the works that shaped it:
- Inertia.js —
useLukkFormis modelled on Inertia'suseForm: thedata/processing/errors/isDirtysurface,422error-bag binding, andremembersemantics all follow its lead. - Nuxt — the module + auto-imported composable design, and the SSR/BFF story (a Nitro proxy holding tokens server-side) build directly on Nuxt's server/client model.
- Laravel Sanctum & Fortify — the auth contract lukk-js speaks, and its customization philosophy, originate here (via lukk).
- VueUse — the reference for ergonomic, composition-first composable API shapes.
- unjs —
lukk-coreand the BFF proxy are built on ofetch and h3 / Nitro.
And the tooling: changesets (releases), unbuild + @nuxt/module-builder (builds), and Vitest (the 100%-coverage gate) — plus the Nuxt and Laravel communities that make all of this possible. 🙏
MIT.