Skip to content

Google OAuth

Google OAuth integration for admin panel authentication using Laravel Socialite.

Admin users authenticate via Google OAuth, providing:

  • Single Sign-On (SSO) with Google Workspace
  • Secure authentication without password management
  • Domain restriction for authorized organizations
  • Session-based authentication with CSRF protection
Terminal window
GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=your-client-secret
GOOGLE_REDIRECT_URI=${APP_URL}/auth/google/callback
# Optional: Restrict to specific domain
GOOGLE_ALLOWED_DOMAIN=yourcompany.com
  1. Go to Google Cloud Console
  2. Create or select a project
  3. Navigate to APIs & ServicesCredentials
  4. Click Create CredentialsOAuth client ID
  5. Select Web application
  6. Add authorized redirect URI: https://yourdomain.com/auth/google/callback
  7. Copy Client ID and Client Secret to .env
RouteMethodDescription
/auth/googleGETRedirect to Google OAuth
/auth/google/callbackGETHandle OAuth callback
/logoutPOSTLogout and destroy session
app/Http/Controllers/Auth/GoogleAuthController.php
class GoogleAuthController extends Controller
{
public function redirect(): RedirectResponse
{
return Socialite::driver('google')->redirect();
}
public function callback(): RedirectResponse
{
try {
$googleUser = Socialite::driver('google')->user();
// Domain restriction
$allowedDomain = config('services.google.allowed_domain');
if ($allowedDomain && !str_ends_with($googleUser->getEmail(), "@{$allowedDomain}")) {
return redirect('/login')->withErrors([
'email' => 'Only users from authorized domains can access this application.',
]);
}
// Find or create user
$user = User::updateOrCreate(
['email' => $googleUser->getEmail()],
[
'name' => $googleUser->getName(),
'google_id' => $googleUser->getId(),
'avatar' => $googleUser->getAvatar(),
]
);
Auth::login($user, remember: true);
return redirect()->intended('/admin');
} catch (\Exception $e) {
Log::error('Google OAuth failed', ['error' => $e->getMessage()]);
return redirect('/login')->withErrors([
'email' => 'Authentication failed. Please try again.',
]);
}
}
}
routes/web.php
Route::get('/auth/google', [GoogleAuthController::class, 'redirect'])
->name('auth.google');
Route::get('/auth/google/callback', [GoogleAuthController::class, 'callback'])
->name('auth.google.callback');
Route::post('/logout', function () {
Auth::logout();
request()->session()->invalidate();
request()->session()->regenerateToken();
return redirect('/');
})->name('logout');
database/migrations/create_users_table.php
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->string('google_id')->nullable()->unique();
$table->string('avatar')->nullable();
$table->timestamp('email_verified_at')->nullable();
$table->rememberToken();
$table->timestamps();
});
app/Models/User.php
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable, HasRoles;
protected $fillable = [
'name',
'email',
'google_id',
'avatar',
];
protected $hidden = [
'remember_token',
];
}
app/Filament/Pages/Auth/Login.php
class Login extends BaseLogin
{
public function mount(): void
{
parent::mount();
// Redirect if already authenticated
if (Filament::auth()->check()) {
redirect()->intended(Filament::getUrl());
}
}
protected function getFormSchema(): array
{
return []; // No form fields - OAuth only
}
protected function getViewData(): array
{
return [
'googleAuthUrl' => route('auth.google'),
];
}
}
{{-- resources/views/filament/pages/auth/login.blade.php --}}
<x-filament-panels::page.simple>
<div class="text-center">
<h2 class="text-2xl font-bold mb-4">Sign in to Admin Panel</h2>
<a href="{{ $googleAuthUrl }}"
class="inline-flex items-center px-6 py-3 bg-white border border-gray-300 rounded-lg shadow-sm hover:bg-gray-50 transition">
<svg class="w-5 h-5 mr-3" viewBox="0 0 24 24">
{{-- Google icon SVG --}}
</svg>
<span>Continue with Google</span>
</a>
</div>
</x-filament-panels::page.simple>

Restrict access to specific email domains:

config/services.php
'google' => [
'client_id' => env('GOOGLE_CLIENT_ID'),
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
'redirect' => env('GOOGLE_REDIRECT_URI'),
'allowed_domain' => env('GOOGLE_ALLOWED_DOMAIN'),
],
config/session.php
'lifetime' => 120, // 2 hours
'expire_on_close' => false,
'encrypt' => true,
'same_site' => 'lax',
'secure' => env('APP_ENV') === 'production',

All POST routes are automatically protected by Laravel’s CSRF middleware.

  1. Visit /auth/google in browser
  2. Sign in with Google account
  3. Verify redirect to admin panel
  4. Check user record created in database
use Laravel\Socialite\Facades\Socialite;
use Laravel\Socialite\Two\User as SocialiteUser;
test('google oauth creates user and logs in', function () {
$googleUser = Mockery::mock(SocialiteUser::class);
$googleUser->shouldReceive('getId')->andReturn('123456');
$googleUser->shouldReceive('getName')->andReturn('Test User');
$googleUser->shouldReceive('getEmail')->andReturn('test@company.com');
$googleUser->shouldReceive('getAvatar')->andReturn('https://avatar.url');
Socialite::shouldReceive('driver')
->with('google')
->andReturn(Mockery::mock([
'user' => $googleUser,
]));
$response = $this->get('/auth/google/callback');
$response->assertRedirect('/admin');
$this->assertDatabaseHas('users', [
'email' => 'test@company.com',
'google_id' => '123456',
]);
});

Error: redirect_uri_mismatch

Solution:

  1. Check Google Cloud Console redirect URIs match exactly
  2. Include protocol (https://) and path (/auth/google/callback)
  3. No trailing slash

Error: “Only users from authorized domains can access this application”

Solution:

  1. Check GOOGLE_ALLOWED_DOMAIN in .env
  2. Verify user’s email domain matches
  3. Set to empty to allow all domains

Symptom: User logged out after redirect

Solutions:

  1. Ensure SESSION_DOMAIN matches application domain
  2. Check SESSION_SECURE_COOKIE for HTTPS
  3. Verify session driver is configured correctly