Login to Your Laravel App With Facebook Using Socialite

Enhancing user experience and security by integrating Facebook login into your Laravel application is a game-changer. In this step-by-step guide, we’ll show you how to seamlessly add ‘Login With Facebook’ functionality to your Laravel application using the powerful Laravel Socialite Package.

We’ll be using Laravel Jetstream’s built-in authentication scaffolding to kickstart the process, allowing you to set up a functional login form quickly. But don’t worry if you’re not using Jetstream – these steps can be easily adapted for any Laravel application.

Step 1: Install Laravel

If you haven’t already, create a new Laravel project using Composer:

composer create-project --prefer-dist laravel/laravel facebook-login-app

Then, navigate to your project directory:

cd facebook-login-app

Step 2: Install Jetstream

First, let’s install Laravel Jetstream so that we can use its scaffolding to generate a starting point for adding the Facebook login feature.

To install Jetstream, run the following artisan command:

composer require laravel/jetstream

Publish Jetstream’s assets and run its installation by running the command:

php artisan jetstream:install livewire

Follow the prompts to set up Jetstream according to your preferences.

Step 3: Install Socialite

Next, we’ll install Laravel Socialite using Composer, and migrate the database tables needed by Socialite by running the following commands:

composer require laravel/socialite
php artisan migrate

Step 4: Starting the Local Application

Note that we won’t be running php artisan serve this time to launch our local site, as it uses http://localhost:8000 and the Facebook/Meta Developer Portal requires us to create apps and their callback URLs on an HTTPS-secured domain.

To launch a local Laravel site and enable HTTPS access, you have two alternatives:

Option 1: Use a Tool which launches your local app on a domain with HTTPS

Instead of relying on artisan serve, consider using Laravel tools like Laravel Herd, Laravel Sail, or Laravel Valet. These tools offer commands to enable HTTPS for your site. Here’s how to do it with each of them:

For Laravel Herd:

herd secure your-app-name

For Laravel Sail:

sail share

Or, if you prefer Laravel Valet (which is what I use):

valet secure your-app-name

Note: There are other tools that support HTTPS for local sites as well but I will only cover the 3 mentioned above.

Option 2: Use a Tunneling Service (like ngrok)

This option involves using a tunneling service called ngrok. You can download ngrok from its official website: https://ngrok.com/. With ngrok, you can create a secure tunnel to your local site, which provides you with an HTTPS URL that Facebook will accept as the redirect and callback URI.

Here’s how to set it up:

  1. Launch your Laravel application using the following command:
php artisan serve
  1. Next, open a terminal or command prompt with administrative privileges and run this command to create a tunnel using ngrok:
ngrok http 8000

Ngrok will generate an HTTPS URL that securely opens your local Laravel app, as shown in the image below:

Screenshot Showing ngrok Tunnel Which Forwards Our localhost Site to a HTTPS URI
  1. You will receive an HTTPS domain, typically something like https://xxxx-xx-xx-xxx-xxx.ngrok-free.app. Make sure to save this URL for later use, but keep the command prompt running.
  2. Now vite won’t use HTTPS yet and your browser will not load the proper JS and CSS on the Jetstream login page and dashboard.
    To fix this edit app/Http/Middleware/TrustProxies.php in the following way:
app/Http/Middleware/TrustProxies.php
<?php
namespace App\Http\Middleware;

use Illuminate\Http\Middleware\TrustProxies as Middleware;
use Illuminate\Http\Request;

class TrustProxies extends Middleware
{
    protected $proxies = '*'; // changed from default ''
    // keep the rest unchanged ...
}

Tip: Test the URL in your web browser to ensure that your login form at https://xxxx-xx-xx-xxx-xxx.ngrok-free.app/login looks the same way as it does on http://localhost:8000/login. If everything appears as expected, you can proceed to the next step.

Step 5: Create Facebook App Credentials

To add a Facebook login to your Laravel site, you’ll need to create an OAuth application in the Facebook for Developers portal. Follow these steps:

  1. Create a Facebook App:
  2. Create an App:
    • Click on “Create App” and follow the prompts to create a new Facebook App.
Create an App in the Facebook/Meta Admin
  1. Configure OAuth Settings:
Filling in the Details of the App
Setting the App to “Allow people to log in…”
  1. In the Facebook App dashboard, navigate to “Settings” and then “Basic”.

Copy both the App ID and secret for later use. Also, enter your app domain (the URL generated by ngrok or any other HTTPS-based URI your app supports)

Meta for Developers Showing Form for App Settings

Copy both the App ID and secret for later use. Also, enter your app domain (the URL generated by ngrok or any other HTTPS-based URI your app supports)

  1. Scroll down to the “Site URL” field and enter your domain once again
Adding the Site URL to the Facebook/Meta Admin
  1. Now go to Products. And click Configure
Configuring the “Product” Facebook Login in the Facebook/Meta Admin
  1. Add your Redirect URI, which should look like https://xxxx-xx-xx-xxx-xxx.ngrok-free.app/auth/facebook/callback
Setting the OAuth Redirect URI in the Facebook/Meta Admin
  1. Save the form

Step 6: Add Facebook App Credentials to the Config

In your Laravel application, open the config/services.php file. Add the Facebook OAuth credentials you obtained in the previous step:

PHP
<?php

return [

    // Other Services ..
    
    'facebook' => [
        'client_id' => env('FACEBOOK_CLIENT_ID'),
        'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
        'redirect' => env('FACEBOOK_REDIRECT_URI'),
    ],
];

Make sure to set these values in your .env file:

.env
FACEBOOK_CLIENT_ID=YOUR_CLIENT_ID
FACEBOOK_CLIENT_SECRET=YOUR_CLIENT_SECRET
FACEBOOK_REDIRECT_URI=https://xxxx-xx-xx-xxx-xxx.ngrok-free.app/auth/facebook/callback

Note:

  • In case you’ve used your own domain instead of ngrok, you can set FACEBOOK_REDIRECT_URI to your own domain instead, for example https://your-domain.test/auth/facebook/callback.
  • In any case, make sure the URI is equal to the one you’ve used in the Facebook/meta admin

Step 7: Add Database Column to Store facebook_id

Add a column facebook_id to your users table by running:

php artisan make:migration add_facebook_id_to_users

In the generated migration file, modify the up and down methods as follows:

database/migrations/2023_10_01_164153_add_facebook_id_to_users.php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('facebook_id')->after('remember_token')->nullable()->unique();
        });
    }

    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('facebook_id');
        });
    }
};

Now run the migration to add the column we’ve defined:

php artisan migrate

Step 8: Modify the User Model

In your User model (typically located at app/Models/User.php), make the facebook_id column fillable for mass assignment by adding it to the $fillable array.

app/Models/User.php
<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Jetstream\HasProfilePhoto;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens;
    use HasFactory;
    use HasProfilePhoto;
    use Notifiable;
    use TwoFactorAuthenticatable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
        'facebook_id', // Add 'facebook_id' to the fillable array.
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
        'two_factor_recovery_codes',
        'two_factor_secret',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    /**
     * The accessors to append to the model's array form.
     *
     * @var array<int, string>
     */
    protected $appends = [
        'profile_photo_url',
    ];
}

Step 9: Create FacebookLoginController

Generate the controller using Laravel Artisan:

php artisan make:controller FacebookLoginController

In FacebookLoginController.php, add the methods redirectToFacebook and handleFacebookCallback which will handle Facebook login and callback.

app/Http/Controllers/FacebookLoginController.php
<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Str;
use Laravel\Socialite\Facades\Socialite;

class FacebookLoginController extends Controller
{
    /**
     * @return RedirectResponse
     */
    public function redirectToFacebook(): RedirectResponse
    {
        return Socialite::driver('facebook')->redirect();
    }

    /**
     * @return RedirectResponse
     */
    public function handleFacebookCallback(): RedirectResponse
    {
        $user = Socialite::driver('facebook')->user();

        $existingUser = User::where('facebook_id', $user->id)->first();

        if ($existingUser) {
            // Log in the existing user.
            auth()->login($existingUser, true);
        } else {
            // Create a new user.
            $newUser = new User();
            $newUser->name = $user->name;
            $newUser->email = $user->email;
            $newUser->facebook_id = $user->id;
            $newUser->password = bcrypt(request(Str::random())); // Set some random password
            $newUser->save();

            // Log in the new user.
            auth()->login($newUser, true);
        }

        // Redirect to url as requested by user, if empty use /dashboard page as generated by Jetstream
        return redirect()->intended('/dashboard');
    }
}

Step 10: Add Routes

Add Facebook login and callback URLs to your routes/web.php file as show below:

routes/web.php
<?php

use App\Http\Controllers\FacebookLoginController;
use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/

Route::middleware([
    'auth:sanctum',
    config('jetstream.auth_session'),
    'verified'
])->group(function () {
    Route::get('/dashboard', function () {
        return view('dashboard');
    })->name('dashboard');
});


// FacebookLoginController redirect and callback urls
Route::get('/auth/facebook', [FacebookLoginController::class, 'redirectToFacebook'])->name('auth.facebook');
Route::get('/auth/facebook/callback', [FacebookLoginController::class, 'handleFacebookCallback']);

Step 11: Update Login Blade File

Edit the resources/views/auth/login.blade.php and add the following code to show a button for signing in with Facebook, right below the existing form submit button.

resources/views/auth/login.blade.php
{{-- Begin custom changes in login.blade.php --}}
<div class="flex mt-4 justify-between">
    <a href="{{ route('auth.facebook') }}" style="background-color: #183153" class="inline-flex items-center px-2 float-left py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 focus:bg-gray-700 active:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition ease-in-out duration-150 h-10 px-2 py-2 mt-2 font-semibold text-xs text-white float-left transition-colors duration-150 rounded-lg uppercase focus:shadow-outline0 bg-gray-800 hover:bg-gray-700 focus:bg-gray-700 active:bg-gray-900">
        <img src="https://www.cdnlogo.com/logos/f/9/facebook.svg" class="w-8 m-0 p-0">
        Login with Facebook
    </a>
    <x-button class="h-10 px-2 py-2 m-2 ml-6 font-semibold text-xs text-white float-right transition-colors duration-150 rounded-lg uppercase focus:shadow-outline0 bg-gray-800 hover:bg-gray-700 focus:bg-gray-700 active:bg-gray-900">
        {{ __('Log in') }}
    </x-button>
</div>

<div class="block mt-4 text-right">
    @if (Route::has('password.request'))
        <a class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" href="{{ route('password.request') }}">
            {{ __('Forgot your password?') }}
        </a>
    @endif
</div>
{{-- End custom changes in login.blade.php --}}

Step 12: Testing Logging in With Facebook

  1. Go to https://xxxx-xx-xx-xxx-xxx.ngrok-free.app/login (or your custom domain if it supports HTTPS) to access the login form.
    Note: Replace the dummy ngrok URL above with the one shown in your terminal from Step 4.
  2. On the login page, you’ll notice the newly added “Login with Facebook” button.
  3. Click on “Login with Facebook,” and you will be directed to Facebook’s permission window
  4. Here, you can log into your Facebook account or choose “Continue as ..” if you already have an active Facebook session.
  5. After you’ve authorized the application, your FacebookLoginController will receive a callback with your user data.
  6. The controller will then execute your custom login logic, which includes creating a user profile and saving the Facebook ID.
  7. Finally, you’ll be automatically redirected to the intended dashboard.

To guide you through the testing I’ve included screenshots of the entire process below:

The Login Form Showing the Added Login With Facebook Button
Facebook Authorize Application Window
Laravel Jetstream Default Dashboard Showing the Logged in User

Conclusion

Congratulations! By following this step-by-step guide, you’ve successfully added a login with Facebook feature to your Laravel application.

This way your your users can choose between a native Laravel account or conveniently using their Facebook credentials to login. Go ahead and add it to your own application. Happy coding!

References

This entry is part 2 of 4 in the series Authenticating With Laravel Socialite

  1. Adding Login With Google to Your Laravel App Using Socialite
  2. Login to Your Laravel App With Facebook Using Socialite
  3. Login to Your Laravel App With Twitter / X Using Socialite
  4. Login to Your Laravel App With GitHub Using Socialite

Johan van den Broek

Johan is the creator of laracoding.com. As a child, he began tinkering with various programming languages, many of which have been long forgotten today. Currently, he works exclusively with PHP and Laravel, and his passion for programming remains to this day.

Leave a Reply

Your email address will not be published. Required fields are marked *

Recent Posts