laravel-workersv0.4.10
documentation

docs / Auth & sessions

Auth & sessions

Auth is compiled, not delegated: the session guard, the CSRF middleware and the throttle run on the Workers kernel. The one thing that cannot be compiled is a guard driver your app defines in PHP.

The session guard

surfaceverdict
Auth::attempt / login / logoutcompiled, byte-parity with PHP 8.3 (13 guard runs)
remember-me, recaller cookiecompiled, with token rotation
EloquentUserProvidercompiled against your model
BcryptHasherbcryptjs with $2y$ ⇄ $2b$ parity both ways
auth, guest, auth.basic middlewarecompiled, including 401 JSON vs redirect
Gate::allows / deniespolicies compiled at build time; the before() hook honoured
Gate::authorize / any / definefails loud — use allows()/denies(), or a port

Session and CSRF

Sessions live in D1 (the database driver) and carry flash data, rotation,migrate/regenerate/invalidate, the token plumbing and thePreventRequestForgery middleware. @csrf and @method work inside compiled views; the token is compared in constant time like Laravel does.

Cookie encryption is the Encrypter parity path: AES-256-CBC with an HMAC, over WebCrypto, using the same key derivation and serialization as PHP. A cookie minted by Laravel opens at the edge and the reverse — which is what lets you run both during a migration.

Throttling

Numeric throttle:n[,m] is wired over the D1-backed database cache store, with the same counter semantics as Laravel. A named rate limiter needs itsAppServiceProvider definition, which the build cannot run — it fails loud and asks you to write the numbers inline.

When your app registers its own guard

Auth::extend('seal', …) is a PHP closure. The compiled rung cannot run it, and silently answering “no user” would let a guarded route through — so the build refuses, at config level, before any route is compiled. The way out is a guard port: declare the driver and provide user(ctx).

ports/seal-guard.mjsjavascript
// registry.json → "guards": { "seal": "seal-guard" }
// ports/seal-guard.mjs
export default {
  async user(ctx) {
    const id = await readToken(ctx.request, ctx.app.env.SEAL_KEY);
    return id === null ? null : ctx.app.models.User.find(ctx.app.db, id);
  },
};
rulewhy
the module exports user(ctx)required; a port without it is refused at build time
throw on failure, return null for a guesta throwing port keeps throwing: a failure never degrades into “no user”
call via ctx.app.*bindings are ctx.app.env, ctx.app.db, ctx.app.models — never at the top level
once per guard per requestPortedGuard memoises; the memo drops on setRequest()

Only the driver is yours. auth:seal still resolves through the compiledAuthenticate middleware; auth()->user(), theguest middleware, the 401/redirect and Auth::viaRemember stay compiled.

Source: README.md §Compiles today, §A guard port; COMPILED.md; README §Auth row — repository ba1e9a5