Integrating Google Calendar with a Laravel 11 application allows me to manage events, schedule appointments, and sync data seamlessly. In this guide, I’ll walk you through setting up Google Calendar API, configuring authentication, and performing operations on events.
Whether you're building a booking system or a personal planner, this step-by-step tutorial will help you integrate Google Calendar effortlessly into your Laravel project.
How to Integrate Google Calendar in Laravel 11
In this step, we'll create a Google application and get the credentials from the Google console.
Run the following command:
composer require google/apiclient
Add your Google Client ID and Secret:
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
GOOGLE_REDIRECT_URI=http://localhost:8000/auth/google/callback
Now, define the routes to the web.php file.
Route::get('/auth/google', [GoogleAuthController::class, 'redirectToGoogle']);
Route::get('/auth/google/callback', [GoogleAuthController::class, 'handleGoogleCallback']);
Route::get('/calendar', [GoogleAuthController::class, 'getCalendarEvents']);
Next, create a GoogleAuthController and add the following code to that file.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Google_Client;
use Google_Service_Calendar;
class GoogleAuthController extends Controller
{
private function getGoogleClient()
{
$client = new Google_Client();
$client->setClientId(env('GOOGLE_CLIENT_ID'));
$client->setClientSecret(env('GOOGLE_CLIENT_SECRET'));
$client->setRedirectUri(env('GOOGLE_REDIRECT_URI'));
$client->addScope(Google_Service_Calendar::CALENDAR);
$client->setAccessType('offline'); // To get refresh token
return $client;
}
public function redirectToGoogle()
{
$client = $this->getGoogleClient();
return redirect($client->createAuthUrl());
}
public function handleGoogleCallback(Request $request)
{
if (!$request->has('code')) {
return redirect('/')->with('error', 'Authorization failed.');
}
$client = $this->getGoogleClient();
$token = $client->fetchAccessTokenWithAuthCode($request->code);
if (!isset($token['access_token'])) {
return redirect('/')->with('error', 'Failed to retrieve access token.');
}
// Store token in session
session(['google_access_token' => $token]);
return redirect('/calendar');
}
public function getCalendarEvents()
{
$client = $this->getGoogleClient();
$accessToken = session('google_access_token');
if (!$accessToken) {
return redirect('/auth/google')->with('error', 'Please authenticate with Google first.');
}
$client->setAccessToken($accessToken);
// Refresh token if expired
if ($client->isAccessTokenExpired()) {
$refreshToken = $client->getRefreshToken();
if ($refreshToken) {
$newToken = $client->fetchAccessTokenWithRefreshToken($refreshToken);
session(['google_access_token' => array_merge($accessToken, $newToken)]);
} else {
return redirect('/auth/google')->with('error', 'Session expired. Please re-authenticate.');
}
}
try {
$service = new Google_Service_Calendar($client);
$events = $service->events->listEvents('primary');
return view('calendar', ['events' => $events->getItems()]);
} catch (Exception $e) {
return response()->json(['error' => $e->getMessage()], 500);
}
}
}
If your users table does not have columns for Google authentication, create a migration:
php artisan make:migration add_google_auth_to_users_table --table=users
Modify the migration file:
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('google_id')->nullable();
$table->text('google_token')->nullable();
$table->text('google_refresh_token')->nullable();
});
}
Run:
php artisan migrate
Now, we'll display the list of events from the Google Calendar.
resource/views/calendar.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Google Calendar Events</title>
</head>
<body>
<h2>Your Google Calendar Events</h2>
<ul>
@forelse ($events as $event)
<li>
<strong>{{ $event->getSummary() }}</strong> -
{{ $event->start->dateTime ?? $event->start->date }}
</li>
@empty
<li>No events found.</li>
@endforelse
</ul>
</body>
</html>
You might also like: