"Log in with Google" or "Log in with Facebook" both follow the same OAuth 2.0 pattern under the hood — Laravel Socialite is the official first-party package that implements that handshake for several major providers behind one consistent API, so the same basic code structure works whether the provider is Google, Facebook, GitHub, or others.
1. Installation and provider setup
composer require laravel/socialite
// config/services.php
'google' => [
'client_id' => env('GOOGLE_CLIENT_ID'),
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
'redirect' => env('GOOGLE_REDIRECT_URI'),
],
'facebook' => [
'client_id' => env('FACEBOOK_CLIENT_ID'),
'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
'redirect' => env('FACEBOOK_REDIRECT_URI'),
],
The client ID, secret, and redirect URI come from each provider's own developer console (Google Cloud Console, Facebook for Developers) — registering the app there and getting these three values is a prerequisite that happens outside of Laravel entirely, before any of the code below will work.
2. The redirect route
use Laravel\Socialite\Facades\Socialite;
Route::get('/auth/{provider}/redirect', function (string $provider) {
return Socialite::driver($provider)->redirect();
});
This sends the user to the provider's own login/consent screen — Laravel doesn't render any login UI itself for this step; the entire authentication interaction happens on Google's or Facebook's own page.
3. The callback route
Route::get('/auth/{provider}/callback', function (string $provider) {
$socialUser = Socialite::driver($provider)->user();
$user = \App\Models\User::updateOrCreate(
['email' => $socialUser->getEmail()],
[
'name' => $socialUser->getName(),
'google_id' => $provider === 'google' ? $socialUser->getId() : null,
'avatar' => $socialUser->getAvatar(),
]
);
auth()->login($user);
return redirect('/dashboard');
});
After the user approves access on the provider's page, they're redirected back to this callback URL with an authorization code Socialite exchanges for the actual profile data — $socialUser exposes getId(), getName(), getEmail(), and getAvatar() consistently across every supported provider.
4. Matching against an existing account by email
updateOrCreate() keyed on email is the standard pattern — it means a user who originally signed up with a password, and later clicks "Log in with Google" using the same email address, gets logged into their existing account rather than accidentally creating a duplicate one. This assumes the email from the provider is trusted and verified, which is generally true for Google and Facebook.
5. Stateless mode, for an API without sessions
Socialite::driver('google')->stateless()->user();
Socialite normally relies on session state to protect against CSRF during the OAuth flow — a stateless SPA or mobile-API backend that doesn't maintain a traditional session needs ->stateless() on both the redirect and callback calls, or the callback fails with a state-mismatch error.
6. The redirect URI must match exactly
The redirect URI registered in the provider's developer console must match the app's callback URL character-for-character, including the scheme (http vs https) and trailing slash — a mismatch here is the single most common setup error, and produces an error from the provider's own consent screen before the request even reaches Laravel's callback route.