Installation
composer require defineweb/google-oauth2
Add the bundle to config/bundles.php (Symfony) or register the service provider in config/app.php (Laravel).
Configuration Publish the config file:
php artisan vendor:publish --provider="Defineweb\GoogleOauth2Bundle\GoogleOauth2ServiceProvider"
Update .env with your Google OAuth2 credentials:
GOOGLE_OAUTH2_CLIENT_ID=your_client_id
GOOGLE_OAUTH2_CLIENT_SECRET=your_client_secret
GOOGLE_OAUTH2_REDIRECT_URI=http://your-app.test/login/google/callback
First Use Case: Login Route
Add routes in routes/web.php:
Route::get('/login/google', [GoogleOauth2Controller::class, 'redirectToGoogle'])->name('google.login');
Route::get('/login/google/callback', [GoogleOauth2Controller::class, 'handleGoogleCallback']);
Basic Controller Usage
use Defineweb\GoogleOauth2Bundle\GoogleOauth2;
public function redirectToGoogle(GoogleOauth2 $googleOauth2)
{
return $googleOauth2->redirect();
}
public function handleGoogleCallback(GoogleOauth2 $googleOauth2)
{
$user = $googleOauth2->getUser();
// Handle user data (e.g., create/update user in DB)
auth()->login($user);
return redirect()->intended('/dashboard');
}
Authentication Flow
$googleOauth2->redirect() to initiate OAuth flow.$googleOauth2->getUser() to fetch user data (e.g., email, name, profile pic).User model (e.g., via findOrCreate or custom logic).User Data Access
The getUser() method returns an array like:
[
'id' => '123456789',
'email' => 'user@example.com',
'name' => 'John Doe',
'picture' => 'https://.../photo.jpg',
// Additional Google-provided fields
]
Extend this with custom claims by configuring scopes in .env:
GOOGLE_OAUTH2_SCOPES="email profile https://www.googleapis.com/auth/userinfo.profile"
Integration with Laravel Auth
Auth::login() or auth()->login() to authenticate the user after fetching data.$userData = $googleOauth2->getUser();
$user = User::firstOrCreate(
['email' => $userData['email']],
[
'name' => $userData['name'],
'google_id' => $userData['id'],
'avatar' => $userData['picture']
]
);
auth()->login($user);
Scopes and Permissions
.env (e.g., email, profile, openid).GOOGLE_OAUTH2_SCOPES="https://www.googleapis.com/auth/calendar.readonly"
Error Handling
try {
$user = $googleOauth2->getUser();
} catch (\Exception $e) {
\Log::error('Google OAuth error: ' . $e->getMessage());
return redirect()->route('login')->with('error', 'Google login failed.');
}
Redirect URI Mismatch
GOOGLE_OAUTH2_REDIRECT_URI in .env exactly matches the URI registered in Google Cloud Console.Missing Scopes
getUser() returns incomplete data (e.g., no picture), verify scopes in .env include profile.https://www.googleapis.com/auth/userinfo.profile to GOOGLE_OAUTH2_SCOPES.State Parameter Issues
public function handleGoogleCallback(Request $request, GoogleOauth2 $googleOauth2)
{
if (!hash_equals($request->session()->get('oauth_state'), $request->query('state'))) {
throw new \RuntimeException('State mismatch');
}
// Proceed with login...
}
Token Expiry
User Data Mutability
email_verified) may change over time. Cache this data if relying on it for critical logic.last_sync timestamp in your users table and periodically refresh data.Enable Logging
Add this to config/logging.php to debug OAuth issues:
'channels' => [
'google_oauth' => [
'driver' => 'single',
'path' => storage_path('logs/google_oauth.log'),
'level' => 'debug',
],
],
Then inject the logger into your controller:
public function __construct(\Psr\Log\LoggerInterface $logger) {
$this->logger = $logger;
}
Test Locally with Google’s Test Users Use Google’s test accounts to avoid rate limits during development.
Inspect the OAuth Response Dump the raw response from Google to debug:
$response = $googleOauth2->getGoogleClient()->fetchAccessTokenWithAuthCode($request->query('code'));
dd($response);
Custom User Provider Override the default user mapping by extending the service:
// app/Providers/GoogleOauth2ServiceProvider.php
public function register()
{
$this->app->bind(\Defineweb\GoogleOauth2Bundle\Contracts\UserProvider::class, function () {
return new CustomGoogleUserProvider();
});
}
Add Custom Claims
Extend the getUser() method by modifying the service:
// app/Services/ExtendedGoogleOauth2.php
class ExtendedGoogleOauth2 extends \Defineweb\GoogleOauth2Bundle\GoogleOauth2
{
public function getUser()
{
$user = parent::getUser();
$user['custom_field'] = $this->fetchCustomData();
return $user;
}
}
Multi-Tenant Support Use middleware to scope the Google client per tenant:
// app/Http/Middleware/GoogleOauth2TenantMiddleware.php
public function handle($request, Closure $next)
{
$tenant = Tenant::resolve();
$googleOauth2 = app(GoogleOauth2::class)->setClientId($tenant->google_client_id);
$request->merge(['google_oauth2' => $googleOauth2]);
return $next($request);
}
Offline Access Request offline access to get a refresh token:
GOOGLE_OAUTH2_SCOPES="https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email offline"
Then fetch the refresh token:
$tokenResponse = $googleOauth2->getGoogleClient()->fetchAccessTokenWithAuthCode($request->query('code'));
$refreshToken = $tokenResponse['refresh_token'] ?? null;
How can I help you explore Laravel packages today?