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

Filament Edit Profile Laravel Package

joaopaulolndev/filament-edit-profile

Filament Edit Profile adds a ready-to-use profile page to Filament panels, letting users update their name, email, password, and avatar. It integrates cleanly with Filament, offers customizable forms and translations, and helps you ship account settings faster.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a small, single-purpose package: it gives a Filament panel a ready-made "Edit Profile" page (avatar, name, email, password, optional account deletion, and — as of v1.0.48 — a "log out other browser sessions" action) so you don't hand-roll one. At ~263 stars and a single maintainer, treat it as thin glue you could own, not critical infrastructure — which is fine, because its whole surface area is a trait, a page class, a plugin class, and a migration.

Install and publish

composer require joaopaulolndev/filament-edit-profile

php artisan vendor:publish --tag="filament-edit-profile-config"
php artisan vendor:publish --tag="filament-edit-profile-migrations"
php artisan migrate

php artisan storage:link   # required for avatar uploads

Wire the trait onto your authenticatable model

use Filament\Models\Contracts\FilamentUser;
use Filament\Models\Contracts\HasAvatar;
use Joaopaulolndev\FilamentEditProfile\Concerns\HasProfile;

class User extends Authenticatable implements FilamentUser, HasAvatar
{
    use HasProfile; // provides the avatar URL accessor the panel expects
}

Register the plugin on the panel

use Joaopaulolndev\FilamentEditProfile\FilamentEditProfilePlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->plugin(
            FilamentEditProfilePlugin::make()
                ->setNavigationLabel('Edit Profile')
                ->setNavigationGroup('Settings')
                ->setIcon('heroicon-o-user-circle')
                ->setSort(10)
        );
}

If you want "log out other sessions" (v1.0.48+), do this before you ship

  1. Add \Illuminate\Session\Middleware\AuthenticateSession::class to the panel's middleware stack — without it the button appears to work and logs nobody out.
  2. Enable the section via the config file or the plugin's fluent toggle for your installed version.
  3. Manually test with two browsers while logged in as the same user: after clicking, the other browser should be signed out on its next request, and the current one should stay signed in.

Where to look first, in this order

  1. config/filament-edit-profile.php — the section toggles (avatar/name/email/password/delete-account/logout-other-sessions) are the whole feature set. Read this before writing any code.
  2. vendor/joaopaulolndev/filament-edit-profile/src/FilamentEditProfilePlugin.php — the fluent setters for title, slug, navigation group/label/icon/sort, and per-section visibility. Fluent method names have shifted between package majors, so trust this file over the README.
  3. src/Pages/EditProfile.php — the Livewire page and its form schema; this is what you subclass when you need extra fields, and where the logout-other-sessions action lives.
  4. The HasProfile trait — confirms which column it reads for avatars (avatar_url) and which storage disk it uses.

First use case to ship: stop forcing users to log out to change a password. Register the plugin, add a user-menu link, and you have a working profile screen in an afternoon. The logout-other-sessions button is the natural second ship — it turns the profile page into the place users go when they suspect a shared or stolen laptop.

Implementation Patterns

Navigation: page vs. user menu

Most apps don't want "Edit Profile" as a permanent sidebar item. Hide it from navigation and hang it off the avatar dropdown instead:

use Filament\Navigation\MenuItem;
use Joaopaulolndev\FilamentEditProfile\Pages\EditProfile;

->userMenuItems([
    'profile' => MenuItem::make()
        ->label('My profile')
        ->icon('heroicon-o-user-circle')
        ->url(fn (): string => EditProfile::getUrl()),
])

Pair that with ->shouldRegisterNavigation(false) on the plugin. The page still resolves by URL and keeps its own title/breadcrumbs.

Per-panel configuration

The plugin is registered per panel, so this is the natural place to differentiate surfaces — e.g. a customer-facing panel gets avatar + name + password + logout-other-sessions, while an internal admin panel disables email changes (identity comes from SSO) and disables account deletion:

// admin panel
FilamentEditProfilePlugin::make()
    ->setNavigationLabel('My Account')
    // section toggles per config/plugin API in your installed version

Keep the toggles in the published config as the baseline and only override per panel where it genuinely differs. Two sources of truth for the same toggle is how you get a "why is the password field back?" bug report.

Logging out other browser sessions (v1.0.48+)

This is a port of the Filament 3 implementation and is described as driver-independent, which in practice means it uses Laravel's own session-invalidation mechanism rather than querying a sessions table. Two things follow from that:

  • It is a security action, not a form field. It needs the user's current password (or a confirmation step), so render it outside the main "Save" flow — a separate action button with its own confirmation modal, not a checkbox that gets submitted with the profile form.
  • It logs out sessions, not credentials. Other devices are kicked out on their next request. It does not revoke API tokens, Sanctum tokens, or OAuth grants — pair it with explicit token revocation if your app issues them.

Keep the UX honest: after a successful click, show a notification along the lines of "Other browsers have been signed out. This browser stays signed in." That single sentence heads off most support tickets.

If you only want the behaviour and not the UI, you can call Laravel directly from your own action and skip the package section entirely:

use Illuminate\Support\Facades\Auth;

Auth::logoutOtherDevices($currentPassword);

That's the whole feature. If your panel's profile page is already customised, this is often the cheaper path.

Adding your own fields

The page is a normal Filament page with a form schema, so the practical extension point is subclassing and re-registering your subclass (or publishing/overriding the view if you only need presentation changes):

namespace App\Filament\Pages;

use Filament\Forms\Components\TextInput;
use Joaopaulolndev\FilamentEditProfile\Pages\EditProfile as BaseEditProfile;

class EditProfile extends BaseEditProfile
{
    // override the form schema to append job title, timezone, locale, etc.
}

For anything beyond one or two fields — notification preferences, team membership, API tokens, active-session listings — stop extending and build a dedicated settings page. The value of this package is that it's disposable; don't turn it into a god page. The logout-other-sessions button is a good litmus test: it's a single destructive action, so it fits; a table of individual sessions with per-device revoke does not, and belongs in its own page.

Avatars

Confirm three things and avatar uploads just work: the avatar_url column exists (from the published migration), the disk is publicly readable, and the accessor resolves through Storage::url(). If you serve assets from S3/CloudFront, set the disk's url correctly rather than string-concatenating paths — otherwise you get signed-URL churn or 403s in production while local dev looks perfect.

If you need thumbnails or conversions, don't fight the package: keep the original upload path in avatar_url and generate derivatives in an observer or a saved hook.

First-login onboarding

A common pattern: force users with no name or avatar to the profile page once. Do it with a small middleware on the panel's route group rather than editing the page's mount() — it keeps the redirect logic testable and out of vendor code.

Account deletion, if enabled

Treat this as a destructive admin action, not a profile feature:

  • Guard against deleting the last super admin.
  • Prefer soft deletes plus an anonymization job.
  • If you have HasApiTokens, revoke tokens on delete.
  • Hook deleting/deleted model events for related-record cleanup rather than relying on the page.

If any of that sounds like work you don't want to own, disable the section in config and point users at a support flow.

Testing

The page is a standard Livewire component:

Livewire::actingAs($user)
    ->test(EditProfile::class)
    ->fillForm(['name' => 'New Name'])
    ->call('save')
    ->assertHasNoFormErrors();

$this->assertDatabaseHas('users', ['name' => 'New Name']);

Use Storage::fake() around avatar tests, and add one test asserting a different user's record is never touched — the classic bug in hand-rolled profile pages is trusting a form field for the user ID.

For the logout-other-sessions action, assert behaviour rather than the notification: create a second session (or set a stale password_hash_web in the session), fire the action, and assert the other session is invalidated. Mocking the session store is usually easier than driving two browser-like tests.

Gotchas and Tips

"Log out other sessions" silently does nothing without AuthenticateSession. Laravel invalidates other sessions by regenerating the session's password hash and comparing it in middleware. No middleware, no invalidation — the action returns success and everyone stays logged in. Put \Illuminate\Session\Middleware\AuthenticateSession::class on the panel's middleware and verify manually with two browsers before you tell anyone the feature works.

