/laravel-social-auth

A thin layer wrapping on Socialite package for even easier implementation of the social login feature

Primary LanguagePHP

laravel-social-auth

Laravel provides an official package named as Socialite to enable an easy implementation of the social login feature. Although, it is absolutely convenient and simple, it still requires some non trivial piece of code.

Sometimes, the repetitious work can cause an inertia for you to start a new project. To eliminate this issue and quickly gain a momentum for a new idea, this package is built to provide a thin layer wrapping over the Socialite package for the even easier implementation of the social login for a Laravel application.

1 Requirements

It is recommended to install this package with PHP version 7.1.3+ and Laravel Framework version 5.5+

2 Installation

composer require bkstar123/social-auth

3 Usage

3.1 Default usage

This package is by default assumed to be used together with the Laravel's default authentication guard (as specified in config/auth.php) and App\User model.

  • Modify Laravel's default user migration yyyy-mm-dd-xxxxxxxx_create_users_table to make sure it has the following lines:
$table->string('name')->nullable();
$table->string('avatar')->nullable();
$table->string('email')->unique();
$table->string('password')->nullable();

Note: If you already run the user migration, you should create another migration to update users table with the new column avatar and set password & name columns to be nullable (email, name are already supplied in the Laravel default user migration), for example:

Run: php artisan make:migration update_users_table

yyyy_mm_dd_xxxxxxxx_update_users_table.php:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class UpdateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('password')->nullable()->change();
            $table->string('name')->nullable()->change();
            $table->string('avatar')->nullable();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function(Blueprint $table) {
            \DB::statement('SET FOREIGN_KEY_CHECKS=0;');
            \DB::table('users')->truncate();
            $table->dropColumn('avatar');
            $table->string('name')->nullable(false)->change();
            $table->string('password')->nullable(false)->change();
            \DB::statement('SET FOREIGN_KEY_CHECKS=1;');
        });
    }
}
  • Run: composer require doctrine/dbal

  • Run migration command: php artisan migrate

  • In app/User.php, import and use Bkstar123\SocialAuth\Traits\SocialLinkable trait. Add avatar to $fillable array, like:

protected $fillable = [
    'name', 'email', 'password', 'avatar'
];
  • In app/Http/Controllers/Auth/LoginController.php, make it to implement Bkstar123\SocialAuth\Contracts\SocialAuthentication interface, then import and use Bkstar123\SocialAuth\Traits\SocialAuthenticable trait
  • In routes/web.php, add the following routes:
Route::get('/login/{provider}', 'Auth\LoginController@redirectToSocialProvider')
     ->name('login.social');
Route::get('/login/{provider}/callback', 'Auth\LoginController@handleSocialProviderCallback')
     ->name('login.social.callback');
  • In the view file where you have the login form, add a social login link, for example:
<!-- For Google login -->
<a href="{{ route('login.social', ['provider' => 'google']) }}" 
   class="btn btn-danger">
    <i class="fa fa-google"></i>&nbsp; Google 
</a>
  • In .env file, add the necessary environment keys/values:
[PROVIDER_NAME]_CLIENT_ID  
[PROVIDER_NAME]_CLIENT_SECRET  
[PROVIDER_NAME]_CLIENT_REDIRECT 

Where [PROVIDER_NAME] can be GOOGLE, FACEBOOK, TWITTER, LINKEDIN, GITHUB, GITLAB, BITBUCKET.

3.2 Custom usage

3.2.1 If you do not want to use the package default migration:

  • Put the following key/value in the .env file:
    BKSTAR123_SOCIALAUTH_LOAD_MIGRATION=false

  • Then, you must create your own migration file for building a table to store social accounts, for example:
    yyyy_mm_dd_xxxxxxxx_create_customer_social_accounts_table.php:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateCustomerSocialAccountsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('customer_social_accounts', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->bigInteger('customer_id')->unsigned()->index();
            $table->string('provider_name');
            $table->string('provider_user_id');
            $table->timestamps();
            $table->foreign('customer_id')->references('id')->on('customers')->onDelete('cascade');
            $table->unique(['provider_name', 'provider_user_id']);
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('customer_social_accounts');
    }
}

Note: provider_name, provider_user_id are required to be named as they are in the migration, the foreign key (customer_id in the above example) can be named appropriately depending on your use cases.

Alternatively, you can publish the package's default migration to database/migrations/ and use it as a starting point for customization.
=> Run: php artisan vendor:publish --provider="Bkstar123\SocialAuth\SocialAuthServiceProvider"

  • Run php artisan migrate

3.2.2 You can define your custom social account model which has a belongsTo relationship with your custom user model

app/Models/CustomerSocialAccount.php:

<?php

namespace App;

use App\Models\Customer;
use Bkstar123\SocialAuth\Models\Abstracts\SocialAccountBase;

class CustomerSocialAccount extends SocialAccountBase
{
    public function getUserModelClass()
    {
    	return Customer::class;
    }
}

3.2.3 You can also tell the package to use your custom social account and user models

For example:

  • In your user model like app/Models/Customer.php:

After importing and using Bkstar123\SocialAuth\Traits\SocialLinkable trait, add the following method:

protected function getSocialAccountModelClass()
{
    return CustomerSocialAccount::class; // Surely, you must autoload this class 
}
  • In the controller which handles the login logic:
    After making it to implement Bkstar123\SocialAuth\Contracts\SocialAuthentication interface, importing and using Bkstar123\SocialAuth\Traits\SocialAuthenticable trait. Add the following methods:
protected function getUserModelClass()
{
    return Customer::class; // Surely, you must autoload this class 
}

protected function getSocialAccountModelClass()
{
    return CustomerSocialAccount::class; // Surely, you must autoload this class 
}

3.2.4 You can change which kind of the social data you want to map to the user which is to be persisted to the database

For example:
Assuming that your users table has social_avatar, email. Then, in the controller which handles the login logic, add the following method:

protected function mapUserWithSocialData($socialUser)
{
    return [
        'social_avatar' => $socialUser->getAvatar(),
        'email' => $socialUser->getEmail(),
    ];
}

3.2.5 You can use beforeFirstSocialLogin() hook to add more business logic before signing in a user using her social account at the first time

For example, you may need to set email_verified_at for a user before signing her in using her social account at the first time if your application enforces a logic that all users must be verified before being able to use some features.

To do so, in the controller which handles the login logic, add the following method:

protected function beforeFirstSocialLogin($user, $socialUser)
{
    if (!$user->email_verified_at) {
        $user->email_verified_at = Carbon::now();
        $user->save();
    }
}

3.2.6 You can customize the action that is to be taken after successfully signing in a user using her social account

For example: You may want to explicitly redirect the authenticated user to a dashboard

protected function postSocialLogIn()
{
    return redirect()->route('dashboard');
}

3.2.7 You can customize the action that is to be taken if your application fails to get data from the social provider

For example: You may want to redirect the user to the customer login page in this case

protected function actionIfFailingToGetSocialData()
{
    return redirect()->route('customer.login');
}

By default, the package uses the Laravel's default authentication guard which is specified in config/auth.php.
This behavior can be overwritten by the guard() method defined in your controller (which handles the login logic):

For example: You may want the package to use the custom authentication guard named as customer

protected function guard()
{
    return Auth::guard('customer');
}