bbs-lab/nova-password-rotation
Nova Password Rotation lets you enforce configurable password expiry and forced rotation policies in Laravel Nova. Set rotation intervals per user or role, prompt users to change expired passwords, and track last-changed dates to keep accounts secure.
composer require bbs-lab/nova-password-rotation, then publish and run the package assets:
php artisan vendor:publish --tag="nova-password-rotation-config"
php artisan vendor:publish --tag="nova-password-rotation-migrations"
php artisan migrate
config/nova-password-rotation.php. That file is the day-to-day policy surface: expiry window, password history depth, first-login forcing, and the change-screen behaviour.expiry_days (e.g. 90), reload Nova as a test user with an old password_changed_at, and confirm the middleware redirects to the built-in forced-change screen. Once you see the redirect working, tune the policy and branding.Nova::brandColorsCSS() after app.css, so configuring nova.brand.colors is enough to make the submit button match the rest of the panel. Set the brand colour before rolling the package out to users so the forced-change flow doesn't look like a phishing page.Nova::actingAs($user) plus Carbon::setTestNow() to fast-forward past the expiry window, then assert the redirect to the change screen and that a valid submission clears it. Test the exempt path (API routes, service accounts) in the same suite.app.css specifically so the primary button overrides Nova's default blue. If you replace the change-screen layout with your own Blade file, you lose that injection — re-add {!! Nova::brandColorsCSS() !!} in your layout or the button reverts to blue.Nova::brandColorsCSS() by Nova version. It's available on current Nova releases, but if you support an older major, wrap the call with method_exists(Nova::class, 'brandColorsCSS') so the screen doesn't fatal. When no brand colour is configured the method returns an empty string; v2.3.1 falls back cleanly, so don't wrap it in your own <style> tag without checking for emptiness.nova.brand.colors or rotation settings, run php artisan config:cache (or clear it). Stale config is the usual cause of "the policy didn't change" and "the button is still blue".password_changed_at (Laravel's now()), and don't mix app timezone with DB CURRENT_TIMESTAMP. Off-by-a-day reports usually trace back to this.How can I help you explore Laravel packages today?