Laravel 5.6 Socialite Tutorial
Laravel is very famous for its ready-to-use modules. One of them is Authentication which was introduced in Laravel 5.2. It generates all the required controllers, routes and views with a single artisan command viz. php artisan make:auth
.
While this works best to set up a conventional login system in the application, the web is moving towards social logins, i.e., Facebook, Google, etc. Today, we will try and integrate this model into a Laravel application. In this tutorial, we will configure preliminary setup Facebook and Google OAuth.
# Laravel Socialite Project Setup
First off, let us craft a fresh Laravel project, you can also use your other Laravel projects.
laravel new socialiteApp
Also, generate .env file and app key, if it isn’t already done for you:
cp .env.example .env
php artisan key:generate
# Socialite Database Setup
As we have learned earlier, Laravel stores database settings in environment config file called .env. I’m using MySQL database, setup your relevant database credentials:
# .env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=social
DB_USERNAME=root
DB_PASSWORD=
# Socialite Model and Migrations
Laravel provides users
and password resets
migration by default. It also provides a working User
model. These are used with Laravel Auth setup. We can rewrite them to suit our requirements or create new migration table and model to improve code readability in the future. Let’s choose the second option and create fresh migration and model first:
php artisan make:model SocialAccount -m

As seen, the above command created both model and migration at once.
# Migration Setup
Add following fields in the create_social_accounts_table
so as to store relevant user data:
# database/migrations/..._create_social_accounts_table.php
...
public function up()
{
Schema::create('social_accounts', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->string('provider_user_id');
$table->string('provider');
$table->timestamps();
$table->softDeletes();
});
Schema::table('social_accounts', function (Blueprint $table) {
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
}
...
Here provider_user_id
will store provider (google/facebook) specific id and provider stores provider name. We are also using soft deletes.
Also, make the password nullable in the table as a user who uses social login won’t pass a password. This can be a compromise for the application, but we can validate the password input from the form.
# database/migrations/..._create_users_accounts_table.php
...
public function up()
{
Schema::create('users', function (Blueprint $table) {
...
$table->string('password')->nullable();
});
}
...
# Relationships
Situation:
A user usually uses same email id for his emails and social accounts. In that case, if we keep creating new records for each new conventional login and social login separately, we may end collecting duplicate emails. On the other hand, if we configure email to be unique, problems will arise when a user uses same email id for both Google and Facebook and will disbar the access.
The Solution:
To save the application from all these hassles, we already created a separate table for social accounts
so now let us map both User
and SocialLogin
model.
Each user can have a social accounts. Thus we will setup One-to-One relationship between User
and SocialAccount
.
# app/User.php
...
class User extends Authenticatable
{
...
public function profile()
{
return $this->hasOne('App\SocialProfile');
}
}
Let us also create a belongsTo relationship with User
.
# app/SocialAccount.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class SocialAccount extends Model
{
use SoftDeletes;
protected $dates = ['deleted_at'];
protected $fillable = ['user_id', 'provider_user_id', 'provider'];
public function user()
{
return $this->belongsTo(User::class);
}
}
We just mapped User
model here and also integrated soft deletes and $fillable
. Everything looks good, let us now migrate the database tables:
php artisan migrate

Did you face the following error while running migration? (If not, move ahead)
Here’s a small solution to it. Just add these two lines of code in app/Providers/AppServiceProvider.php
# app/Providers/AppServiceProvider.php
...
use Illuminate\Support\Facades\Schema;
class AppServiceProvider extends ServiceProvider
{
...
public function boot()
{
Schema::defaultStringLength(191);
}
...
}
# Socialite Package Setup
Laravel has a ready-to-use package to configure social logins in the application named Socialite. It was initially a third-party library, but with the newer version of Larvel, it was merged with it. We need to install it anyway:
composer require laravel/socialite
For version 5.5+ in Laravel, the Service Provider and Alias are mapped automatically so we don’t need to add them manually.
# Routes for Social Login
We will create three endpoints in the application:
- Main Endpoint for login buttons with Google and Facebook
- Social endpoint to redirect to respective login screens
- Callback endpoint that the respective website must redirect on successful login
And here they are:
# routes/web.php
<?php
...
Route::get('/', function () {
return view('welcome');
});
Route::get('/login', function () {
return view('socialLogin');
});
Route::get('/auth/social/{social}', 'SocialLoginController@redirectToSocial');
Route::get('/auth/{social}/callback', 'SocialLoginController@handleSocialCallback');
# Blade for Social Login
In routes, we are setting an endpoint for login buttons, so let us first add them. Create a fresh blade file socialLogin.blade.php
in resources/views
namespace.
# resources/views/socialLogin.blade.php
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Social Login In Laravel 5.6</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Fonts -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- Styles -->
<style>
body {
background-color: #fff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
}
.social-login {
display: flex;
flex-direction: column;
background-color: white;
justify-content: center;
width: 400px;
height: 220px;
max-width: 50vw;
padding: 15px 35px;
border-radius: 5px;
box-shadow: 0 10px 40px 0 rgba(0, 0, 0, 0.1);
}
.social-login h2 {
margin: 20px 0 20px;
padding: 0;
text-transform: uppercase;
color: #000;
position: relative;
text-align: center;
}
.social-button--facebook {
list-style: none;
background-color: transparent;
border-width: 2px;
border-style: solid;
border-color: #3A5998;
color: #3A5998;
cursor: pointer;
font-size: 14px;
padding: 15px;
display: flex;
border-radius: 5px;
align-items: center;
text-decoration: none;
text-transform: uppercase;
transition: background-color 250ms ease-out, color 250ms ease-out;
font-weight: 700;
position: relative;
margin: 10px 0;
z-index: 0;
will-change: background-color, color;
user-select: none;
-webkit-font-smoothing: antialiased;
}
.social-button--facebook:focus, .social-button--facebook:hover {
background-color: #bac8e4;
}
.social-icon--facebook {
color: white;
font-size: 18px;
}
.social-icon--facebook:after {
content: "";
background-color: #3A5998;
position: absolute;
width: 50px;
height: 100%;
top: 0;
left: 0;
z-index: -1;
}
.social-button--google {
list-style: none;
background-color: transparent;
border-width: 2px;
border-style: solid;
border-color: #DB4437;
color: #DB4437;
cursor: pointer;
font-size: 14px;
padding: 15px;
display: flex;
border-radius: 5px;
align-items: center;
text-decoration: none;
text-transform: uppercase;
transition: background-color 250ms ease-out, color 250ms ease-out;
font-weight: 700;
position: relative;
margin: 10px 0;
z-index: 0;
will-change: background-color, color;
user-select: none;
-webkit-font-smoothing: antialiased;
}
.social-button--google:focus, .social-button--google:hover {
background-color: #fae6e4;
}
.social-icon--google {
color: white;
font-size: 18px;
}
.social-icon--google:after {
content: "";
background-color: #DB4437;
position: absolute;
width: 50px;
height: 100%;
top: 0;
left: 0;
z-index: -1;
}
.social-text {
width: 100%;
text-align: center;
}
</style>
</head>
<body>
<div class="social-login">
<h2>Social Login in Laravel 5.6</h2>
<a href="{{ url('/auth/social/google') }}" class="social-button--google">
<i class="social-icon--google fa fa-google"></i>
<span class="social-text">
Sign in with google
</span>
</a>
<a href="{{ url('/auth/social/facebook') }}" class="social-button--facebook">
<i class="social-icon--facebook fa fa-facebook"></i>
<span class="social-text">
Sign in with facebook
</span>
</a>
</div>
</body>
</html>
We can test it by running:
http://localhost:8000/login

# Controller for Social Login
Let us first create a new controller to handle social logins in Laravel:
php artisan make:controller SocialLoginController
Since we want to setup two social logins (Google and Facebook), and as the application scales, the other providers may also be needed, let us setup, dynamic Socialite.
public function redirectToSocial()
{
//static
Socialite::driver('facebook')->redirect();
Socialite::driver('google')->redirect();
Socialite::driver('twitter')->redirect();
Socialite::driver('github')->redirect();
}
# app/Http/Controllers/SocialLoginController.php
...
class SocialLoginController extends Controller
{
//dynamic
public function redirectToSocial($social)
{
return Socialite::with($social)->redirect();
}
}
The social login provider sends back data to the application on successful login or error in case of unsuccessful login. Here’s how we can handle that:
# app/Http/Controllers/SocialLoginController.php
...
class SocialLoginController extends Controller
{
...
function handleSocialCallback(SocialAccountService $service, $social)
{
try {
$user = $service->setOrGetUser(Socialite::driver($social));
auth()->login($user);
return redirect('/');
} catch (\Exception $e) {
return $e;
}
}
}
In the above code snippet, we are using SocialAccountService
(which we will set up in a moment!) and adding new user to the database and also authenticating the user to browse the application.
Thus, here’s how SocialLoginController
looks now:
# app/Http/Controllers/SocialLoginController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Reqauest;
use Socialite;
use App\SocialAccountService;
class SocialLoginController extends Controller
{
public function redirectToSocial($social)
{
return Socialite::with($social)->redirect();
}
function handleSocialCallback(SocialAccountService $service, $social)
{
try {
$user = $service->setOrGetUser(Socialite::driver($social));
auth()->login($user);
return redirect('/');
} catch (\Exception $e) {
return $e;
}
}
}
# Insert Records in Database
As discussed earlier, we would want to keep track of user logging in with their social accounts. We already have a working migration table and model for it. So now let us work around creating records in the database. To keep this logic independent, we intentionally have not added this in the controller we created in the previous step.
We will create a different service that will take provider response as a parameter, check if the user email and provider details already exist in the database, add if not and finally return back the user details to the controller. Here’s the whole scenario in action:
# app/SocialAccountService.php
<?php
namespace App;
use Laravel\Socialite\Contracts\Provider;
class SocialAccountService
{
public function setOrGetUser(Provider $provider)
{
$providerUser = $provider->user();
$providerName = class_basename($provider);
$account = SocialAccount::whereProvider($providerName)
->whereProviderUserId($providerUser->getId())
->first();
if ($account) {
return $account->user;
} else {
$account = new SocialAccount([
'provider_user_id' => $providerUser->getId(),
'provider' => $providerName
]);
$user = User::whereEmail($providerUser->getEmail())->first();
if (!$user) {
$user = User::create([
'email' => $providerUser->getEmail(),
'name' => $providerUser->getName(),
'username' => strtolower(preg_replace('/\s+/', '_', $providerUser->name) . mt_rand(10, 100))
]);
}
$account->user()->associate($user);
$account->save();
return $user;
}
}
}
And that concludes the overall setup to work with the socialite in Laravel. It may be difficult for some developers to digest all the information at once. So let’s take a break and continue configuring Google and Facebook login in the next post.
Conclusion:
In this post, we started setting up the Laravel application from scratch to configure social logins like Google and Facebook. In the next session, we will work with Google and Facebook’s developer console to get API keys and integrate them into this application. Don’t miss on all the fun there.
Questions & Comments:
Thanks for reading. Drop your suggestions and questions in the comment section below.