To add Login with Facebook to Laravel 13, install Laravel Socialite, create an app in Meta for Developers, add its keys to config/services.php and write two routes: one that redirects to Facebook and one that handles the callback. In the callback you find or create a local user and log them in. This guide covers each step, including the points that usually cause errors.
Targets: Laravel 13 (PHP 8.3 to 8.5) and laravel/socialite. Socialite ships a built-in facebook driver.
Step 1: Install Socialite
composer require laravel/socialite Step 2: Create a Facebook app
- Open Meta for Developers and create an app. Choose a use case that includes Facebook Login.
- Add the Facebook Login product to the app.
- Under Facebook Login settings, add your callback URL to Valid OAuth Redirect URIs, for example
http://localhost:8000/auth/facebook/callback. - From the app settings, copy the App ID and App Secret.
Meta changes the dashboard layout from time to time, so use the names above as a guide and follow the labels you see. Keep the app in development mode while testing; only the app's admins and testers can log in until you publish it.
Step 3: Add the credentials
Put the values in .env:
FACEBOOK_CLIENT_ID=your-app-id FACEBOOK_CLIENT_SECRET=your-app-secret FACEBOOK_REDIRECT_URI=http://localhost:8000/auth/facebook/callback Then register them in config/services.php:
'facebook' => [ 'client_id' => env('FACEBOOK_CLIENT_ID'), 'client_secret' => env('FACEBOOK_CLIENT_SECRET'), 'redirect' => env('FACEBOOK_REDIRECT_URI'), ], The redirect value must match the URI you saved in the Meta dashboard exactly, including the scheme, host, port and path.
Step 4: Store the Facebook ID on users
Create a migration that adds a unique facebook_id column and makes the password optional, because social users have no password:
php artisan make:migration add_facebook_id_to_users_table --table=users public function up(): void { Schema::table('users', function (Blueprint $table) { $table->string('facebook_id')->nullable()->unique()->after('email'); $table->string('password')->nullable()->change(); }); } public function down(): void { Schema::table('users', function (Blueprint $table) { $table->dropColumn('facebook_id'); }); } Add facebook_id to the $fillable array on the User model, then run php artisan migrate.
Step 5: Create the controller
php artisan make:controller FacebookAuthController <?php namespace App\Http\Controllers; use App\Models\User; use Illuminate\Http\RedirectResponse; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Str; use Laravel\Socialite\Facades\Socialite; use Throwable; class FacebookAuthController extends Controller { public function redirect(): RedirectResponse { return Socialite::driver('facebook')->redirect(); } public function callback(): RedirectResponse { try { $facebookUser = Socialite::driver('facebook')->user(); } catch (Throwable $e) { report($e); return redirect('/login')->withErrors(['email' => 'Facebook login failed. Please try again.']); } if (! $facebookUser->getEmail()) { return redirect('/login')->withErrors(['email' => 'Facebook did not share an email address.']); } $user = User::updateOrCreate( ['facebook_id' => $facebookUser->getId()], [ 'name' => $facebookUser->getName() ?: 'Facebook user', 'email' => $facebookUser->getEmail(), 'email_verified_at' => now(), 'password' => Str::password(32), ] ); Auth::login($user, remember: true); return redirect()->intended('/dashboard'); } } The callback uses the Facebook ID as the lookup key, handles a failed login, and refuses accounts without an email address. Facebook users can sign up with a phone number only, or deny the email permission, so always check.
One security point: if a user already registered with the same email by password, updateOrCreate on facebook_id would try to create a second user with that email and fail on the unique index. For a real product decide whether to link the accounts after the user confirms ownership.
Step 6: Add the routes
use App\Http\Controllers\FacebookAuthController; use Illuminate\Support\Facades\Route; Route::get('/auth/facebook/redirect', [FacebookAuthController::class, 'redirect'])->name('facebook.redirect'); Route::get('/auth/facebook/callback', [FacebookAuthController::class, 'callback']); Link to it from your login page:
<a href="{{ route('facebook.redirect') }}">Continue with Facebook</a> How do I test the login?
- Start the app with
php artisan serveand open the login page. - Click the Facebook link and approve the permissions with an admin or tester account.
- After the redirect you should land on
/dashboardand see a new row in theuserstable with afacebook_id.
Common mistakes
- Redirect URI mismatch: the URI in
.envand in the Meta dashboard must be identical. - App not live: a normal user who is not a tester cannot log in while the app is in development mode.
- Null email: not every Facebook account returns an email. Handle it.
- Password column not nullable: inserts fail for social users unless you change it or set a random password, as the example does.
- Cached config: after editing
services.phpor.envrunphp artisan config:clear.
FAQ
Does Socialite support Facebook out of the box?
Yes. Facebook is one of the built-in drivers, along with X, LinkedIn, Google, GitHub, GitLab, Bitbucket and Slack.
Do I need the stateless() method?
Only for stateless apps such as pure APIs without sessions. A normal web app can use the default flow.
How do I request more permissions?
Call scopes([...]) before redirect(). Extra permissions may require Meta app review before they work for the public.
References
Originally published on yasiramin.dev.


