tomatophp/filament-social
Filament Social is a TomatoPHP plugin that brings social authentication to your Filament panels. Add login buttons for providers like Google, Facebook, and GitHub, manage linked accounts, and configure everything with a simple, Laravel-friendly setup.
Match the package major to your Filament major before touching Composer. v5 targets Filament 5 / Livewire 4 / Laravel 12–13 / PHP 8.2+; the Filament 3 line is frozen on the v3 branch. Check composer.lock for filament/filament and livewire/livewire first — mixing lines either fails at install or, worse, breaks the auth page at runtime.
composer require tomatophp/filament-social:"^5.0" # Filament 5
composer require tomatophp/filament-social:"^3.0" # Filament 3
Publish config, migrations, and translations. v5's install command only runs migrations, so don't assume the v4 scaffold covers you. Run php artisan vendor:publish interactively if a tag is missing.
php artisan vendor:publish --tag="filament-social-config"
php artisan vendor:publish --tag="filament-social-migrations"
php artisan vendor:publish --tag="filament-social-translations"
php artisan migrate
Register the plugin on each panel. On Filament 5 the plugin hooks the native auth page classes — do not also call ->login() with your own page or you'll fight it for the route.
use TomatoPHP\FilamentSocial\FilamentSocialPlugin;
public function panel(Panel $panel): Panel
{
return $panel->plugin(FilamentSocialPlugin::make());
}
Wire credentials, then verify the callback URL against real routes. The redirect URI must include the panel path (https://app.test/admin/social/callback/google), not the plain Socialite path. Confirm rather than guess:
php artisan route:list | grep social
Paste the generated URL directly into the provider console.
First use case — social login on the panel login page, tested twice. Enable a provider, add keys to config/services.php / .env, confirm "Login with Google" renders on /admin/login, complete the flow, then sign out and sign in a second time. The returning-user path was a real v5 bug fix, so it's the cheapest smoke test you own.
Where to look first: config/filament-social.php (provider list and flags), the FilamentSocialPlugin class (what it hooks into the Filament 5 auth pages), and the social_auth_users migration — in v5 that table is the home of provider profile data, so the schema tells you exactly what you can read back.
Treat the plugin as panel-scoped, not global. Multi-panel installs (admin / app / tenant) should instantiate the plugin per panel and enable only the providers that make sense there. Don't assume the shared config applies uniformly — decide per panel which providers appear and on which surfaces.
Learn the flow you're customizing before extending it. Auth page renders buttons → redirect route → Socialite → provider → callback → resolve/link/create user → authenticate on the panel's guard. Your legitimate customization points are:
User model (match by email then link provider/provider_id, or create).Prefer config flags and plugin hooks over overriding routes. If no hook exists, publish and extend the controller rather than editing vendor/.
Read provider profile data from its new home. v5 stores the raw provider payload on social_auth_users instead of writing into users.data:
$account = SocialAuthUser::where('user_id', $user->id)
->where('provider', 'google')
->first();
$account->provider_data; // avatar, locale, etc.
Any dashboard widget, import script, or admin column still reading users.data for social fields is stale after the upgrade — fix those as part of the upgrade, not in a follow-up ticket.
Parameterize share actions per record. v5 makes sharing contextual instead of a fixed "share this page":
ShareAction::make()
->shareUrl(fn ($record) => route('posts.show', $record))
->shareTitle(fn ($record) => $record->title);
<x-filament-social::share url="{{ route('posts.show', $post) }}" title="{{ $post->title }}" />
Derive both deterministically from record fields so link previews stay consistent. Because v5 buttons no longer rely on package Tailwind utilities, they inherit your panel theme — delete any CSS shims you were carrying.
Attaching accounts for already-authenticated users. Reuse the redirect route with an explicit "attach" intent (a session flag) so the callback links the provider to the current session user instead of logging someone in. Never link by email alone on this path — that's an account-takeover vector.
Share the linking table if you also use Socialite elsewhere. Same credentials and the same social_auth_users table. Two disjoint linking tables produce the classic "user exists but isn't linked" bug depending on which entry point the user came through.
Test with Socialite fakes, including the second login.
Socialite::fake('google', (new User)->map([
'id' => '123',
'nickname' => 'test',
'name' => 'Test',
'email' => '[email protected]',
]));
Assert the callback creates or links the user, writes a social_auth_users row, and authenticates the correct guard. The upstream repo ships a Pest suite — crib its fakes rather than inventing your own. Write an explicit returning-user test; it's the regression risk introduced by the v5 data-model change.
Keep a staging click-through. Social login can't be validated from localhost without a tunnel (ngrok/Expose). Add a per-environment smoke test: complete OAuth → land authenticated → sign out → repeat.
Wrap it behind a thin adapter. A small internal service or interface around account resolution and share-link building means you can swap in vanilla Socialite in an afternoon if the package stalls. Given single-maintainer risk, that reversibility is cheap insurance.
users.data to social_auth_users, and unique usernames are now enforced. Dedupe existing username rows before upgrading a busy production database, or the migration fails mid-deploy.v3, Filament 5 → v5. Upgrading Filament means upgrading this package and vice versa. Don't mix.APP_URL trailing slashes, https vs http. Log the generated URL during setup and paste it verbatim into the provider console.php artisan route:list | grep social.php artisan config:clear locally, config:cache in production. Stale config surfaces as "provider not configured," which reads like a package bug.lang_path() in v5. Check published lang files before editing vendor PHP — the "Or login with" separator and provider tooltips are both overridable there.email is populated or unique.socialite log channel and the session state parameter first, then the provider's own error body. Most "it just bounces back to login" cases are CSRF/state or wrong credentials, not package logic.php artisan filament:optimize-clear on v5."^5.0", read the changelog before every bump (v5 changed both the data model and the supported stack — not a quiet patch), and keep the callback test green as your tripwire.How can I help you explore Laravel packages today?