Lockbox
A security addon for Filament v4 that protects sensitive fields with user-bound encryption keys (Split-Key, TOTP, crypto password or Passkeys).
Author:
Ilya Beliaev
Documentation
- 🧪 Code Quality & Coverage
- 🚧 Project Status
- ✨ Features
- 🗄️ Centralized Lockbox Storage
- 🔑 How It Works (Key Derivation)
- 🚀 Installation
- 🔌 Register the Plugin (Filament v4)
- ⚙️ Model Setup
- 🧑💻 User Flow
- 🧩 Usage in Filament Forms
- 🔒 Security Model
- 📖 Roadmap
- 📜 License

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:
- Part A (server-side key) is stored encrypted in the database.
- Part B (user-provided secret) is collected at runtime (crypto password, passkey, or TOTP).
- Final key is derived from PartA + PartB using
hash('sha256', ...).
This ensures that even administrators cannot decrypt data without the user-provided input.
#🧪 Code Quality & Coverage
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.
#🚧 Project Status
This package is currently in alpha and under active development. Features and APIs may change before a stable release.
#✨ Features
- 🔑 Per-user encryption keys (split key: server + user)
- 🧩 Plug-and-play Filament components:
EncryptedTextInput→ encrypts before saveDecryptedTextDisplay→ decrypts on displayUnlockLockboxAction→ prompts for crypto password or TOTP
- 🔒 User-configurable crypto password support
- 🗝️ Passkey (WebAuthn) support if your user implements
HasPasskeys - 🔐 TOTP support if your user implements
HasAppAuthentication - 🛡️ Zero-knowledge for admins – data is unreadable without user input
- ⚙️ Configurable key material providers (PBKDF2, Passkeys, TOTP, custom)
#🗄️ Centralized Lockbox Storage
Unlike 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.
#✅ Benefits of This Architecture
-
Drop-in Usage
Simply useEncryptedTextInputanywhere 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
- Simplified GDPR / “Right to be Forgotten”: just delete Lockbox entries per user.
- Perfect for audits: one table gives full visibility of all encrypted fields.
- Allows separate backup and retention strategies.
-
Developer Experience
- No manual hooks or closures needed — saving & loading is handled automatically.
dehydrated(false)is applied internally.- Just replace
TextInputwithEncryptedTextInputand get full encryption.
$form->schema([
// Before:
TextInput::make('credit_card'),
// After:
EncryptedTextInput::make('credit_card')
->label('Credit Card'),
]);
The plugin takes care of everything:
- 🔑 Per-user key management
- 🔐 Encryption & decryption
- 🗄️ Transparent Lockbox record handling
- 🔄 Auto-loading of values on form display
- 🧹 Automatic cleanup when models are deleted
#🔑 How It Works (Key Derivation)
┌────────────────────────┐
│ 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.
#🚀 Installation
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 migrate
Run the install command to publish all required assets and migrations:
```bash
php artisan filament-lockbox:install
#🔌 Register the Plugin (Filament v4)
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.php
return [
'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"
#⚙️ Model Setup
Your User model must:
- Implement
HasLockboxKeys - Use the
InteractsWithLockboxKeystrait - Hide and cast the lockbox fields
#Example: User Model
use 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',
];
}
}
#Example: Any Model with Encrypted Fields
Any Eloquent model that should have encrypted fields must:
- Implement
HasLockbox - Use the
InteractsWithLockboxtrait
This 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.
#🧑💻 User Flow
- Go to the Lockbox widget in your Filament panel.
- Click Generate Lockbox Key.
- Set a crypto password, register a passkey, or enable TOTP.
- Unlock once per session to access or modify encrypted fields.
#🧩 Usage in Filament Forms
#1️⃣ Storing Encrypted Data
use N3XT0R\FilamentLockbox\Forms\Actions\UnlockLockboxAction;
use N3XT0R\FilamentLockbox\Forms\Components\EncryptedTextInput;
$form
->schema([
EncryptedTextInput::make('secret_notes')
->label('Secret Notes'),
])
->extraActions([
UnlockLockboxAction::make(),
]);
#2️⃣ Displaying Decrypted Data
use N3XT0R\FilamentLockbox\Forms\Components\DecryptedTextDisplay;
use N3XT0R\FilamentLockbox\Forms\Actions\UnlockLockboxAction;
$form
->schema([
DecryptedTextDisplay::make('secret_notes')
->label('Secret Notes'),
])
->extraActions([
UnlockLockboxAction::make(),
]);
#🔒 Security Model
- Split-key encryption (PartA + PartB → Final Key)
- PBKDF2 key derivation with 100,000 iterations
- Server keys stored encrypted with
APP_KEY - Extensible providers for alternative key material
#🔑 Passkeys (WebAuthn)
This 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.
#📖 Roadmap
- Textarea and file encryption support
- Automatic modal prompt if unlock is missing
- Session-based unlock expiry
- Configurable PBKDF2 parameters
- Improve TOTP integration: ensure user-assigned secrets (crypto password) are required and TOTP is used only as a second factor
#📜 License
MIT © N3XT0R
The author
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.
From the same author
Featured Plugins
A selection of plugins curated by the Filament team
Custom Dashboards
Let your users build and share their own dashboards with a drag-and-drop interface. Define your data sources in PHP and let them do the rest.
Filament
Data Lens
Advanced Data Visualization for Laravel Filament - a premium reporting solution enabling custom column creation, sophisticated filtering, and enterprise-grade data insights within admin panels.
Padmission
Advanced Tables (formerly Filter Sets)
Supercharge your tables with powerful features like user-customizable views, quick filters, multi-column sorting, advanced table searching, convenient view management, and more. Compatible with Resource Panel Tables, Relation Managers, Table Widgets, and Table Builder!
Kenneth Sese