Introduction

One of the main goals in the modern web is to make the user experience as simple as possible, for instance instead of filling all those boring forms to complete a basic registration, the user can sign up with one simple click.

That's why most websites include social media authentication. We will be using both Laravel 5.6 and Socialite, you can the check the documentation for more details on : Socialite Docs Now let's say you have a website with 2 types of users: student and teacher. Each one with it's own register form. Based on the submitted form we know the user type and store it in the database, for the oauth api that would mean that for each one there is a separate method hence callback url from the provider. That's what i will demonstrate here : how to use social media provider with multiple callback url for each user.

Application Setup

Let's start by creating our application using


    Bashlaravel new SocialMediaAuth
 

If you started fresh like i did you will need to generate key for you application using


    Bashphp artisan key:generate
 

Database Migration

We will stick with the default 'User' model Now we need to customize our User table before we migrate it


    User Migrationpublic function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('firstName');
            $table->string('lastName');
            $table->string('type');
            $table->string('email')->unique();
            $table->string('password')->nullable();
            $table->string('provider');
            $table->string('provider_id');
            $table->rememberToken();
            $table->timestamps();
        });
    }
    

next go ahead to .env file and enter your database credentials


    .envDB_CONNECTION=mysql
    DB_HOST=127.0.0.1
    DB_PORT=3306
    DB_DATABASE=SocialMediaAuth
    DB_USERNAME=root
    DB_PASSWORD=123
    

Now that everything is setup we can go ahead and migrate to our database


    Bashphp artisan migrate
 

Models Setup

After setting up the migration we must include the attributes in the mass assignments array in our User model


    User.phpprotected $fillable = [
        'firstName', 'lastName', 'type', 'email', 'password', 'provider', 'provider_id',
    ];
    

Including Socialite

Obvoiusly we need to require the package to work with it, if you're using laravel 5.6 all you need to do is run this command in your CLI


    Bashcomposer require laravel/socialite
 

In terms of providers we'll use google and facebook, feel free to use any other provider they're all pretty much the same, just make sure they support multiple callback url's for example GitHub oauth doesn't support that, for the others you should be good to go. Now add the credentials for the OAuth services in our config/services.php file


    config/services.php'facebook' => [
        'client_id' => env('FACEBOOK_CLIENT_ID'),
        'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
        'redirect' => env('FACEBOOK_CALLBACK_STUDENT'),
    ],
    'google' => [
        'client_id' => env('GOOGLE_CLIENT_ID'),
        'client_secret' => env('GOOGLE_CLIENT_SECRET'),
        'redirect' => env('GOOGLE_CALLBACK_STUDENT'),
    ],
    

By default we 'll set the student callback as the the one by default, later we'll change depending on the submitted form. We must now set the keys that we obtain after creating the app in the .env file, make sure the name is the same as the one in services.php file.


    .envFACEBOOK_CLIENT_ID={{API Key}}
    FACEBOOK_CLIENT_SECRET={{API secret}}
    FACEBOOK_CALLBACK_STUDENT={{API CALLBACK URL FOR STUDENT}}
    FACEBOOK_CALLBACK_TEACHER={{API CALLBACK URL FOR TEACHER}}
         
    GOOGLE_CLIENT_ID={{API Key}}
    GOOGLE_CLIENT_SECRET={{API secret}}
    GOOGLE_CALLBACK_STUDENT={{API CALLBACK URL FOR STUDENT}}
    GOOGLE_CALLBACK_TEACHER={{API CALLBACK URL FOR TEACHER}}
    

as you can see here and as I explained before for each provider there is 2 callback url one for student and the other one for teacher. The callback url should be something similar to : http://localhost:8000/{user_type}/{provider_type}/callback

Creating Social Media Api

In order to obtain an api key and secret you need to go and create a new application one for Facebook and another for Google+ API it's pretty straight forward, first create a project then select the type of application you want to integrate after that fill out the form then get the keys and past them in your .env file

Routing

