sergkulich / laravel-key-rotate
A Laravel package to rotate app key and re-encrypt data stored in eloquent models.
Requires
- php: ^8.2
Requires (Dev)
- larastan/larastan: ^2.9
- laravel/pint: ^1.18
- orchestra/testbench: ^9.8
- pestphp/pest: ^3.5
- pestphp/pest-plugin-laravel: ^3.0
- pestphp/pest-plugin-type-coverage: ^3.1
- phpstan/extension-installer: ^1.4
- rector/rector: ^1.2
- symfony/var-dumper: ^7.1
README
Laravel Key Rotate package allows automatically copy current APP_KEY
and update APP_PREVIOUS_KEYS
with it,
After that it will call key:generate
artisan command to generate new APP_KEY
, and, optionally, update all your
Eloquent Models encrypted fields.
The Command available only then app()->runningInConsole()
as it may take a while to update Models.
Warning
The package is in beta. Use with caution.
Never run in production without previous local testing and fresh .env
copy and DB
dump.
Table of contents
Installation
Install the package via composer:
composer require sergkulich/laravel-key-rotate
Usage
Run artisan command to rotate the key.
php artisan key:rotate
Use --force
option to run the command in production to avoid confirmation prompt.
php artisan key:rotate --force
Dive deeper
Quick example of extended usage.
You need to register KeyRotate::useListener()
only if you want your model encrypted fields to be re-encrypted.
namespace App\Providers; class AppServiceProvider extends ServiceProvider { public function boot(): void { if (app()->runningInConsole()) { // Subscribe The Listener to The Event KeyRotate::withListener() // Discover Models that are not in App\ namespace ->withDir(base_path('src/Domain'), 'Domain\\') // Exclude Models ->withoutModel(User::class) // Exclude Model Fields ->withoutModelFileds(Secret::class, ['secret']) // Without Cast ->withoutCast('encrypted:array') // With Custom Cast ->withCast(CustomCast::class); } } }
The Event
The key:rotate
command fires an event after successful completion.
The Event Class
The package provides helper to get the event class name to subscribe listeners to it.
$keyRotateEventClass = KeyRotate::getEventClass(); Event::listen($keyRotateEventClass, MyKeyRotateListener::class);
The Listener
The package provides default listener that update encrypted models fields after key rotation.
The Listener Class
The package provides helper to get the listener class name in case you need it.
KeyRotate::getListenerClass();
Get Instance of the Listener
Simply subscribe the listener to the event in your app service provider boot method.
namespace App\Providers; class AppServiceProvider extends ServiceProvider { public function boot(): void { if (app()->runningInConsole()) { KeyRotate::withListener(); } } }
Or get singleton instance of the listener and call it anywhere in your code.
// Get Instance $listener = KeyRotate::getListener(); // Call it either $listener(); // or $listener->handle();
Models
The package discovers all Models in your app()->path()
folder with app()->getNamespace()
namespace.
But only then app()->runningInConsole()
, so no unnecessary file scans happen during http requests.
Discover Models
It's possible to discover Models with defined namespace that are not located in your app()->path()
but in a custom
directory.
$listener->withDir(base_path('src/Domain'), 'NameSpace\\Domain\\');
Include Models
It's possible to include Model to be updated with the listener without scanning directories.
$listener->withModel(CustomModel::class);
Exclude Models
It's possible to exclude Model from being updated with the listener.
$listener->withoutModel(User::class);
Exclude Model Fields
It's possible to exclude some Model fields from being updated with the listener.
$listener->withoutModelFields(User::class, ['encrypted_text', 'encrypted_array']);
Casts
By default, the listener takes care of Laravel's predefined encrypted
Casts.
[ 'encrypted', 'encrypted:array', 'encrypted:collection', 'encrypted:object', AsEncryptedArrayObject::class, AsEncryptedCollection::class, ];
At your disposal there are helpers to reduce the above list or extend it with your custom cast that implements
Castable
, CastsAttributes
, or CastsInboundAttributes
interfaces.
// Exclude cast $listener->withoutCast('encrypted:array'); // Include cast $listener->withCast(CustomCast::class);
Tests
Run the entire test suite:
composer test
Changelog
Please see CHANGELOG for more information.
Contributing
Please see CONTRIBUTING for more information.
License
The MIT License (MIT). Please see LICENSE for more information.