Update March 30, 2017
If you having problems with facebook login make sure to update your Socialite package with composer update laravel/socialite
.
This is a tutorial of integrating Laravel Socialite plugin using Facebook.
I will be using Laravel 5.2. I assume you have experiance with Laravel. With make:auth
we will create basic scaffold for login and registration views and routes.
Preparing
Lets begin with the clean laravel installation. In terminal type:
laravel new awesome-app
cd awesome-app
Create database:
echo "create database awesome_app" | mysql -u root -p
# type password
On local environment I'm using root user for mysql but you change it accorting to your setup. Fill in .env with credentials and finally migrate database.
php artisan migrate
Create the scaffold for login with
php artisan make:auth
Start the server with php artisan serve
and visit the page http://localhost:8000/.
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' => [
// Other service 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
Hover over My Apps and click on Add a New App and select Website.
Enter the app name. On the next step select the category and click Create App ID
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()
{
// when facebook call us a with token
}
}
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');
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://localhost:8000
by default, our final config will look like:
'facebook' => [
'client_id' => '690344774435367',
'client_secret' => 'ebc50d3fd1d2f7286e02d247e5751ef4',
'redirect' => 'http://localhost:8000/callback',
],
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://localhost:8000
) 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.
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>
Now in addition to normal login, we have Facebook login link.
Now you can test the link. Fist time, you will need to confirm that you allow this app to use your data.
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');
}
}
Now when we login click FB Login this time we are redirected and logged in.
In my next post I will add Twitter as a login option.
Update: changed Schema::table to Schema::create tnx to Adam Esterle