OAuth authentication has become a standard for web applications, allowing users to log in using their existing accounts from services like Google. Laravel Socialite makes this process straightforward, but what if you want to go beyond simple authentication and access Google's APIs like Calendar? This article will guide you through setting up Laravel Socialite with Google OAuth and connecting it to the Google Client PHP Library.
Setting Up Laravel Socialite
First, create a new Laravel project and install Socialite:
composer create-project laravel/laravel googlecomposer require laravel/socialite
Add Google OAuth credentials to your config/services.php
file:
'google' => [ 'client_id' => env('GOOGLE_CLIENT_ID'), 'client_secret' => env('GOOGLE_CLIENT_SECRET'), 'redirect' => 'http://localhost:8000/auth/callback',],
Creating Google OAuth Credentials
Because it has a lot of steps, this part is always a bit tricky.
- Go to the Google Cloud Console
- Navigate to "APIs & Services > Credentials"
- Set up your OAuth consent screen if you haven't already
- Click "Create Credentials" and select "OAuth client ID"
- Choose "Web Application" as your application type and give it a name
- Add an authorized redirect URI (e.g.,
http://localhost:8000/auth/callback
orhttp://yoursite.test/auth/callback
if using Laravel Herd) - After creation, you'll receive your Client ID and Client Secret. You'll add these to your .env file as GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET. You'll also need the credentials file downloaded as JSON. Click "Download JSON" to get this file.
- Rename this new JSON file as oauth-credentials.json and place it at
storage/app/private/google/oauth-credentials.json
Basic Socialite Implementation
Set up routes in your routes/web.php
file for OAuth redirection and callback. I've made changes to the typical setup to store tokens as files and included a route we'll use to handle refresh tokens:
Route::get('/auth/redirect', function (){ return Socialite::driver('google') ->scopes(['https://www.googleapis.com/auth/calendar']) ->with([ 'prompt' => 'consent', ]) ->redirect();}); Route::get('/auth/refresh', function (){ $refreshToken = Storage::disk('local')->get('google/oauth-refresh-token.json'); $newTokens = Socialite::driver('google')->refreshToken($refreshToken); if($newTokens->token) { Storage::disk('local')->put('google/oauth-token.json', $newTokens->token); } if($newTokens->refreshToken) { Storage::disk('local')->put('google/oauth-refresh-token.json', $newTokens->refreshToken); } return redirect('/gmail');}); Route::get('/auth/callback', function (){ $googleUser = Socialite::driver('google')->user(); Storage::disk('local')->put('google/oauth-token.json', $googleUser->token); if($googleUser->refreshToken) { Storage::disk('local')->put('google/oauth-refresh-token.json', $googleUser->refreshToken); } $expiresIn = $googleUser->expiresIn; Auth::login($user); return redirect('/dashboard');});
Authorization
Visit http://localhost:8000/auth/redirect
to login. You should now see a Google sign-in screen.
Expanding OAuth Scope for Google Calendar Access
Let's say you want to expand the usefulness of this OAuth token exchange. It has been great for getting users logged into your web application, but now you want to have users see events from their Google Calendar. We can change the scope of our OAuth access so fetching Google Calendar events will work. To do this, we'll need a different library.
To access Google Calendar data, we need to enable the Google Calendar API.
-
Enable the Google Calendar API in Google Cloud Console:
- Go to "APIs & Services > Library"
- Search for and enable the Google Calendar API
-
Modify your redirect route to include the Calendar scope:
Route::get('/auth/redirect', function () { return Socialite::driver('google') ->scopes(['https://www.googleapis.com/auth/calendar']) ->redirect();});
Note: You can see a list of different scopes to Google products at https://developers.google.com/identity/protocols/oauth2/scopes
When you visit /auth/redirect
, you'll now be prompted to grant access to your Google Calendar.
Note: If you encounter a 403 error, add yourself as a test user under "Google Auth Platform > Audience > Test Users" in the Google Cloud Console.
Connecting to the Google Client PHP Library
But now what? How do you get that calendar data? Simply having the OAuth token isn't enough to access Google Calendar data. For this, we need another library.
I'm going to use the Google APIs Client Library for PHP.
composer require google/apiclient
Create a new route to access the Google Calendar API. Obviously a route might not be the best place for this, but it'll work.
use Google\Client; Route::get('/calendar', function (){ $client = new Client(); // Pluck the same tokens used for Socialite $oathCredentialsPath = Storage::disk('local')->path('google/oauth-credentials.json'); $refreshToken = Storage::disk('local')->get('google/oauth-refresh-token.json'); $oathToken = Storage::disk('local')->get('google/oauth-token.json'); $client->setAuthConfig($oathCredentialsPath); $client->setAccessToken($oathToken); $client->addScope(\Google\Service\Calendar::CALENDAR_READONLY); $service = new \Google_Service_Calendar($client); $calendar_id = 'youremail@gmail.com'; $opt_params = array( 'maxResults' => 10, 'orderBy' => 'startTime', 'singleEvents' => true, 'timeMin' => date('c'), ); $results = $service->events->listEvents($calendar_id, $opt_params); dd($results); });
Now, using the tokens you already had from Socialite, you should see Google Calendar events back from the API.
Obtaining and Managing Refresh Tokens
For long-term API access, you'll need a refresh token. Eventually your access token will expire. We created a /auth/refresh
route for refreshing a token, but visiting that URL might not work for you the first time. If you don't have a storage/app/private/google/oauth-refresh-token.json
file, it will fail. Your first OAauth request likely didn't return a refresh token.
Force Google to provide one by adding the consent
prompt to your /auth/redirect route
:
Route::get('/auth/redirect', function () { return Socialite::driver('google') ->scopes(['https://www.googleapis.com/auth/calendar']) ->with([ 'prompt' => 'consent', ]) ->redirect();});
An Alternate Way to Handle Token Expiration and Refreshing
You don't have to redirect a user to /auth/refresh
for a refresh token, if you don't want. Here's an example of how to handle token refreshing when connecting to Google's APIs in an exception.
The key to making this work is the refreshToken()
method from Socialite.
try { // Your attempt to connect to Google API } catch (\Exception $e) { // Refresh Google auth token $oldRefreshToken = Storage::disk('local')->get('google/oauth-refresh-token.json'); $newTokens = Socialite::driver('google')->refreshToken($oldRefreshToken); if ($newTokens->token) { Storage::disk('local')->put('google/oauth-token.json', $newTokens->token); } if ($newTokens->refreshToken) { Storage::disk('local')->put('google/oauth-refresh-token.json', $newTokens->refreshToken); } // Try to connect again after refreshing the token}
Conclusion
By combining Laravel Socialite with the Google Client PHP Library, you can create powerful applications that not only authenticate users but also interact with Google services like Calendar. This approach gives you the flexibility to expand your application's capabilities while maintaining a smooth authentication flow for your users. And it might be a little more efficient for you.
Remember to always handle tokens securely and implement proper error handling for API requests to ensure a secure and robust user experience.
I'm a Boise area web developer who's passionate about design, code, and the tools of my craft. Day-to-day I work with PHP, JavaScript, and CSS. I'm currently the director of enrollment marketing technology at Miami University (OH).