Integrating socialite in Laravel 5.2

Laravel Socialite provides an expressive, fluent interface to OAuth authentication with Facebook, Twitter, Google, LinkedIn, GitHub and Bitbucket. It handles almost all of the boilerplate social authentication code you are dreading writing.
Lets see the steps to integrating socialite in laravel 5.2 now.
NOTE : Before we get started, please go ahead and create your api keys and secrets for the social logins you are going to integrate. Also install laravel/socialite package from github.
Configuring services.php
<?php
return [
/*
|--------------------------------------------------------------------------
| Third Party Services
|--------------------------------------------------------------------------
|
| This file is for storing the credentials for third party services such
| as Stripe, Mailgun, Mandrill, and others. This file provides a sane
| default location for this type of information, allowing packages
| to have a conventional place to find your various credentials.
|
*/
'mailgun' => [
'domain' => env('MAILGUN_DOMAIN'),
'secret' => env('MAILGUN_SECRET'),
],
'mandrill' => [
'secret' => env('MANDRILL_SECRET'),
],
'ses' => [
'key' => env('SES_KEY'),
'secret' => env('SES_SECRET'),
'region' => 'us-east-1',
],
'facebook' => [
'client_id' => env('FACEBOOK_ID'),
'client_secret' => env('FACEBOOK_SECRET'),
'redirect' => env('FACEBOOK_REDIRECT'),
],
'google' => [
'client_id' => env('GOOGLE_ID'),
'client_secret' => env('GOOGLE_SECRET'),
'redirect' => env('GOOGLE_REDIRECT'),
],
'linkedin' => [
'client_id' => env('LINKEDIN_ID'),
'client_secret' => env('LINKEDIN_SECRET'),
'redirect' => env('LINKEDIN_REDIRECT'),
],
'stripe' => [
'model' => App\User::class,
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
],
];
<?php
return [
/*
|--------------------------------------------------------------------------
| Third Party Services
|--------------------------------------------------------------------------
|
| This file is for storing the credentials for third party services such
| as Stripe, Mailgun, Mandrill, and others. This file provides a sane
| default location for this type of information, allowing packages
| to have a conventional place to find your various credentials.
|
*/
'mailgun' => [
'domain' => env('MAILGUN_DOMAIN'),
'secret' => env('MAILGUN_SECRET'),
],
'mandrill' => [
'secret' => env('MANDRILL_SECRET'),
],
'ses' => [
'key' => env('SES_KEY'),
'secret' => env('SES_SECRET'),
'region' => 'us-east-1',
],
'facebook' => [
'client_id' => env('FACEBOOK_ID'),
'client_secret' => env('FACEBOOK_SECRET'),
'redirect' => env('FACEBOOK_REDIRECT'),
],
'google' => [
'client_id' => env('GOOGLE_ID'),
'client_secret' => env('GOOGLE_SECRET'),
'redirect' => env('GOOGLE_REDIRECT'),
],
'linkedin' => [
'client_id' => env('LINKEDIN_ID'),
'client_secret' => env('LINKEDIN_SECRET'),
'redirect' => env('LINKEDIN_REDIRECT'),
],
'stripe' => [
'model' => App\User::class,
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
],
];
Once you have created your api keys and secrets, configure them in your services.php like the above code.
Then, modify your .env file like below.
APP_ENV=local
APP_DEBUG=true
APP_KEY=FmqTcYazqRIOZ08AQpAOYZfX6FIXj1t4
DB_HOST=localhost
DB_DATABASE=homestead
DB_USERNAME=database
DB_PASSWORD=secret
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync
REDIS_HOST=localhost
REDIS_PASSWORD=null
REDIS_PORT=6379
FACEBOOK_ID=YOUR_FACEBOOK_APP_ID
FACEBOOK_SECRET=YOUR_FACEBOOK_APP_SECRET
FACEBOOK_REDIRECT=http://localhost:8000/social/auth/facebook
GOOGLE_ID=YOUR_GOOGLE_APP_ID
GOOGLE_SECRET=YOUR_GOOGLE_APP_SECRET
GOOGLE_REDIRECT=http://localhost:8000/social/auth/google
LINKEDIN_ID=YOUR_LINKEDIN_APP_ID
LINKEDIN_SECRET=YOUR_LINKEDIN_APP_SECRET
LINKEDIN_REDIRECT=http://localhost:8000/social/auth/linkedin
APP_ENV=local
APP_DEBUG=true
APP_KEY=FmqTcYazqRIOZ08AQpAOYZfX6FIXj1t4
DB_HOST=localhost
DB_DATABASE=homestead
DB_USERNAME=database
DB_PASSWORD=secret
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync
REDIS_HOST=localhost
REDIS_PASSWORD=null
REDIS_PORT=6379
FACEBOOK_ID=YOUR_FACEBOOK_APP_ID
FACEBOOK_SECRET=YOUR_FACEBOOK_APP_SECRET
FACEBOOK_REDIRECT=http://localhost:8000/social/auth/facebook
GOOGLE_ID=YOUR_GOOGLE_APP_ID
GOOGLE_SECRET=YOUR_GOOGLE_APP_SECRET
GOOGLE_REDIRECT=http://localhost:8000/social/auth/google
LINKEDIN_ID=YOUR_LINKEDIN_APP_ID
LINKEDIN_SECRET=YOUR_LINKEDIN_APP_SECRET
LINKEDIN_REDIRECT=http://localhost:8000/social/auth/linkedin
Modifying migration file
Now, we need to add extra columns for social logins ids to store to. So open up your user migration file and add social login columns
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->nullable();
$table->string('password', 60);
$table->string('facebook_id');
$table->string('google_id');
$table->string('linkedin_id');
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('users');
}
}
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->nullable();
$table->string('password', 60);
$table->string('facebook_id');
$table->string('google_id');
$table->string('linkedin_id');
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('users');
}
}
Configuring routes.php
Route::get('social/auth/redirect/{provider}', 'Auth\AuthController@redirectToProvider');
Route::get('social/auth/{provider}', 'Auth\AuthController@handleProviderCallback');
Route::get('social/auth/redirect/{provider}', 'Auth\AuthController@redirectToProvider');
Route::get('social/auth/{provider}', 'Auth\AuthController@handleProviderCallback');
Here we are going to dynamically pass our social login providers instead of creating routes for each and every provider.
Modify auth controller
Here we are going to write our business logic of creating, updating and authenticating our users
<?php
namespace App\Http\Controllers\Auth;
use App\User;
use Laravel\Socialite\Facades\Socialite;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
class AuthController extends Controller
{
/*
|--------------------------------------------------------------------------
| Registration & Login Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users, as well as the
| authentication of existing users. By default, this controller uses
| a simple trait to add these behaviors. Why don't you explore it?
|
*/
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
/**
* Where to redirect users after login / registration.
*
* @var string
*/
protected $redirectTo = '/';
/**
* Create a new authentication controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest', ['except' => 'logout']);
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|confirmed|min:6',
]);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
/**
* Redirect the user to the social provider authentication page.
*
* @return Response
*/
public function redirectToProvider($provider)
{
return Socialite::driver($provider)->redirect();
}
/**
* Obtain the user information from social provider.
*
* @return Response
*/
public function handleProviderCallback($provider)
{
try {
$user = Socialite::driver($provider)->user();
} catch (Exception $e) {
return Redirect::to('/auth/login');
}
$authUser = $this->findOrCreateUser($user, $provider);
auth()->login($authUser, true);
return redirect()->to('/');
}
/**
* Return user if exists; create and return if doesn't
*
* @param $socialLiteUser
* @param $key
* @return User
*/
private function findOrCreateUser($socialLiteUser, $key)
{
$user = User::updateOrCreate([
'email' => $socialLiteUser->email,
], [
$key . '_id' => $socialLiteUser->id,
'name' => $socialLiteUser->name
]);
return $user;
}
}
<?php
namespace App\Http\Controllers\Auth;
use App\User;
use Laravel\Socialite\Facades\Socialite;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
class AuthController extends Controller
{
/*
|--------------------------------------------------------------------------
| Registration & Login Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users, as well as the
| authentication of existing users. By default, this controller uses
| a simple trait to add these behaviors. Why don't you explore it?
|
*/
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
/**
* Where to redirect users after login / registration.
*
* @var string
*/
protected $redirectTo = '/';
/**
* Create a new authentication controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest', ['except' => 'logout']);
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|confirmed|min:6',
]);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
/**
* Redirect the user to the social provider authentication page.
*
* @return Response
*/
public function redirectToProvider($provider)
{
return Socialite::driver($provider)->redirect();
}
/**
* Obtain the user information from social provider.
*
* @return Response
*/
public function handleProviderCallback($provider)
{
try {
$user = Socialite::driver($provider)->user();
} catch (Exception $e) {
return Redirect::to('/auth/login');
}
$authUser = $this->findOrCreateUser($user, $provider);
auth()->login($authUser, true);
return redirect()->to('/');
}
/**
* Return user if exists; create and return if doesn't
*
* @param $socialLiteUser
* @param $key
* @return User
*/
private function findOrCreateUser($socialLiteUser, $key)
{
$user = User::updateOrCreate([
'email' => $socialLiteUser->email,
], [
$key . '_id' => $socialLiteUser->id,
'name' => $socialLiteUser->name
]);
return $user;
}
}
Auth Biolerplate
Now, lets pull in laravel’s default auth boilerplate files by following command
php artisan make:auth
php artisan make:auth
Open login.blade.php and add the necessary socialite links.
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Login</div>
<div class="panel-body">
<form class="form-horizontal" role="form" method="POST" action="{{ url('/login') }}">
{!! csrf_field() !!}
<div class="row">
<div class="col-sm-8">
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
<label class="col-md-4 control-label">E-Mail Address</label>
<div class="col-md-6">
<input type="email" class="form-control" name="email" value="{{ old('email') }}">
@if ($errors->has('email'))
<span class="help-block">
<strong>{{ $errors->first('email') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
<label class="col-md-4 control-label">Password</label>
<div class="col-md-6">
<input type="password" class="form-control" name="password">
@if ($errors->has('password'))
<span class="help-block">
<strong>{{ $errors->first('password') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<div class="checkbox">
<label>
<input type="checkbox" name="remember"> Remember Me
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button type="submit" class="btn btn-primary">
Login
</button>
<a class="btn btn-link" href="{{ url('/password/reset') }}">Forgot Your Password?</a>
</div>
</div>
</div>
<div class="col-sm-4">
<h5>Sign in with one click!</h5>
<a style="background-color:#3a5795; border-color:#3a5795" href="{{ url('/social/auth/redirect', ['facebook']) }}" class="btn btn-info">
<i class="fa fa-facebook"></i>
</a>
<a style="background-color:#e53935; border-color:#e53935" href="{{ url('/social/auth/redirect', ['google']) }}" class="btn btn-info">
<i class="fa fa-google"></i>
</a>
<a style="background-color:#43acff; border-color:#43acff" href="{{ url('/social/auth/redirect', ['linkedin']) }}" class="btn btn-info">
<i class="fa fa-linkedin"></i>
</a>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Login</div>
<div class="panel-body">
<form class="form-horizontal" role="form" method="POST" action="{{ url('/login') }}">
{!! csrf_field() !!}
<div class="row">
<div class="col-sm-8">
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
<label class="col-md-4 control-label">E-Mail Address</label>
<div class="col-md-6">
<input type="email" class="form-control" name="email" value="{{ old('email') }}">
@if ($errors->has('email'))
<span class="help-block">
<strong>{{ $errors->first('email') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
<label class="col-md-4 control-label">Password</label>
<div class="col-md-6">
<input type="password" class="form-control" name="password">
@if ($errors->has('password'))
<span class="help-block">
<strong>{{ $errors->first('password') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<div class="checkbox">
<label>
<input type="checkbox" name="remember"> Remember Me
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button type="submit" class="btn btn-primary">
Login
</button>
<a class="btn btn-link" href="{{ url('/password/reset') }}">Forgot Your Password?</a>
</div>
</div>
</div>
<div class="col-sm-4">
<h5>Sign in with one click!</h5>
<a style="background-color:#3a5795; border-color:#3a5795" href="{{ url('/social/auth/redirect', ['facebook']) }}" class="btn btn-info">
<i class="fa fa-facebook"></i>
</a>
<a style="background-color:#e53935; border-color:#e53935" href="{{ url('/social/auth/redirect', ['google']) }}" class="btn btn-info">
<i class="fa fa-google"></i>
</a>
<a style="background-color:#43acff; border-color:#43acff" href="{{ url('/social/auth/redirect', ['linkedin']) }}" class="btn btn-info">
<i class="fa fa-linkedin"></i>
</a>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
Do the same for register.blade.php file too.
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Register</div>
<div class="panel-body">
<form class="form-horizontal" role="form" method="POST" action="{{ url('/register') }}">
{!! csrf_field() !!}
<div class="row">
<div class="col-sm-8">
<div class="form-group{{ $errors->has('name') ? ' has-error' : '' }}">
<label class="col-md-4 control-label">Name</label>
<div class="col-md-6">
<input type="text" class="form-control" name="name" value="{{ old('name') }}">
@if ($errors->has('name'))
<span class="help-block">
<strong>{{ $errors->first('name') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
<label class="col-md-4 control-label">E-Mail Address</label>
<div class="col-md-6">
<input type="email" class="form-control" name="email" value="{{ old('email') }}">
@if ($errors->has('email'))
<span class="help-block">
<strong>{{ $errors->first('email') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
<label class="col-md-4 control-label">Password</label>
<div class="col-md-6">
<input type="password" class="form-control" name="password">
@if ($errors->has('password'))
<span class="help-block">
<strong>{{ $errors->first('password') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group{{ $errors->has('password_confirmation') ? ' has-error' : '' }}">
<label class="col-md-4 control-label">Confirm Password</label>
<div class="col-md-6">
<input type="password" class="form-control" name="password_confirmation">
@if ($errors->has('password_confirmation'))
<span class="help-block">
<strong>{{ $errors->first('password_confirmation') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button type="submit" class="btn btn-primary">
<i class="fa fa-btn fa-user"></i>Register
</button>
</div>
</div>
</div>
<div class="col-sm-4">
<h5>Sign in with one click!</h5>
<a style="background-color:#3a5795; border-color:#3a5795" href="{{ url('/social/auth/redirect', ['facebook']) }}" class="btn btn-info">
<i class="fa fa-facebook"></i>
</a>
<a style="background-color:#e53935; border-color:#e53935" href="{{ url('/social/auth/redirect', ['google']) }}" class="btn btn-info">
<i class="fa fa-google"></i>
</a>
<a style="background-color:#43acff; border-color:#43acff" href="{{ url('/social/auth/redirect', ['linkedin']) }}" class="btn btn-info">
<i class="fa fa-linkedin"></i>
</a>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Register</div>
<div class="panel-body">
<form class="form-horizontal" role="form" method="POST" action="{{ url('/register') }}">
{!! csrf_field() !!}
<div class="row">
<div class="col-sm-8">
<div class="form-group{{ $errors->has('name') ? ' has-error' : '' }}">
<label class="col-md-4 control-label">Name</label>
<div class="col-md-6">
<input type="text" class="form-control" name="name" value="{{ old('name') }}">
@if ($errors->has('name'))
<span class="help-block">
<strong>{{ $errors->first('name') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
<label class="col-md-4 control-label">E-Mail Address</label>
<div class="col-md-6">
<input type="email" class="form-control" name="email" value="{{ old('email') }}">
@if ($errors->has('email'))
<span class="help-block">
<strong>{{ $errors->first('email') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
<label class="col-md-4 control-label">Password</label>
<div class="col-md-6">
<input type="password" class="form-control" name="password">
@if ($errors->has('password'))
<span class="help-block">
<strong>{{ $errors->first('password') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group{{ $errors->has('password_confirmation') ? ' has-error' : '' }}">
<label class="col-md-4 control-label">Confirm Password</label>
<div class="col-md-6">
<input type="password" class="form-control" name="password_confirmation">
@if ($errors->has('password_confirmation'))
<span class="help-block">
<strong>{{ $errors->first('password_confirmation') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button type="submit" class="btn btn-primary">
<i class="fa fa-btn fa-user"></i>Register
</button>
</div>
</div>
</div>
<div class="col-sm-4">
<h5>Sign in with one click!</h5>
<a style="background-color:#3a5795; border-color:#3a5795" href="{{ url('/social/auth/redirect', ['facebook']) }}" class="btn btn-info">
<i class="fa fa-facebook"></i>
</a>
<a style="background-color:#e53935; border-color:#e53935" href="{{ url('/social/auth/redirect', ['google']) }}" class="btn btn-info">
<i class="fa fa-google"></i>
</a>
<a style="background-color:#43acff; border-color:#43acff" href="{{ url('/social/auth/redirect', ['linkedin']) }}" class="btn btn-info">
<i class="fa fa-linkedin"></i>
</a>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
That’s it! That’s all you need to do for integrating socialite in laravel 5.2