This is a tutorial of integrating Laravel Socialite plugin using Facebook.
I will be using Laravel 5.4. I assume you have experience with Laravel. With make:auth
we will create basic scaffold for login and registration views and routes.
I hope you have created default basic Login/Logout functionality in Laravel 5.4 (very easy to create)
When your projects will execute then it will looks like: http://nimb.ws/MtLxyB
now let’s start:
Installing Socialite
Socialite is a package that makes building authentification with popular social networks simple.
Install it with composer:
composer require laravel/socialite
… and by following the instructions from github page add provider to the config/app.php
file
'providers' => [
Laravel\Socialite\SocialiteServiceProvider::class,
],
and alias
'Socialite' => Laravel\Socialite\Facades\Socialite::class,
now our app is ready for accepting users from other services.
Facebook Login
Let’s start with facebook since it is most common requirement. You need to have developers account on facebook to be able to create apps. I don’t remember when and how I did register that but a little googling can help.
Open Facebook page for developers
See here: http://nimb.ws/AYO0Q8
Hover over My Apps and click on Add a New App and select Website.
See here: http://nimb.ws/EhWcUF
Enter the app name. On the next step select the category and click Create App ID
After creating the app you will see all details of your app on /dashboard/.
When you get to the next step, select Skip Quick Start because it is showing instructions of how to login users with JavaScript SDK. With Socialite we are not using that.
On the app dashboard you will see all important data that we need for configuring Laravel Socialite. In the config/services.php
add credentials for facebook:
Value from field App ID put in client_id
, from App Secret to client_secret
and redirect
we will leave empty for now. Configuration will look like this.
'facebook' => [
'client_id' => '690344774435367',
'client_secret' => 'ebc50d3fd1d2f7286e02d247e5751ef4',
'redirect' => '',
],
Next, we need following methods in our app that will
- redirect our users to the facebook.
- handle callback from facebook
For that we need controller.
php artisan make:controller SocialAuthController
Add two methods redirect()
and callback()
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Socialite;
class SocialAuthController extends Controller
{
public function redirect()
{
return Socialite::driver('facebook')->redirect();
}
public function callback()
{
}
}
Now register those methods in routes.php
file in the group that has web
middleware (we need session).
Update: It looks like web
middleware is applied by default since 5.2.31 version of Laravel. So do not create a group with a web
middleware.
Route::get('/redirect', 'SocialAuthController@redirect');
Route::get('/callback', 'SocialAuthController@callback');
Add above root in your /app/routes/web.php
Now this is a part when we need to go back to the facebook configuration in service.php
and update redirect
url.
We are going to set this field to full url of the callback
route. In our case when we are using PHP development server which is served on http:
by default, our final config will look like:
'facebook' => [
'client_id' => '690344774435367',
'client_secret' => 'ebc50d3fd1d2f7286e02d247e5751ef4',
'redirect' => 'http:
],
This will be changed for production, and you should make use of the env()
helper function.
One more thing before proceeding is to register our development site url (which is in this case http:
) with facebook app. Back to the Developer’s dashboard. Click on Settings and Add Platform. Choose Website and type your development domain (http://localhost:8000). Save Changes.
After clicking on app you will see all details on the dashboard like, Settings, Roles, etc…
In Settings you will see two more sub menu:
- Basic
- Advanced
Now we need to add link to our redirect
route which will further redirect user to the facebook. Open resources/views/auth/login.blade.php
and add simple link under the Forgot Your Password link.
<a href="redirect">FB Login</a>
Or
<a href="redirect"><img src="/path/of/your/image.png" /></a>
Now in addition to normal login, we have Facebook login link.
Note: If you get this error when run (Failed to connect to graph.facebook.com port 443: No route to host) then make your created app public and clear cache and run again. (It’s happened in localhost only).
See display looks like this: http://nimb.ws/b7mUAX
Now you can test the link. Fist time, you will need to confirm that you allow this app to use your data.
It’s looks like: http://nimb.ws/hHINWf
After confirmation, you will be returned back to the app. You can see, that url contains code
which is a kind of temporary username and password that allow us to ask facebook for more data about the user.
Socialite again handles this automatically. In the callback
method add following:
$providerUser = \Socialite::driver('facebook')->user();
This user is different from User in our system, but it has enough data for us to create and authenticate the user in our app. It provides following methods: getId()
, getNickname()
, getName()
, getEmail()
, getAvatar()
.
And with this we are done with Socialite and facebook. Next step is to integrate facebook users with our system.
Integrating Facebook users with our app
This solution is designed with a goal to allow multiple social accounts to be connected to the single account in our app. Note that some providers do not return email address, so email cannot be not null and we will change that.
So set the email to be nullable in create_users_table migration:
$table->string('email')->unique()->nullable();
We will need additional migration and model for social accounts.
php artisan make:migration create_social_accounts_table --create="social_accounts"
php artisan make:model SocialAccount
Add following fields to the migration:
Schema::create('social_accounts', function (Blueprint $table) {
$table->integer('user_id');
$table->string('provider_user_id');
$table->string('provider');
$table->timestamps();
});
Run the migrations php artisan migrate:refresh
Column provider_user_id
is facebook’s user id, and provider
in this case will be always facebook but it will allow us to add additional providers (twitter, linkedin, …) later.
Add relations and fillable to the SocialAccount
model.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class SocialAccount extends Model
{
protected $fillable = ['user_id', 'provider_user_id', 'provider'];
public function user()
{
return $this->belongsTo(User::class);
}
}
Now we need some handling service that will try to register user or log in if account already exists. Create SocialAccountService.php
in the app
folder and put following content:
<?php
namespace App;
use Laravel\Socialite\Contracts\User as ProviderUser;
class SocialAccountService
{
public function createOrGetUser(ProviderUser $providerUser)
{
$account = SocialAccount::whereProvider('facebook')
->whereProviderUserId($providerUser->getId())
->first();
if ($account) {
return $account->user;
} else {
$account = new SocialAccount([
'provider_user_id' => $providerUser->getId(),
'provider' => 'facebook'
]);
$user = User::whereEmail($providerUser->getEmail())->first();
if (!$user) {
$user = User::create([
'email' => $providerUser->getEmail(),
'name' => $providerUser->getName(),
]);
}
$account->user()->associate($user);
$account->save();
return $user;
}
}
}
This will try to find provider’s account in the system and if it is not present it will create new user. This method will also try to associate social account with the email address in case that user already has an account.
Now everything is ready to handle facebook’s callback to our app.
Open SocialAuthController
and with updated callback method it should look like this:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\SocialAccountService;
use Socialite;
class SocialAuthController extends Controller
{
public function redirect()
{
return Socialite::driver('facebook')->redirect();
}
public function callback(SocialAccountService $service)
{
$user = $service->createOrGetUser(Socialite::driver('facebook')->user());
auth()->login($user);
return redirect()->to('/home');
}
}
Note: email and password need to be null able.
Now when we login click FB Login this time we are redirected and logged in.