I want to give users the opportunity to login/register via social login (like Facebook or Google). In order to do this I am using the package Socialite provided by Laravel.
I also give the users the opportunity to register by email and password. When doing so they have to choose a username as well. So far so good. Here is no problem because when the user gets created he has submitted a username, a email address and a password.
However, when doing this via social login the user has not chosen a username. I just get the name of the user from Google or Facebook but that's not what I want. I want the user to choose a username/nickname.
The problem is that the username is not nullable because I am using implicit binding on my username for the user model.
Right now I am bypassing this problem by putting the email, provider and provider_id I get from the social login in the user session. Whenever the user session contains those 3 parameters I show a form to the user where he has to choose a username. When submitting the form the user gets created by the username provided from the form and the email, provider and provider_id from the session.
Another possible solution is to make username nullable in the database and store the email, provider and provider_id right away when doing the social login and setting the username to null. This would solve the problem of having a session conflict but I would have a empty username in my database which would lead to many other problems as username is my key for the implicit route binding. I don't really favor this solution too but it is one possible solution.
My question to you is now what better way to do this is there? My favorite way would be to pass the email, provider and provider_id to the ProductController@index` as PHP variables because they cannot be manipulated! However, I haven't found any solution on how to do this except doing this via sessions.
Here is my sourcecode so far:
SocialLoginController
class SocialLoginController extends Controller
{
public function redirect($provider)
{
return Socialite::driver($provider)->redirect();
}
public function callback($provider)
{
$getInfo = Socialite::driver($provider)->user();
$user = $this->userExists($getInfo);
if(!$user){
$user = array();
$user['email'] = $getInfo->email;
$user['provider'] = $provider;
$user['provider_id'] = $getInfo->id;
$user['avatar'] = $getInfo->avatar_original;
Session::put('user', $user);
return redirect()->to(route('home'));
}
auth()->login($user);
return redirect()->to(route('product.index'));
}
function createUser(SocialRegisterUserRequest $request)
{
//TODO: Avatar
//TODO: Username
$userSession = Session::get('user');
$user = User::create([
'name' => $request->name,
'email' => $userSession['email'],
'email_verified_at' => date('Y-m-d H:i:s'),
'provider' => $userSession['provider'],
'provider_id' => $userSession['provider_id']
]);
Session::flash('user');
auth()->login($user);
return redirect()->to(route('product.index'));
}
}
web.php (routes)
Route::get('/auth/redirect/{provider}', 'SocialLoginController@redirect');
Route::get('/callback/{provider}', 'SocialLoginController@callback');
Route::post('/social/register', ['as' => 'social.register', 'uses' => 'SocialLoginController@createUser']);
Some explanation for you:
When doing a social login the user calls the route SocialLoginController@redirect. This passes to request to the redirect function. When the user has approved the social login for my app on Facebook or Google he will be redirected to the callback function. Here he checks if the user already exists. If so, he gets logged in if not the data are put into the session. Now the form for choosing a username will be shown to the user. When he submits this form he will be routed to the createUser function which then finally creates the user.
Any ideas on how to do this in a better way?
I am grateful for any kind of help!
Kind regards