Now we will cover our entire application routing system as you can see in the code snippet down below we will have : - home page where we can navigate our application - Sign Up form for each type of users - Redirection link to the provider based on each user type - Callback URL from the provider.


    web.phpRoute::view('/', 'welcome');
    Route::view('register-teacher', 'register_teacher');
    Route::post('register-teacher', 'AuthController@registerTeacherStore');
    Route::view('register-student', 'register_student');
    Route::post('register-student', 'AuthController@registerStudentStore');
    Route::get('oauth/{type}/{provider}', 'AuthController@RedirectToProvider');
    Route::get('{type}/{provider}/callback', 'AuthController@ProviderCallback');
    Route::get('users', 'AuthController@usersDisplay');
    

Authenticationn Medthod Controller

Let's make the AuthController that will contain our authentication methods


    Bashphp artisan make:controller AuthController
 

Then we must inclue the User model and Socialite in order to use them in the controller methods


    AuthController.phpuse App\User;
    use Socialite;
    

First let's cover the normal form registration for both users


    AuthController.phppublic function registerTeacherStore()
    {
        $this->validate(request(),[
            'firstName' => 'required|string',
            'lastName' => 'required|string',
            'email' => 'required|email|unique:users,email',
            'password' => 'required|string',
        ]);

        User::create([
            'firstName' => request('firstName'),
            'lastName' => request('lastName'),
            'type' => 'Teacher',
            'email' => request('email'),
            'password' => bcrypt(request('password')),
            'provider' => 'Email'
        ]);

        session()->flash('message','Registration Complete !');

        return redirect('users');
    }

    public function registerStudentStore()
    {
        $this->validate(request(),[
            'firstName' => 'required|string',
            'lastName' => 'required|string',
            'email' => 'required|email|unique:users,email',
            'password' => 'required|string',
        ]);

        User::create([
            'firstName' => request('firstName'),
            'lastName' => request('lastName'),
            'type' => 'Student',
            'email' => request('email'),
            'password' => bcrypt(request('password')),
            'provider' => 'Email'
        ]);

        session()->flash('message','Registration Complete !');

        return redirect('users');
    }
    

Here we have the methods that'll be called after the form is submitted for each user type, first we include basic input validation, followed by storing the data in the DB after that we use session()->flash for some user feedback and then we redirect to the users page where we have all users listed.


    AuthController.phppublic function changeCallbackUrl($type, $provider)
    {
        if($type == 'student')
        {
            switch ($provider) 
            {
                case 'google':
                    $redirectUrl = env('GOOGLE_CALLBACK_STUDENT');
                    break;
                
                case 'facebook':				
                    $redirectUrl = env('FACEBOOK_CALLBACK_STUDENT');
                    break;
            }
        }

        if($type == 'teacher')
        {
            switch ($provider) 
            {
                case 'google':
                    $redirectUrl = env('GOOGLE_CALLBACK_TEACHER');
                    break;
                
                case 'facebook':				
                    $redirectUrl = env('FACEBOOK_CALLBACK_TEACHER');
                    break;
            }
        }
        
        return $redirectUrl;
    }
    

The changeCallbackUrl method takes 2 parameters the type (user or student) and the name of the provider in this case (google or facebook) then it returns the redirectUrl for each case. Note that we've already specified the callback url for each situation in the .env file.

        
    AuthController.phppublic function RedirectToProvider($type, $provider)
    {
        $redirectUrl = $this->changeCallbackUrl($type, $provider);
        return Socialite::with($provider)->redirectUrl($redirectUrl)->redirect();
    }
    

    AuthController.phppublic function ProviderCallback($type,$provider)
    {
        $redirectUrl = $this->changeCallbackUrl($type, $provider);

        config(["services.$provider.redirect" => $redirectUrl]);

        $allowedTypes = array('student','teacher');

        if(in_array($type, $allowedTypes))
        {
            try
            {
                $user = Socialite::driver($provider)->stateless()->user();
        
                $userDB = User::where('email', $user->email)->first();

                if(!$userDB) 
                {
                    if($provider === 'google')
                    {
                        $lastName = $user->user['name']['familyName'];
                        $firstName = $user->user['name']['givenName'];
                    }
                    if($provider === 'facebook')
                    {
                        $lastName = $user->user['name']['lastName'];
                        $firstName = $user->user['name']['firstName'];
                    }

                    User::create([
                        'firstName' => $firstName,
                        'lastName' => $lastName,
                        'type' => $type,
                        'email' => $user->email,
                        'provider' => $provider,
                        'provider_id' 	 => $user->id,
                    ]);

                    session()->flash('message','Registration Complete !');
                }
                else
                {
                    session()->flash('error','user already exists');
                }

                return redirect('users');
            
            } 
            catch (\Exception $e) 
            {
                return redirect('/');
            }
        }
        else
        {
            return redirect('/');
        }
    }
    

