Google OAuth Authentication Implementation for Websites
Google OAuth 2.0 is one of the most common authorization methods. Integrates via standard OAuth2 flow or Google Identity Services (GIS)—the new JS SDK for "Sign in with Google" button.
Registering OAuth Client
- Google Cloud Console → APIs & Services → Credentials
- Create OAuth 2.0 Client ID of type Web application
- Add Authorized redirect URIs:
https://example.com/auth/google/callback - Save Client ID and Client Secret
Laravel Socialite
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'),
],
// routes/web.php
Route::get('/auth/google', [GoogleAuthController::class, 'redirect']);
Route::get('/auth/google/callback', [GoogleAuthController::class, 'callback']);
class GoogleAuthController extends Controller
{
public function redirect(): RedirectResponse
{
return Socialite::driver('google')
->scopes(['openid', 'profile', 'email'])
->redirect();
}
public function callback(): RedirectResponse
{
try {
$googleUser = Socialite::driver('google')->user();
} catch (\Exception $e) {
return redirect('/login')->withErrors(['google' => 'Google authorization error']);
}
$user = User::updateOrCreate(
['google_id' => $googleUser->getId()],
[
'name' => $googleUser->getName(),
'email' => $googleUser->getEmail(),
'email_verified_at' => now(),
'avatar' => $googleUser->getAvatar(),
]
);
Auth::login($user, remember: true);
return redirect()->intended('/dashboard');
}
}
Link with Existing Account
If user is already registered with same email via password—decide how to merge accounts:
public function callback(): RedirectResponse
{
$googleUser = Socialite::driver('google')->user();
// Search by google_id
$user = User::where('google_id', $googleUser->getId())->first();
// If not—search by email (link existing account)
if (!$user) {
$user = User::where('email', $googleUser->getEmail())->first();
if ($user) {
$user->update(['google_id' => $googleUser->getId()]);
} else {
$user = User::create([
'google_id' => $googleUser->getId(),
'name' => $googleUser->getName(),
'email' => $googleUser->getEmail(),
'email_verified_at' => now(),
]);
}
}
Auth::login($user, remember: true);
return redirect()->intended('/dashboard');
}
One Tap / Google Identity Services
New Google Identity Services SDK shows One Tap popup without redirect:
<script src="https://accounts.google.com/gsi/client" async defer></script>
<div id="g_id_onload"
data-client_id="{{ config('services.google.client_id') }}"
data-callback="handleGoogleResponse"
data-auto_prompt="false">
</div>
<div class="g_id_signin" data-type="standard"></div>
function handleGoogleResponse(response) {
// response.credential — is id_token (JWT)
fetch('/auth/google/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken },
body: JSON.stringify({ credential: response.credential }),
}).then(r => r.json()).then(data => {
if (data.redirect) window.location.href = data.redirect;
});
}
// Verify id_token on server
use Google\Client as GoogleClient;
public function handleToken(Request $request): JsonResponse
{
$client = new GoogleClient(['client_id' => config('services.google.client_id')]);
$payload = $client->verifyIdToken($request->credential);
if (!$payload) {
return response()->json(['error' => 'Invalid token'], 401);
}
$user = User::updateOrCreate(
['google_id' => $payload['sub']],
['name' => $payload['name'], 'email' => $payload['email']]
);
Auth::login($user);
return response()->json(['redirect' => '/dashboard']);
}
Timeline
Standard OAuth2 flow via Socialite—1–2 days. With One Tap and account linking—2–3 days.







