To add Login with Google to Laravel 13, install Laravel Socialite, create an OAuth client in the Google Cloud Console, put its client ID and secret in config/services.php and add two routes: one redirects the user to Google, the other receives the callback and logs the user in. This guide covers the full flow, including the settings that most often cause the "redirect_uri_mismatch" error.
Targets: Laravel 13 (PHP 8.3 to 8.5) and laravel/socialite, which includes a built-in google driver.
Step 1: Install Socialite
composer require laravel/socialiteStep 2: Create Google OAuth credentials
- Open the Google Cloud Console and create a project (or pick an existing one).
- Configure the OAuth consent screen: app name, support email and the contact email.
- Create an OAuth client ID of type Web application.
- Under Authorized redirect URIs, add your callback URL, for example
http://localhost:8000/auth/google/callback. - Copy the client ID and client secret.
The redirect URI must match your Laravel config character for character, including the scheme (http or https), the host, the port and the path. While the consent screen is in testing mode, only the test users you add can sign in.
Step 3: Add the credentials
GOOGLE_CLIENT_ID=your-client-id
GOOGLE_CLIENT_SECRET=your-client-secret
GOOGLE_REDIRECT_URI=http://localhost:8000/auth/google/callback'google' => [
'client_id' => env('GOOGLE_CLIENT_ID'),
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
'redirect' => env('GOOGLE_REDIRECT_URI'),
],Add the array to config/services.php. Keep the secret out of version control.
Step 4: Add a google_id column to users
php artisan make:migration add_google_id_to_users_table --table=userspublic function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->string('google_id')->nullable()->unique()->after('email');
$table->string('password')->nullable()->change();
});
}
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('google_id');
});
}Add google_id to the $fillable array of the User model and run php artisan migrate.
Step 5: Write the controller
<?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 GoogleAuthController extends Controller
{
public function redirect(): RedirectResponse
{
return Socialite::driver('google')->redirect();
}
public function callback(): RedirectResponse
{
try {
$googleUser = Socialite::driver('google')->user();
} catch (Throwable $e) {
report($e);
return redirect('/login')->withErrors(['email' => 'Google login failed. Please try again.']);
}
$user = User::where('google_id', $googleUser->getId())
->orWhere('email', $googleUser->getEmail())
->first();
if ($user) {
$user->update(['google_id' => $googleUser->getId()]);
} else {
$user = User::create([
'name' => $googleUser->getName(),
'email' => $googleUser->getEmail(),
'google_id' => $googleUser->getId(),
'email_verified_at' => now(),
'password' => Str::password(32),
]);
}
Auth::login($user, remember: true);
return redirect()->intended('/dashboard');
}
}This version links Google to an existing account with the same email. Google returns a verified email address for its own accounts, which is why linking by email is reasonable here. If your app handles very sensitive data, ask the user to confirm their password before linking.
Step 6: Add the routes and the button
use App\Http\Controllers\GoogleAuthController;
use Illuminate\Support\Facades\Route;
Route::get('/auth/google/redirect', [GoogleAuthController::class, 'redirect'])->name('google.redirect');
Route::get('/auth/google/callback', [GoogleAuthController::class, 'callback']);<a href="{{ route('google.redirect') }}">Continue with Google</a>How do I request extra Google permissions?
Call scopes() before redirect():
return Socialite::driver('google')->scopes(['openid', 'profile', 'email'])->redirect();Sensitive scopes (for example Google Drive or Calendar) may require Google's app verification before the public can use them.
How do I test the login?
- Run
php artisan serveand open the page with the Google link. - Choose a test user's Google account and approve access.
- Confirm you land on
/dashboardand that theuserstable has a row with agoogle_id.
Common mistakes
- redirect_uri_mismatch: the URI in Google Cloud, in
.envand the route must be identical. - Using localhost with a different port: if you start the app on port 8001, update the URI everywhere.
- Cached configuration: after editing
.envorservices.php, runphp artisan config:clear. - Not a test user: while the consent screen is in testing mode only listed test users can log in.
- NOT NULL password column: social users have no password, so make the column nullable or set a random one.
FAQ
Do I need the stateless() method?
Only when your app does not use sessions, such as a pure API or single-page app backend. A normal web app uses the default flow.
Can users still log in with a password?
Yes. Keep your normal login. A linked user can use either method. If they never set a password they can use the password reset flow to create one.
Is the Google driver built in?
Yes. Socialite supports Google out of the box, along with GitHub, GitLab, Bitbucket, Facebook, X, LinkedIn and Slack.



