
Secure per-user field encryption for Filament v4.
This package allows you to encrypt and decrypt sensitive data on a per-user basis, using a split-key approach:
hash('sha256', ...).This ensures that even administrators cannot decrypt data without the user-provided input.
To ensure long-term maintainability and security, this package is continuously analyzed with two systems:
SonarQube Cloud
Monitors code quality, maintainability, and potential security issues. Results are automatically updated on every
commit.
qlty.sh
Provides detailed path coverage via PHPUnit’s --path-coverage, ensuring not only that lines are executed but
also that different execution paths are validated.
For cryptographic code, this level of coverage is especially important: it verifies complete execution flows (e.g.
valid vs. invalid keys, missing secrets, or failed TOTP checks).
Compared to branch coverage, path coverage ensures higher confidence in correctness and security-critical behavior.
Both tools run in CI and guarantee that security and quality checks are part of the development workflow.
This package is currently in alpha and under active development. Features and APIs may change before a stable release.
EncryptedTextInput → encrypts before saveDecryptedTextDisplay → decrypts on displayUnlockLockboxAction → prompts for crypto password or TOTPHasPasskeysHasAppAuthenticationUnlike typical field encryption solutions, Filament Lockbox does not store encrypted data on your models.
Instead, all encrypted values are kept in a dedicated, polymorphic lockbox table — completely transparent to your
application.
Drop-in Usage
Simply use EncryptedTextInput anywhere in your Filament form schema — no schema changes or model attributes
required.
Polymorphic & Universal
Works with any Eloquent model (User, Product, Order, ...).
All sensitive data is centralized, making it easy to see which records have encrypted fields.
Performance-Friendly
Main tables remain lean and fast, as encrypted data is kept out of your core business tables.
Compliance & Auditing
Developer Experience
dehydrated(false) is applied internally.TextInput with EncryptedTextInput and get full encryption.$form->schema([ // Before: TextInput::make('credit_card'), // After: EncryptedTextInput::make('credit_card') ->label('Credit Card'),]);
The plugin takes care of everything:
┌────────────────────────┐ │ encrypted_user_key │ (in DB, encrypted with APP_KEY) └──────────┬─────────────┘ │ decrypt ▼ ┌──────────┐ │ Part A │ (server key) └─────┬────┘ │ │ ┌───────────▼───────────┐ │ Part B (User Input) │ ← crypto password, passkey, or TOTP └───────────┬──────────┘ │ combine ▼ ┌───────────────────┐ │ Final Key (32B) │ └─────────┬─────────┘ │┌─────────────▼─────────────┐│ Encrypt / Decrypt fields │└──────────────────────────┘
This means database leaks alone cannot decrypt your data – PartB must be provided by the user.
Install the package via Composer:
composer require n3xt0r/filament-lockbox
Important:
This package integrates withspatie/laravel-passkeys. Before running the install command, make sure you have published and run the Spatie migrations:
php artisan vendor:publish --provider="Spatie\\LaravelPasskeys\\LaravelPasskeysServiceProvider" --tag="laravel-passkeys-migrations"php artisan migrateRun the install command to publish all required assets and migrations: ```bashphp artisan filament-lockbox:install
Add the plugin to your Filament panel provider:
// app/Providers/Filament/AdminPanelProvider.php use Filament\Panel;use Filament\PanelProvider;use N3XT0R\FilamentLockbox\FilamentLockboxPlugin; class AdminPanelProvider extends PanelProvider{ public function panel(Panel $panel): Panel { return $panel ->plugins([ FilamentLockboxPlugin::make(), ]); }}
Optional configuration:
// config/filament-lockbox.phpreturn [ 'show_widget' => true, // set false to hide the status widget 'providers' => [ \N3XT0R\FilamentLockbox\Managers\KeyMaterial\TotpKeyMaterialProvider::class, \N3XT0R\FilamentLockbox\Managers\KeyMaterial\CryptoPasswordKeyMaterialProvider::class, ],];
You can publish the config and translations if you need customization:
php artisan vendor:publish --tag="filament-lockbox-config"php artisan vendor:publish --tag="filament-lockbox-translations"
Your User model must:
HasLockboxKeysInteractsWithLockboxKeys traituse Filament\Models\Contracts\FilamentUser;use Illuminate\Contracts\Auth\MustVerifyEmail;use Illuminate\Foundation\Auth\User as Authenticatable;use N3XT0R\FilamentLockbox\Contracts\HasLockboxKeys;use N3XT0R\FilamentLockbox\Concerns\InteractsWithLockboxKeys; class User extends Authenticatable implements FilamentUser, MustVerifyEmail, HasLockboxKeys{ use InteractsWithLockboxKeys; protected $hidden = [ 'encrypted_user_key', 'crypto_password_hash', 'lockbox_provider', ]; protected function casts(): array { return [ 'encrypted_user_key' => 'encrypted', 'crypto_password_hash' => 'string', 'lockbox_provider' => 'string', ]; }}
Any Eloquent model that should have encrypted fields must:
HasLockboxInteractsWithLockbox traitThis enables the polymorphic relation to the lockbox table and lets the package handle encryption transparently.
use Illuminate\Database\Eloquent\Model;use N3XT0R\FilamentLockbox\Contracts\HasLockbox;use N3XT0R\FilamentLockbox\Concerns\InteractsWithLockbox; class Company extends Model implements HasLockbox{ use InteractsWithLockbox; protected $fillable = [ 'name', 'email', // no need to list encrypted fields here – they live in the lockbox table ];}
You can now use EncryptedTextInput::make('field_name') in your Filament form schemas for this model —
the package will automatically store and retrieve the data from the centralized lockbox table.
use N3XT0R\FilamentLockbox\Forms\Actions\UnlockLockboxAction;use N3XT0R\FilamentLockbox\Forms\Components\EncryptedTextInput; $form ->schema([ EncryptedTextInput::make('secret_notes') ->label('Secret Notes'), ]) ->extraActions([ UnlockLockboxAction::make(), ]);
use N3XT0R\FilamentLockbox\Forms\Components\DecryptedTextDisplay;use N3XT0R\FilamentLockbox\Forms\Actions\UnlockLockboxAction; $form ->schema([ DecryptedTextDisplay::make('secret_notes') ->label('Secret Notes'), ]) ->extraActions([ UnlockLockboxAction::make(), ]);
APP_KEYThis package ships with built-in support for spatie/laravel-passkeys and requires it by default.
You can control Passkey usage via this package's configuration.
If you don't plan to use WebAuthn/Passkeys, disable the integration in config/filament-lockbox.php.
MIT © N3XT0R
I’m a software engineer with 15+ years of experience in backend development, system architecture, and DevOps. As a certified ISO 27001 Information Security Officer, I combine development expertise with a strong focus on security and compliance. I enjoy contributing to open-source and creating tools that make complex systems more secure and developer-friendly.