Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Larapass Laravel Package

darkghosthunter/larapass

Larapass adds WebAuthn and passkey authentication to Laravel. Users can register security keys or device biometrics and sign in without a password, with ready-made models, routes, and events for simple, phishing-resistant passwordless login.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install the package and publish its assets/migrations:
    composer require darkghosthunter/larapass
    php artisan vendor:publish --tag=larapass-config
    php artisan vendor:publish --tag=larapass-migrations
    php artisan migrate
    
  • Look at config/larapass.php first. The four knobs that cause 90% of setup pain are relying_party.id, relying_party.origin, user_handle, and guard.
  • Add the credential relationship to your authenticatable model:
    use DarkGhostHunter\Larapass\WebAuthnAuthenticatable;
    
    class User extends Authenticatable
    {
        use WebAuthnAuthenticatable; // adds webAuthnCredentials() and handle logic
    }
    
  • The package ships pre-registered routes (registration options/attestation and login options/assertion). Consume the bundled JS helper or roll your own navigator.credentials.create() / navigator.credentials.get() calls against them.
  • First useful milestone: register a passkey on a profile screen (POST attestation), confirm a row lands in web_authn_credentials, then log out and authenticate with that passkey through the login endpoints. Once that loop works end-to-end, everything else is configuration.
  • Verify the schema before trusting it on v3.0.2 — run a quick SHOW COLUMNS/Schema::getColumnType() check on web_authn_credentials.attestation_type; it should be a string, not JSON.

Implementation Patterns

Standard register-then-login flow

Two browser round trips per ceremony: fetch options, then post the credential/assertion back. Keep the challenge in the same session/statefulness context.

  • Registration: GET options → navigator.credentials.create() → POST attestation payload → package stores a WebAuthn\PublicKeyCredentialSource in web_authn_credentials.
  • Assertion: GET options → navigator.credentials.get() → POST payload → package validates signature and resolves the user.

Headless / custom controllers

Skip the shipped routes and drive the facade directly when you need a JSON API, custom guards, or extra business rules:

use DarkGhostHunter\Larapass\Facades\WebAuthn; // or Larapass facade

$options = WebAuthn::generateAttestation($user);   // PublicKeyCredentialCreationOptions
// ... send JSON to browser, receive response ...
WebAuthn::validateAttestation($data, $user);        // returns credential source

Disable the built-in routes (routes => false or the env toggle) as soon as you go headless, otherwise you get duplicate URLs and confusing CSRF failures.

Userless (passwordless) login

Pass a null user into the assertion options to get an "allow any credential" challenge; the package resolves the owning user from the stored user handle during validation. This is the pattern for a login page that doesn't ask for an email first — but it only works for credentials captured with a stable, globally unique user_handle.

Guard and multi-auth scenarios

Set guard in config when the passkey endpoints must authenticate into a non-default guard. Everything downstream (the Authenticated event payload, Auth::guard() resolution, redirect targets) keys off this setting, so set it explicitly rather than relying on the default.

Event-driven side effects

Hook listeners to the package's domain events instead of overriding controllers:

  • AttestationSuccessful / AuthenticationSuccessful — audit log, notify, rate-limit reset
  • AttestationFailed / AuthenticationFailed — throttling, alerting, lockout counters
  • CredentialCreated / CredentialUpdated / CredentialDeleted — invalidate sessions, sync to other services, fire analytics

Register them in EventServiceProvider; they're the cleanest extension point the package offers.

Attestation policy

attestation in config controls whether you request none, self, or basic conveyance. none is right for consumer apps; basic/direct only if you actually verify the attestation chain server-side and gate enrollment on it (e.g. hardware-key-only access for staff).

Gotchas and Tips

  • v3.0.2 schema fix (act on this if you're on 3.0.0/3.0.1). web_authn_credentials.attestation_type was incorrectly declared as json; it should be string. The stored value was being written as a bare attestation constant, so a JSON column either double-encodes or fails validation on read. Write a migration:
    Schema::table('web_authn_credentials', fn (Blueprint $t) =>
        $t->string('attestation_type')->nullable()->change()
    );
    
    If you have existing rows, normalize them (json_decode the quoted value, or null them and re-register) before switching the type. Note ->change() needs doctrine/dbal on older Laravel versions.
  • Origin vs RP ID must agree exactly. relying_party.id must be the registrable domain suffix of the browser origin, and relying_party.origin must be scheme+host+port identical to what the browser sees. A trailing slash, http vs https, or a www. mismatch yields a cryptically generic SecurityError in the browser with no server log.
  • HTTPS is mandatory except on localhost. No exceptions, and emulator/ngrok hostnames count as their own origins — you'll need separate config for each.
  • Session statefulness. The challenge is stashed between the options call and the verification call. If your frontend hits these endpoints from a different session context (SPA on another subdomain, Sanctum + stateful middleware missing), you get "challenge not found" / invalid-type errors. Ensure the session cookie and CSRF token are sent on the POST.
  • user_handle must be immutable and unique. If you point it at email and users can change their email, previously registered passkeys stop resolving. Prefer an opaque, never-changing column.
  • Don't log the payloads. Attestation/assertion responses contain public keys and signatures; useful in a dedicated debug channel, dangerous in general application logs.
  • Config mismatches were the theme of this release. After pulling v3.0.2, diff your published config/larapass.php against the package's current stub (vendor:publish --force into a temp path, compare) — config keys were realigned, so a stale published file may silently fall back to defaults for guard, timeout, or attestation.
  • Timeouts. The default ceremony timeout (60s-ish) is measured by the browser; users fumbling with a security key can miss it. Bump timeout rather than chasing phantom server bugs.
  • Testing. You cannot exercise real WebAuthn ceremonies in CI. Assert on routes, events, and credential persistence using faked option/response objects, and keep one manual browser smoke test in your release checklist.
  • Deleting a credential should cascade to session invalidation if it was the user's only factor — the package won't do this for you; wire it to CredentialDeleted.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings