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

Nova Password Rotation Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install with 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
    
  • Look first at 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.
  • The fastest first use case: set 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.

Implementation Patterns

  • Policy via config, overrides via the user model. Keep global defaults in the config file, and expose per-user or per-role exceptions through a model method/interface rather than branching inside the package. This keeps rotation rules auditable in one place.
  • Branding is shared with Nova's login screen. The change screen renders 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.
  • Customising the screen. Publish the views if you need to add copy, a password-strength meter, or a "why am I seeing this?" explanation. Keep the existing form action, CSRF token, and field names so the package's controller still handles the update.
  • Audit and notify through events. Listen for the package's password-changed/rotated event to write an audit log entry or send a "your password was changed" notification. This is also the clean hook for SSO users you want to exempt.
  • Testing the flow. Use 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.
  • Exempt non-Nova traffic. The rotation middleware belongs on the Nova stack, not globally. Confirm API, health-check, and webhook routes are not caught by the redirect.

Gotchas and Tips

  • Brand CSS injection order matters. The stylesheet is injected after 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.
  • Guard 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.
  • Config caching. After changing 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".
  • Middleware ordering. Registration must come after Nova's authentication middleware; otherwise unauthenticated users get redirected to the change screen instead of the login screen.
  • Timezone consistency. Compare expiry using the same clock as the stored 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.
  • History table growth. The password-history table grows with every rotation. Add a pruning job or cap the history depth in config; otherwise large tenants accumulate rows indefinitely.
  • Don't fight Nova's middleware in tests. Hitting Nova routes directly in feature tests requires acting as a Nova user and following the package's redirect chain; asserting the final rendered change screen is more stable than asserting intermediate redirects.
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.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route