Google Oauth Authentication from Scratch in Laravel

Google Oauth Authentication from Scratch in Laravel

Login with Google from Scratch in Laravel 10

In this step-by-step guide, we'll learn how to implement Google authentication in Laravel 10 without relying on any external authentication packages. Instead, we'll use Google's OAuth 2.0 API endpoints directly, making the integration more customizable. This method ensures better control over the Google login process and enhances user experience with a smooth, secure authentication flow.

Table of Contents

  1. Initialize a New Laravel Project
  2. Add Authentication Scaffolding to Your Project
  3. Configure Google OAuth 2.0 Credentials
  4. Set Up Environment Variables for Google Login
  5. Prepare the Database with Migrations
  6. Create a Controller for Google Authentication
  7. Define Routes for Google Authentication
  8. Customize the Login View for Google Sign-In
  9. Run and Test Your Application

Step 1: Initialize a New Laravel Project

First, create a new Laravel project by running the following command:

<?php
composer create-project laravel/laravel google-integration
?>

Once the project is created, set up an authentication scaffold using Laravel's UI Bootstrap package.

Step 2: Install Authentication Scaffolding

Run the following commands to add authentication scaffolding:

<?php
composer require laravel/ui
php artisan ui bootstrap --auth
npm install
?>

This will set up basic authentication views and routes, which you can customize.

Step 3: Configure Google OAuth 2.0 Credentials

Set up a project on Google Developers Console. Add your Authorized Redirect URI, e.g., http://127.0.0.1:8000/auth/google/callback.

Step 4: Configure Environment Variables

In your .env file, add:

GOOGLE_CLIENT_ID=your-client-id
GOOGLE_CLIENT_SECRET=your-client-secret
GOOGLE_REDIRECT_URI=http://127.0.0.1:8000/auth/google/callback
These values will be used for the OAuth 2.0 flow to authenticate users via Google.

Step 5: Database Migration Setup

We need to update the users table to store additional information for Google login, such as the **google_id** and **picture_url**. Modify the create_user_table migration file as follows:
Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('google_id')->nullable(); $table->string('picture_url')->nullable(); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->rememberToken(); $table->timestamps(); });
Now, update the User model to include the new fields in the $fillable array:
protected $fillable = [ 'name', 'email', 'google_id', 'picture_url' ]
Run this command to add tables in db.
php artisan migrate

Step 6: Create the Google Login Controller

Next, create a new controller to handle the Google login logic:
php artisan make: controller GoogleController
In this controller, we’ll implement two main methods: one to redirect to Google's OAuth service, and another to handle the callback.

Redirect to Google for Authentication

public function redirectToGoogle() { $clientId = env('GOOGLE_CLIENT_ID'); $redirectUri = env('GOOGLE_REDIRECT_URI'); $scope = 'email%20profile'; // Requesting email and profile permissions // Redirect to Google's OAuth 2.0 authorization endpoint return redirect("https://accounts.google.com/o/oauth2/auth?client_id=$clientId&redirect_uri=$redirectUri&response_type=code&scope=$scope"); }

Purpose:

This function generates a URL that directs the user to Google's OAuth 2.0 login page.

  • clientId: The GOOGLE_CLIENT_ID from your .env file (your app's identifier in Google's OAuth system).
  • redirectUri: The URL to which Google will redirect the user after authorization, specified by GOOGLE_REDIRECT_URI in the .env file.
  • scope: This specifies what user data you're requesting permission for (email and profile in this case).
  • OAuth Flow: Redirects the user to the Google authorization page where the user can grant your app permission to access their data.

Handle the Callback from Google

public function handleGoogleCallback(Request $request) { $code = $request->query('code'); if (empty($code)) { return response()->json(['error' => 'Authorization code not provided'], 400); } $clientId = env('GOOGLE_CLIENT_ID'); $clientSecret = env('GOOGLE_CLIENT_SECRET'); $redirectUri = env('GOOGLE_REDIRECT_URI'); $response = Http::post('https://accounts.google.com/o/oauth2/token', [ 'code' => $code, 'client_id' => $clientId, 'client_secret' => $clientSecret, 'redirect_uri' => $redirectUri, 'grant_type' => 'authorization_code', ]); $tokens = $response->json(); if (isset($tokens['access_token'])) { $accessToken = $tokens['access_token']; $userData = $this->getUserData($accessToken); $user = $this->findOrCreateUser($userData); $userRecord = User::where('email', $user['email'])->first(); if ($userRecord) { Auth::login($userRecord, true); return redirect('/'); // Redirect the logged-in user } else { return redirect()->route('login'); } } return response()->json(['error' => 'Failed to obtain access token']); } private function getUserData($accessToken) { $response = Http::get('https://www.googleapis.com/oauth2/v3/userinfo', [ 'access_token' => $accessToken, ]); return $response->json(); }

Authorization Code:

When Google redirects back to your app, it includes a code (authorization code) in the URL.

Token Exchange:

The code is exchanged for an access token by making a POST request to Google's OAuth token endpoint:

client_id, client_secret, code, redirect_uri, and grant_type are required to request the token.

Access Token:

If successful, the response contains an access_token which will be used to access the user’s Google profile.

  • Purpose: This function retrieves the authenticated user’s profile data from Google using the access token.
  • Google API: The userinfo endpoint returns the user's profile information (email, name, profile picture, etc.).
  • Access Token: The access token is sent in the request to authenticate the API call.

Find or Create User in Database

private function findOrCreateUser($userData) { $user = User::where('email', $userData['email'])->first(); if (!$user) { $user = User::create([ 'google_id' => $userData['sub'], // Google ID 'name' => $userData['name'], 'email' => $userData['email'], 'picture_url' => $userData['picture'], // Profile picture ]); } return $user; }
**Find Existing User:** Searches the database for a user with the same email as the one provided by Google. **Create New User:** If no user exists with that email, a new user record is created using the data from Google: **Google ID:** The user’s Google ID is saved as google_id. **Name, Email, Profile Picture:** The user’s name, email, and profile picture are stored. ## Summary: **Step 1:** Redirect users to Google for OAuth. **Step 2:** Handle Google's callback by exchanging the code for an access token. **Step 3:** Retrieve user data using the access token. **Step 4:** Check if the user exists in the database. If not, create a new user, and then log them in.

Step 7: Define Routes for Google Authentication

In routes/web.php, define the routes for Google login and the callback:
Auth::routes(); Route::get('/home', [App\Http\Controllers\HomeController::class, 'index']); Route::get('auth/google', [GoogleController::class, 'redirectToGoogle']); Route::get('auth/google/callback', [GoogleController::class, 'handleGoogleCallback']);

Step 8: Customize the Login View for Google Sign-In

Update the resources/views/auth/login.blade.php file to add a "Login with Google" button:
<!-- resources/views/auth/login.blade.php --> @extends('layouts.app') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-8"> <div class="card"> <div class="card-header"><strong>Login</strong></div> <div class="card-body"> <form method="POST" action="{{ route('login') }}"> @csrf <div class="row mb-3"> <label for="email" class="col-md-4 col-form-label text-md-end"><strong>Email Address</strong></label> <div class="col-md-6"> <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus> @error('email') <span class="invalid-feedback" role="alert"> <strong>{{ $message }}</strong> </span> @enderror </div> </div> <div class="row mb-3"> <label for="password" class="col-md-4 col-form-label text-md-end"><strong>Password</strong></label> <div class="col-md-6"> <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password"> @error('password') <span class="invalid-feedback" role="alert"> <strong>{{ $message }}</strong> </span> @enderror </div> </div> <div class="row mb-3"> <div class="col-md-6 offset-md-4"> <div class="form-check"> <input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}> <label class="form-check-label" for="remember"> <strong>Remember Me</strong> </label> </div> </div> </div> <div class="row mb-0"> <div class="col-md-8 offset-md-4"> <a href="{{ url('auth/google') }}" class="btn btn-primary"><strong>Login with Google</strong></a> <button type="submit" class="btn btn-primary"> <strong>Login</strong> </button> @if (Route::has('password.request')) <a class="btn btn-link" href="{{ route('password.request') }}"> <strong>Forgot Your Password?</strong> </a> @endif </div> </div> </form> </div> </div> </div> </div> </div> @endsection

Run and Test Your Application

Finally, run your Laravel application and compile the frontend assets:
php artisan serve npm run dev

Output

![The San Juan Mountains are beautiful!](http://localhost:8000/storage/uploads/images/3qPfZaMQjuvfE9ADO6Ynr5mTWRdBcj5GYMymTd7q.png) ![The San Juan Mountains are beautiful!](http://localhost:8000/storage/uploads/images/F4YZyPC1yKmaD9TlJvt7DPwVwCqNX3KRW0lbNLQa.png)
Tags
Auth Google Auth Login Google Google Login In Laravel Login With Google In Laravel Google Login From Scratch Google Login In Laravel Without Pakage Laravel 10 Laravel Authentication In Laravel How To Login With Google In Laravel Sign In With Google In Laravel Social Login With Laravel Laravel Social Login Google Login