Laravel Social Authentication with Socialite

Socialite is a great package that lets us authenticate users with a variety of social networks.

Laravel introduced a built in Authentication module in version 5.2. To set this up, you just have to run php artisan make:auth and everything is generated for you, from the views to the controllers and the routes.

In the views folder, an auth folder will be created containing registration, login and password reset views. You will also get an auth folder generated in the controllers containing an AuthController and PasswordController. In the routes, a route mapping to these controllers will be created as well. And that is a great thing. However, this command will only make you a traditional login.

In most sites nowadays when signing up, users have the option of signing up with a social provider such as Facebook. In this tutorial, I will teach you how to add multiple social providers to a Laravel app using Socialite package. For this tutorial we will add Facebook, Github and Twitter signups. The complete code can be found on Github

Lets generate a new Laravel app. I am using Laravel 5.2 for this tutorial.

composer create-project laravel/laravel lara-social

Database Setup

Next you need to setup your database to work with Laravel - to do this, you first need to know the hostname, username and database name. I will leave my password empty for this tutorial. Edit the Laravel environment configuration file .env (in the root directory) and add the database settings:

.env

DB_HOST=localhost
DB_DATABASE=lara-social
DB_USERNAME=username
DB_PASSWORD=

Migrations and Creating the users Table

If you look inside database/migrations you will notice that the generated laravel app already came with migrations for creating the users table and password resets table.

Open the migration for creating the users table. There are a few things I want us to tweak before creating the users table.

A user created via OAuth will have a provider and we also need a provider_id which should be unique. With Twitter, there are cases where the user does not have an email set up and thus the hash sent back by the callback won't have an email resulting to an error. To counter this, we will set the email field to nullable. Also, when creating users via Oauth we won't be passing any passwords therefore we need to set the password field in the migration nullable.

Here, we are doing four things: adding provider and provider_id columns to the users table (note the provider_id column should be set to unique). We also make the email and password fields in the users table nullable.

The up method in your migration should now look like this:

database/migrations/{titmestamp}_create_users_table.php

[...]
public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->nullable();
            $table->string('password', 60)->nullable();
            $table->string('provider');
            $table->string('provider_id')->unique();
            $table->rememberToken();
            $table->timestamps();
        });
    }
[...]

If you already have a Laravel app, you will have to generate a new migration to add the extra columns to the users table and also set the email and password fields to nullable at the database level.

Then run the migration with:

php artisan migrate

This will create both the users and password resets table.

User Model

We should add provider and provider_id to the list of mass assignable attributes in the User model.

app/User.php

[...]
protected $fillable = [
        'name', 'email', 'password', 'provider', 'provider_id'
    ];
[...]

We can now add authentication to our app with:

php artisan make:auth

So, if we run php artisan serve and visit http://localhost:8000 you will notice sign up and sign in links on the nav. Users can now sign up and login to our app via traditional Login. We want them to be able to sign up using Facebook, Twitter and Github. With Socialite , adding this functionality is made a breeze since Socialite handles almost all of the boilerplate social authentication code.

Adding Socialite

To get started with Socialite we'll first require the package

composer require laravel/socialite

After installing the Socialite library, register the Laravel\Socialite\SocialiteServiceProvider in your config/app.php configuration file like this:

config/app.php

'providers' => [
    // Other service providers...

    Laravel\Socialite\SocialiteServiceProvider::class,
],

Then add the Socialite facade to the aliases array in your app configuration file:

config/app.php

'aliases' => [
    // Other aliases...

    'Socialite' => Laravel\Socialite\Facades\Socialite::class,
],

App registration

The next step is to add the credentials for the OAuth services the application utilizes. These credentials should be placed in your config/services.php configuration file. In this app we are going to use Twitter, Github and Facebook.

Let's start by registering our app on Twitter so we can get the client id and secret. We should also set the callback URL for our app. Visit this link to register your new app. Note, you have to be logged in in order to register an app on Twitter.

Set the callback URL to http://localhost:8000/auth/twitter/callback. Once the app has been created click on the keys and access tokens tab to get your Consumer API Key and Consumer API secret. Add Twitter as a service in your config/services.php file:

config/services.php

[...]
'twitter' => [
        'client_id'     => env('TWITTER_ID'),
        'client_secret' => env('TWITTER_SECRET'),
        'redirect'      => env('TWITTER_URL'),
    ],
[...]

Set the keys you got after registering your app in your .env file:

TWITTER_ID={{API Key}}
TWITTER_SECRET={{API secret}}
TWITTER_URL={{callbackurl}}

We will have to repeat this for both Facebook and Github.

For Facebook, register your app here then click on settings on the sidenav. From the basic settings you will be able to access your API Key and API Secret. Also, click the Add Platform button below the settings configuration. Select Website in the platform dialog then enter the website URL, in our case it is http://localhost:8000. Set the App Domains to localhost then save the settings.