It's a Filament 3 port. v1.0.48's note says "(Filament 3)" explicitly. If you're on Filament 4, check the plugin class and the changelog before assuming the toggle exists or behaves identically — the feature may lag across majors.

Don't double-implement HasAvatar. If your User already implements Filament\Models\Contracts\HasAvatar with its own getFilamentAvatarUrl(), adding the trait collides. Pick one; if you already have avatar logic, skip the trait and let the package write to your existing column (and adjust the migration accordingly).

The migration assumes a users table with the usual columns. Custom table names, UUID/ULID keys, or an existing avatar column mean editing the published migration before running it. Never run it blind on a database with real users in it.

Filament v4 changes the calculus. Filament v4 ships a first-party profile page, so on a greenfield v4 project you should evaluate whether this package adds anything beyond what ->profile() gives you — and whether the v1.0.48 session feature is even reachable there. Check the package's composer.json constraint against your Filament major before adopting, and don't mix package majors across Filament majors.

Email changes and verification are the sharp edge. If your model implements MustVerifyEmail, decide explicitly whether changing the email resets email_verified_at — the package may or may not do this for you. Also verify the unique-email validation rule ignores the current user's record; a "this email is taken" error on saving your own unchanged email is the most common complaint with profile screens generally.

Passwords: know whether you're hashing once or twice. If your model casts password => 'hashed', assigning the plain value is correct. If it doesn't, the page must hash. Don't add Hash::make() on top of a hashed cast — you'll silently lock users out, and it only shows up on next login. This bites hardest with the logout-other-sessions action, which re-hashes the password internally: if your cast situation is wrong, the "current password" confirmation can fail for a user who typed it correctly.

Logging out other sessions does not log out API clients. Sanctum tokens, personal access tokens, and remember_token cookies are separate concerns. If a user clicked the button because they lost a device, tell them (in UI copy) to also revoke tokens, or wire the revocation into the same action.

Authorization is "any authenticated panel user." That's usually right for a profile page, but if you need to restrict it (e.g. read-only impersonation sessions), override canAccess() in a subclass rather than adding middleware. The logout-other-sessions action deserves the same thought: an impersonating admin clicking it would be a bad day.

Tenancy is user-global, not tenant-scoped. In a ->tenant() panel, this page edits the User, not the user's membership in the current tenant. That's usually what you want, but it surprises people who expect role/tenant settings to live there.

Slug collisions. If you already have a profile-ish page (Breezy, a custom Profile page, or Filament v4's built-in), two pages claiming edit-profile gives confusing 404s or the wrong page winning. Grep your panel provider for existing profile routes.

Avatar URLs break in production far more often than in dev. storage:link missing, APP_URL wrong behind a proxy, or ASSET_URL unset with a CDN — all produce the same "broken image" symptom with no error in the logs. Check Storage::disk(...)->url($path) output first.

Version-pin and read the plugin class. The fluent API (navigation setters, section toggles, title/slug) has changed shape between releases. Pin the version in composer.json, and when upgrading, diff src/FilamentEditProfilePlugin.php and src/Pages/EditProfile.php — that pair is the real changelog. v1.0.48 is a good example: a user-visible feature landed with a one-line release note and no migration or config diff called out.

Sanctum tokens section (if present in your version) requires Laravel\Sanctum\HasApiTokens on the model, and plaintext tokens are shown exactly once. Make sure your UI copy says so — and note the pairing with the new "log out other sessions" action above.

Localization: publish the translation tag if you need to override labels; otherwise you're editing vendor files and losing them on the next composer update. The new session-logout strings are a common first target.

Exit strategy is cheap — keep it that way. The entire integration is a trait, a plugin registration, and one migration. Don't scatter references to EditProfile::getUrl() across your codebase; wrap it in a single helper or route name so swapping to Filament's built-in profile page later is a one-file change. The session-logout action is the one piece you may end up keeping even after you drop the package — it's three lines of Auth::logoutOtherDevices().

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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib