Your Guide to Laravel Excellence

How to Implement Custom Facebook OAuth Login in Laravel  Without Socialite

How to Implement Custom Facebook OAuth Login in Laravel Without Socialite

In this tutorial, we will learn how to implement OAuth login with Facebook from scratch in a Laravel application, without using any third-party packages like Socialite. We’ll directly interact with Facebook’s OAuth API endpoints to create a custom authentication system. The tutorial will walk through every step, starting from setting up a new Laravel project to configuring the Facebook developer application. We will cover how to handle user authentication, manage access tokens, and store user data in the database. By the end, you'll have a fully functioning Facebook login feature integrated into your Laravel app using a custom API approach, providing a flexible alternative to third-party solutions.

Set up a Facebook Oauth

First, we'll need to create a Facebook App in the Facebook Developer Dashboard. This will provide you with the necessary credentials (App ID and App Secret) to authenticate users.

  • Go to the Facebook Developers Account.
  • Create a new app and configure the app
  • Create credentials for a new OAuth app id and app secret. Set the authorized redirect URI to your Laravel API endpoint.

.env Configuration

Now go to .env file configuration.

FACEBOOK_APP_ID=12xxxxxxxxxxx18978
FACEBOOK_APP_SECRET=82faxxxxxxxxxxxxx7737
FACEBOOK_REDIRECT_URI="${APP_URL}/auth/facebook/callback"

Register in Config

Goto your config/services.php

'facebook' => [
    'app_id'     => env('FACEBOOK_APP_ID'),
    'app_secret' => env('FACEBOOK_APP_SECRET'),
    'redirect_uri' => env('FACEBOOK_REDIRECT_URI')
]

Migration Setup

Updating the Migration

Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('facebook_id')->nullable();
    $table->string('picture_url')->nullable();
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->rememberToken();
    $table->timestamps();
});

Updating the User Model Run this command to add tables in database.

protected $fillable = [
    'name',
    'email',
    'facebook_id',
    'picture_url'
  ];

Run this command to add tables in database.

php artisan migrate

Controller Setup

php artisan make:controller FacebookController

We will create multiple functions in a controller which will be our application bussiness logic.

Now goto your FacebookController

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Http;

class FacebookController extends Controller
{

    public function redirectToFacebook()
    {
        $appId = config('services.facebook.app_id');
        $redirectUri = config('services.facebook.redirect_uri');
        $scope = 'public_profile%20email';
        
        // $display=popup
        $url = "https://www.facebook.com/v18.0/dialog/oauth?client_id=$appId&redirect_uri=$redirectUri&scope=$scope";
        return redirect()->away($url);
    }

    public function handleFacebookCallback(Request $request)
    {
        // // Verify the state parameter to prevent CSRF attacks
        // if ($request->input('state') !== session('facebook_state')) {
        //     // Handle CSRF attack
        //     return redirect('/login')->with('error', 'CSRF validation failed');
        // }

        $code = $request->input('code');
        $tokenEndpoint = 'https://graph.facebook.com/v18.0/oauth/access_token';

        $response = Http::post($tokenEndpoint, [
            'client_id' => config('services.facebook.app_id'),
            'client_secret' => config('services.facebook.app_secret'),
            'redirect_uri' => config('services.facebook.redirect_uri'),
            'code' =>  $code,

        ]);

        $accessTokenResponse = $response->json();
        if (isset($accessTokenResponse['access_token'])) {
            $tokenType = $accessTokenResponse["token_type"];
            $accessToken = $accessTokenResponse["access_token"];
            $userData = $this->getUserData($accessToken);
            $user = $this->findOrCreateUser($userData);
            $userRecord = User::where('email', $user['email'])->where('google_id', $user['google_id'])->first();
            if ($userRecord) {
                Auth::login($userRecord);
                return redirect()->route('home');
            } else {
                return redirect()->route('login');
            }
        }
        return response()->json(['error' => 'Failed to obtain access token']);
    }

    private function getUserData($accessToken)
    {
        $response = Http::get(
            'https://graph.facebook.com/v18.0/me',
            [
                'fields' => 'id,name,first_name,last_name,email,picture',
                'access_token' => $accessToken
            ]
        );
        return $response->json();
    }

    private function findOrCreateUser($userData)
    {
        $user = User::where('email', $userData['email'])->first();
        if (!$user) {
            $user = User::create([
                'facebook_id' => $userData['id'],
                'name' => $userData['name'],
                'email' => $userData['email'],
                'picture_url' => $userData['picture']['data']['url'],
            ]);
        }
        return $user;
    }
}

Now run this project , open the terminal and run the commands

Recommeded Posts

Guide to Session Management and Flash Messages in Laravel

Guide to Session Management and Flash Messages in Laravel

Learn how to use Laravel's session management and flash messages. This comprehensive guide covers storing data, handling user states, and displaying temporary notifications in your Laravel applications.

1 month ago Read article →
New in Laravel 12: Eager Loading, Attribute Scopes, and fromJson

New in Laravel 12: Eager Loading, Attribute Scopes, and fromJson

Discover the new features in Laravel 12! Learn about automatic eager loading, easier query scopes with PHP attributes, and the new Collection::fromJson() method

1 month ago Read article →
Better Error Handling with onFailure Callback in Laravel's DB::transaction() (New in Laravel 12.9)

Better Error Handling with onFailure Callback in Laravel's DB::transaction() (New in Laravel 12.9)

Laravel 12.9 now supports onFailureCallback in DB::transaction(), making database error handling easier with automatic rollback and failure notifications.

1 month ago Read article →
Localization - Automatically Generate Translation JSON Files

Localization - Automatically Generate Translation JSON Files

Discover how to automatically generate translation JSON files for localization in Laravel. This guide simplifies managing multiple languages in your application, making localization easier than ever.

1 month ago Read article →