Update your config/services.php file to take note of Facebook as a service. Note, the values for the key, secret and callback url should be set in your .env file. The FACEBOOK_URL in this case will be http://localhost:8000/auth/facebook/callback :

config/services.php

[...]
'facebook' => [
        'client_id'     => env('FACEBOOK_ID'),
        'client_secret' => env('FACEBOOK_SECRET'),
        'redirect'      => env('FACEBOOK_URL'),
    ],
[...]

Visit this link to create a new app on Github. Enter the app details and you will receive the API key and secret. Update your config/services.php file to take note of Github, similar to how you you did it for Twitter and Facebook.

Routing

Next, you are ready to authenticate users! You will need two routes: one for redirecting the user to the OAuth provider, and another for receiving the callback from the provider after authentication:

app/Http/routes.php

// Other routes
[...]
// OAuth Routes
Route::get('auth/{provider}', 'Auth\AuthController@redirectToProvider');
Route::get('auth/{provider}/callback', 'Auth\AuthController@handleProviderCallback');

Auth Controller

We will access Socialite using the Socialite facade. We will also have to require the Auth facade so we can access various Auth methods:

app/Http/Controllers/Auth/AuthController.php

[...]
use Auth;
use Socialite;
[...]

class AuthController extends Controller
{
    // Some methods which were generated with the app
    [...]
    /**
     * Redirect the user to the OAuth Provider.
     *
     * @return Response
     */
    public function redirectToProvider($provider)
    {
        return Socialite::driver($provider)->redirect();
    }

    /**
     * Obtain the user information from provider.  Check if the user already exists in our
     * database by looking up their provider_id in the database.
     * If the user exists, log them in. Otherwise, create a new user then log them in. After that 
     * redirect them to the authenticated users homepage.
     *
     * @return Response
     */
    public function handleProviderCallback($provider)
    {
        $user = Socialite::driver($provider)->user();

        $authUser = $this->findOrCreateUser($user, $provider);
        Auth::login($authUser, true);
        return redirect($this->redirectTo);
    }

    /**
     * If a user has registered before using social auth, return the user
     * else, create a new user object.
     * @param  $user Socialite user object
     * @param $provider Social auth provider
     * @return  User
     */
    public function findOrCreateUser($user, $provider)
    {
        $authUser = User::where('provider_id', $user->id)->first();
        if ($authUser) {
            return $authUser;
        }
        return User::create([
            'name'     => $user->name,
            'email'    => $user->email,
            'provider' => $provider,
            'provider_id' => $user->id
        ]);
    }
    [...]

The redirectToProvider method takes care of sending the user to the OAuth provider, while the handleProviderCallback method will read the incoming request and retrieve the user's information from the provider. Notice we also have a findOrCreateUser method which looks up the user object in the database to see if it exists. If a user exists, the existing user object will be returned. Otherwise, a new user will be created. This prevents users from signing up twice.

Social Login Links

It's time to add the links to to the registration and login views so that users can sign up and login with Facebook, Github and Twitter. You will notice that the links point to /auth/{provider} and will take you to OAuth provider for authentication.

In the user registration view add this after Register button:

Resources/Views/Auth/register.blade.php

[...]
<form class="form-horizontal" role="form" method="POST" action="{{ url('/register') }}">
<!--Other form fields above the button-->
    <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>
    <hr>
    <div class="form-group">
        <div class="col-md-6 col-md-offset-4">
            <a href="{{ url('/auth/github') }}" class="btn btn-github"><i class="fa fa-github"></i> Github</a>
            <a href="{{ url('/auth/twitter') }}" class="btn btn-twitter"><i class="fa fa-twitter"></i> Twitter</a>
            <a href="{{ url('/auth/facebook') }}" class="btn btn-facebook"><i class="fa fa-facebook"></i> Facebook</a>
        </div>
    </div>
</form>
[...]

The registration view should now look like this:

In the login view add this after Login button:

Resources/Views/Auth/login.blade.php

[...]
<form class="form-horizontal" role="form" method="POST" action="{{ url('/login') }}">
<!--Other form fields above the button-->
    <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-sign-in"></i> Login
            </button>
        </div>
    </div>
    <hr>
    <div class="form-group">
        <div class="col-md-6 col-md-offset-4">
            <a href="{{ url('/auth/github') }}" class="btn btn-github"><i class="fa fa-github"></i> Github</a>
            <a href="{{ url('/auth/twitter') }}" class="btn btn-twitter"><i class="fa fa-twitter"></i> Twitter</a>
            <a href="{{ url('/auth/facebook') }}" class="btn btn-facebook"><i class="fa fa-facebook"></i> Facebook</a>
        </div>
    </div>
</form>
[...]

The login view should now look like this:

And there you have it, users can now sign up with various social providers. Socialite is not limited to Twitter, Facebook and Github as it also supports LinkedIn, Google and Bitbucket. I hope the tutorial was helpful.

Christopher Vundi

Will code to travel. Will travel to code. Software developer at Andela