Now as mentionned in the route web.php file the callback URL's structure can be similar to : http://localhost:8000/student/google/callback In order to a avoid mismatch error in our provider we need to change the redirect URL in the services.php file so that it would match the one used in the provider API. That's why we use again the changeCallbackUrl method so that it will assign the callback url based on the user type and provider. Then we created an array of allowed users and run a check if the user type returned from the provider exists in that array (just to avoid any sort of error or inserting a wrong type of users) once it's done we retrieve the user's information from the provider, after that we use $userDB to check if any user with similar email address exists in our database if it doesn't we go ahead and store it, if it does we redirect with an error message of course here you can try something else like log In the user directly.

        
    AuthController.phppublic function usersDisplay()
    {
        $users = User::all();
        return view('users',compact('users'));
    }
    

The usersDisplay method lists the users stored in the database.

View Page Forms

   
        register_student.blade.php<div>
            <a class="socialMediaLink" href="{{url('oauth/student/facebook')}}"><i class="fab fa-facebook-f"></i> Facebook</a>

            <a class="socialMediaLink" href="{{url('oauth/student/google')}}"><i class="fab fa-google-plus-g"></i> Google</a>
        </div>

        <form action="{{url('register-student')}}" method="post">
            
            {{ csrf_field() }}

            <div>
                <label for="firstName">First Name</label>
                <input type="text" name="firstName">
            </div>

            <div>
                <label for="lastName">Last Name</label>
                <input type="text" name="lastName">
            </div>

            <div>
                <label for="email">Email</label>
                <input type="email" name="email">
            </div>

            <div>
                <label for="password">Password</label>
                <input type="password" name="password">
            </div>

            <div>
                <input type="submit" value="Register">
            </div>

        </form>
    
   
        register_teacher.blade.php<div>
            <a class="socialMediaLink" href="{{url('oauth/teacher/facebook')}}"><i class="fab fa-facebook-f"></i> Facebook</a>

            <a class="socialMediaLink" href="{{url('oauth/teacher/google')}}"><i class="fab fa-google-plus-g"></i> Google</a>
        </div>

        <form action="{{url('register-teacher')}}" method="post">
            
            {{ csrf_field() }}

            <div>
                <label for="firstName">First Name</label>
                <input type="text" name="firstName">
            </div>

            <div>
                <label for="lastName">Last Name</label>
                <input type="text" name="lastName">
            </div>

            <div>
                <label for="email">Email</label>
                <input type="email" name="email">
            </div>

            <div>
                <label for="password">Password</label>
                <input type="password" name="password">
            </div>

            <div>
                <input type="submit" value="Register">
            </div>

        </form>
    

Here we have both registration forms. In the top div we have the link that will redirect to the social media provider for each user there is 2 links one for google and another for facebook as explained previously


         users.blade.php<div>
             <table>
                 <thead>
                     <th>First Name </th>
                     <th>Last Name </th>
                     <th>Type </th>
                     <th>Email </th>
                     <th>Provider </th>
                     <th>Creation Date </th>
                 </thead>
                 <tbody>
                    @foreach ($users as $user)
                         <tr>
                             <td> {{$user->firstName}} </td>
                             <td> {{$user->lastName}} </td>
                             <td> class="capitelize">{{$user->type}} </td>
                             <td> {{$user->email}} </td>
                             <td> class="capitelize">{{$user->provider}} </td>
                             <td> {{$user->created_at->format('d/m/Y')}} </td>
                         </tr>
                    @endforeach
                 </tbody>
             </table>
         </div>
    

The table were we display our users, we also include the provider type to know which provider is used by each user.

Screenshots

Social Media Auth – Home Page
Home Page

 

Social Media Auth – Student Form
Student Form

 

Social Media Auth – Teacher Form
Teacher Form

 

Social Media Auth – Users List
Users List

Source Code

That's all folks ! if you want to access the source code feel free to clone the project from Github. And of course if you need help with the code don't hesitate just drop a comment and i will reply asap.