0
votes

Ok so I read how to implement Laravel socialite into my application so I can let users log in using Google or Facebook. I read how to do it here. The problem I encounter with this approach is that if a user logs in from say Google with email [email protected] then logs in from Facebook using [email protected] they are logging into the same account! Security issue right. So I thought that before I let them log in I would check the provider id which you can get, however when I try to compare the provider_id that I store in the database when they create the account with the provider_id stored in the socialite user variable I get this error:

Argument 1 passed to Illuminate\Auth\SessionGuard::login() must implement interface Illuminate\Contracts\Auth\Authenticatable, instance of Illuminate\Http\RedirectResponse given

Here is all the code I am using for Socialite:

<?php

namespace App\Http\Controllers;
use Socialite;
use App\User;
use Auth;
use Illuminate\Support\Facades\Redirect;
use Flash;
use Illuminate\Http\Request;
use App\Http\Requests;

class SocialiteController extends Controller
{

    public function redirectToProvider($provider)
    {
        return Socialite::driver($provider)->redirect();
    }

    public function handleProviderCallback($provider)
    {
        try
        {
            $social_user = Socialite::driver($provider)->user();
        }
        catch(Exception $e)
        {
             return Redirect::to('auth/' . $provider);
        }
        $authUser = $this->findOrCreateUser($social_user);
        Auth::login($authUser, true);
        flash()->overlay('You have been logged in successfully!', 'Congratulations');
        return Redirect::to('/');

    }
    //create a new user in our database or grab existing user
    private function findOrCreateUser($social_user)
    {
        if ($authUser = User::where('email', $social_user->email)->first()) {
            //this creates an error
            if($authUser->provider_id == $social_user->id)
                return $authUser;
            else
            {
                flash()->overlay('An account for that email already exists!', 'Error');
                return Redirect::to('/');
            }
        }


        return User::Create([
            'provider_id' => $social_user->id,
            'name' => $social_user->name,
            'email' => $social_user->email,
            'nickname' => $social_user->nickname,
            'avatar_img' => $social_user->avatar,
            'role_id' => 1, //set role to guest
            'social_login' => true //tell the database they are logging in from oauth

        ]);

    }
}
2

2 Answers

0
votes

The error message is actually self explained. When you do User::where('provider_id', $social_user->id) you end up with builder object that implements

Illuminate\Database\Eloquent\Builder.

You can call ->get() on it to get the collection of results (a collection of objects that implements

Illuminate\Contracts\Auth\Authenticatable

in your case, so you can iterate over them), or as you did, you can get the first match with ->first() (one object that implement

Illuminate\Contracts\Auth\Authenticatable).

You can read more in the Eloquent documentation.

The main point is that until you call ->get() or ->first() you are working with builder object. There is actually ->find() method also, that is used to retrieve record by pk, you cannot use it to search for records by constraints (where), but it also returns model object.

0
votes

The problem I encounter with this approach is that if a user logs in from say Google with email [email protected] then logs in from Facebook using [email protected] they are logging into the same account! Security issue right.

In my opinion, this is an incorrect assumption. It is not a security issue.

OAuth is used as an authentication delegation, if a user controls accounts in different providers with the same email, it simply means he has more 3rd party OAuth services with which to validate control of his identity (email)

I would consider it a bug, if you limited me to only be able to sign in with one OAuth provider, and prohibited me to user another one with the same email.