Google OAuth
Google OAuth integration for admin panel authentication using Laravel Socialite.
Overview
Section titled “Overview”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
Quick Start
Section titled “Quick Start”Environment Configuration
Section titled “Environment Configuration”GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.comGOOGLE_CLIENT_SECRET=your-client-secretGOOGLE_REDIRECT_URI=${APP_URL}/auth/google/callback
# Optional: Restrict to specific domainGOOGLE_ALLOWED_DOMAIN=yourcompany.comGoogle Cloud Console Setup
Section titled “Google Cloud Console Setup”- Go to Google Cloud Console
- Create or select a project
- Navigate to APIs & Services → Credentials
- Click Create Credentials → OAuth client ID
- Select Web application
- Add authorized redirect URI:
https://yourdomain.com/auth/google/callback - Copy Client ID and Client Secret to
.env
Routes
Section titled “Routes”| Route | Method | Description |
|---|---|---|
/auth/google | GET | Redirect to Google OAuth |
/auth/google/callback | GET | Handle OAuth callback |
/logout | POST | Logout and destroy session |
Implementation
Section titled “Implementation”Controller
Section titled “Controller”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 Definition
Section titled “Routes Definition”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');User Model
Section titled “User Model”Required Fields
Section titled “Required Fields”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();});Model Configuration
Section titled “Model Configuration”class User extends Authenticatable{ use HasApiTokens, HasFactory, Notifiable, HasRoles;
protected $fillable = [ 'name', 'email', 'google_id', 'avatar', ];
protected $hidden = [ 'remember_token', ];}FilamentPHP Integration
Section titled “FilamentPHP Integration”Custom Login Page
Section titled “Custom Login Page”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'), ]; }}Login View
Section titled “Login View”{{-- 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>Security
Section titled “Security”Domain Restriction
Section titled “Domain Restriction”Restrict access to specific email domains:
'google' => [ 'client_id' => env('GOOGLE_CLIENT_ID'), 'client_secret' => env('GOOGLE_CLIENT_SECRET'), 'redirect' => env('GOOGLE_REDIRECT_URI'), 'allowed_domain' => env('GOOGLE_ALLOWED_DOMAIN'),],Session Security
Section titled “Session Security”'lifetime' => 120, // 2 hours'expire_on_close' => false,'encrypt' => true,'same_site' => 'lax','secure' => env('APP_ENV') === 'production',CSRF Protection
Section titled “CSRF Protection”All POST routes are automatically protected by Laravel’s CSRF middleware.
Testing
Section titled “Testing”Manual Testing
Section titled “Manual Testing”- Visit
/auth/googlein browser - Sign in with Google account
- Verify redirect to admin panel
- Check user record created in database
Feature Test
Section titled “Feature Test”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', ]);});Troubleshooting
Section titled “Troubleshooting”Redirect URI Mismatch
Section titled “Redirect URI Mismatch”Error: redirect_uri_mismatch
Solution:
- Check Google Cloud Console redirect URIs match exactly
- Include protocol (https://) and path (/auth/google/callback)
- No trailing slash
Domain Not Allowed
Section titled “Domain Not Allowed”Error: “Only users from authorized domains can access this application”
Solution:
- Check
GOOGLE_ALLOWED_DOMAINin.env - Verify user’s email domain matches
- Set to empty to allow all domains
Session Issues
Section titled “Session Issues”Symptom: User logged out after redirect
Solutions:
- Ensure
SESSION_DOMAINmatches application domain - Check
SESSION_SECURE_COOKIEfor HTTPS - Verify session driver is configured correctly
Related Documentation
Section titled “Related Documentation”- Roles and Permissions - RBAC after authentication
- FilamentPHP Authentication - Official docs