I am using socialite to integrate the login with Facebook function. Here is my code:
public function handleProviderCallback()
{
try {
$socialUser = Socialite::driver('facebook')->user();
} catch (\Exception $e) {
return redirect('/dashboard');
}
/*section1 : i check if the user exists in the db, and if no then
I save this user in the db */
$user = User::where('facebook_id', $socialUser->getId())->first();
if (!$user) {
User::create([
'facebook_id' => $socialUser->getId(),
'name' => $socialUser->getName(),
'email' => $socialUser->getEmail(),
]);
Auth::loginUsingId($socialUser->id);
return redirect()->intended('/dashboard');
}
/* end of section one */
else{
if(Auth::loginUsingId($user->id)){
return redirect()->intended('/dashboard');
}
}
}
The problem is: I login with a new user, the data is added to the database and I am redirected to the dashboard, but I am not logged in. After I try logging in again (when the user already exists in the database) I am successfully logged in. Why? Thanks!
The issue is with following line. You have to pass the user id in the database, not the Facebook id.
Auth::loginUsingId($socialUser->id);
Update as following
$newUser = User::create(...);
Auth::loginUsingId($newUser->id);
Related
I am trying to set up login with Google using Laravel and socialite. I've set everything up to go to the Google login page and redirect me back to the application. However, when I'm redirected I always end up on the "login" page and not the "home" page. After successfully logging in with Google I'm not logged into my Laravel app. What is wrong?
/**
* Obtain the user information from Google.
*
* #return \Illuminate\Http\Response
*/
public function handleProviderCallback()
{
try {
$user = Socialite::driver('google')->user();
} catch (\Exception $e) {
return redirect('/login');
}
// check if they're an existing user
$existingUser = User::where('email', $user->email)->first();
if($existingUser){
// log them in
auth()->login($existingUser, true);
} else {
// create a new user
$newUser = new User;
$newUser->name = $user->name;
$newUser->email = $user->email;
$newUser->google_id = $user->id;
$newUser->avatar = $user->avatar;
$newUser->avatar_original = $user->avatar_original;
$newUser->save();
auth()->login($newUser, true);
}
return redirect()->to('/home');
}
Despite the calls to login a user I am not logged in when redirected back to the app. How can I make sure that after logging in with Google I'm logged in to the Laravel app?
Update
It turns out when the $user variable comes back from Google I am getting a InvalidStateException
The try catch block actually throws an exception. If I dd the exception it looks like:
It turns out what was breaking it for me was in my .env file I had:
SESSION_DOMAIN=http://localhost:8000
Removing this line fixed the issue!
Remove SESSION_DOMAIN from your .env file
How to force the user to fill the form after login with google or facebook. I ma using laravel 5.4 with socials. In my app i want to allow google and facebook login but user can create a standard user too. When login with one of the social providers (facebook or google) i want the user to fill other fields in the form to complete the registration.
The handleProviderCallback:
public function handleProviderCallback($provider)
{
try{
$socialUser = Socialite::driver($provider)->stateless()->user();
}catch (Exception $e){
return redirect('/');
}
// check if we have logged PROVIDER
$socialProvider = Social::where('provider_id', $socialUser->getId())->first();
// if we don`t have a provider create a user and provider
if(!$socialProvider){
// i want the user to go back in the form and finish the registration
return view('auth.socials')->with('socialUser', $socialUser)->with('provider', $provider);
}
else{
// return the user
$user = $socialProvider->user;
}
// log the user in our app :)
auth()->login($user);
return redirect('/home');
the problem is when submiting the form i get an exception:
Client error: `POST https://accounts.google.com/o/oauth2/token` resulted in
a `400 Bad Request` response:
{
"error" : "invalid_grant",
"error_description" : "Invalid code."
}
If i use the method handleProviderCallback like this:
public function handleProviderCallback($provider)
{
try{
$socialUser = Socialite::driver($provider)->stateless()->user();
}catch (Exception $e){
return redirect('/');
}
// check if we have logged PROVIDER
$socialProvider = Social::where('provider_id', $socialUser->getId())->first();
// if we don`t have a provider create a user and provider
if(!$socialProvider){
$user = User::firstOrCreate(
['email' => $socialUser->getEmail()],
// i have to manualy add the missing fields
['name' => $socialUser->getName(), 'forename' => 'test', 'password' => '' ,'address' => 'adasda', 'country' => 'asasfasf', 'town' => 'asfasfsfsfs', 'legal_person' => '0', 'newsletter' => '1', 'phone' => '1235241521']
);
// add provider for this user
$user->socials()->create(
['provider_id' => $socialUser->getId(), 'provider' => $provider]
);
}
else{
// return the user
$user = $socialProvider->user;
}
// log the user in our app :)
auth()->login($user);
return redirect('/home');
}
the user get logged in, but as you can see i have to manually insert the missing fields in the firstOrCreate method (which are required in the users table)
Any suggestion how to do this?
I have a Laravel 5 web app with Socialite to login my user by using Facebook account.
This is my callback function:
public function callback(SocialAccountService $service)
{
$user = $service->createOrGetUser(Socialite::driver('facebook')->user());
auth()->login($user);
return redirect()->to('/home');
}
This is my SocialAccountService, basically the function returns the user if existing or creates a new one:
class SocialAccountService
{
public function createOrGetUser(ProviderUser $providerUser)
{
$account = SocialAccount::whereProvider('facebook')
->whereProviderUserId($providerUser->getId())
->first();
if ($account) {
return $account->user;
} else {
$account = new SocialAccount([
'provider_user_id' => $providerUser->getId(),
'provider' => 'facebook'
]);
$user = User::whereEmail($providerUser->getEmail())->first();
if (!$user) {
$user = User::create([
'email' => $providerUser->getEmail(),
'name' => $providerUser->getName(),
]);
}
$account->user()->associate($user);
$account->save();
return $user;
}
}
}
Now the problem is, I am able to make my user login successfully via Facebook, but when the user clicks Cancel on the FB dialog for permission, it breaks.
How can I handle this error? I can see the error message in URL box, but don't know to handle them.
P.S I am fairly new to Laravel and Socialite
in the callback(...) method you can check for presense of the 'code' input field and if it is not there redirect to back to login page with errors.
Example:
function callback(SocialAccountService $service ,Request $request) {
if (! $request->input('code')) {
return redirect('login')->withErrors('Login failed: '.$request->input('error').' - '.$request->input('error_reason'));
}
// rest of your code
}
Try catch is the best practice(it catches all exception)
try
{
$userSocial =Socialite::driver('facebook')
->stateless()->user();
dd($userSocial);
}
catch (\Throwable $e) {
//handle error here for php 7 or 8
} catch (\Exception $e) {
// for php 5
handle error here
}
I have asked this question already but still I didn't get an answer.
How to login using Github, Facebook, Gmail and Twitter in Laravel 5.1?
auth not working
I am able to store data from gmail, github in the database.
Controller
if (Auth::attempt(['email' => $email, 'password' => $user_id]))
{
return redirect()->intended('user/UserDashboard');
}
else
{
//here i am going to insert if user not logged in already
return redirect()->intended('user/UserDashboard');
}
My problem is if I echo any data instead of return redirect()->intended('user/UserDashboard'); then it displays. If I add redirect then it doesn't work.
I'm not entirely sure how it works when using google for oAuth, but I assume your desired flow is:
User returns from google.
Check if user already exists, otherwise create new user record.
Log user in.
Redirect to dashboard.
Assuming the above your methods would look something like this.
Controller
public function google()
{
// Redirect user to google for authentication
return Socialite::driver('google')->redirect();
// In Laravel 5.0 this would be
// return Socialize::with('google')->redirect();
}
public function googleCallback()
{
// Return from google with user object
$googleUser = Socialite::driver('google')->user();
// In Laravel 5.0 the above would be
// $user = Socialize::with('google')->user();
// If user exists, retrieve the first() record,
// otherwise create a new record
$user = User::firstOrCreate([
'user_id' => $googleUser->id,
'name' => $googleUser->name,
'password' => $googleUser->id,
'email' => $googleUser->email,
'avatar' => $googleUser->avatar
]);
// Login the user
Auth::login($user, true);
// Redirect to the dashboard
return Redirect::intended('user/UserDashboard');
}
After reading: http://laravel.com/docs/5.0/authentication I was able to retrieve the user details from the OAuth provider (Facebook) using Socialite:
$user->getNickname();
$user->getName();
$user->getEmail();
$user->getAvatar();
But I couldn't find any further documentation on how to save the user in the database or log the user in.
I want to do the equivalent to:
Auth::attempt(['email' => $email, 'password' => $password])
But for the details retrieved via Socialite (I don't have a password)
Can you please show me an example on using "Auth" with user data retrieved via Socialite?
Add to "users" table new column: facebook_user_id. Every time when user tries to login through Facebook, Facebook will return the same user id.
public function handleProviderCallback($provider)
{
$socialize_user = Socialize::with($provider)->user();
$facebook_user_id = $socialize_user->getId(); // unique facebook user id
$user = User::where('facebook_user_id', $facebook_user_id)->first();
// register (if no user)
if (!$user) {
$user = new User;
$user->facebook_id = $facebook_user_id;
$user->save();
}
// login
Auth::loginUsingId($user->id);
return redirect('/');
}
How Laravel Socialite works?
public function redirectToProvider()
{
// 1. with this method you redirect user to facebook, twitter... to get permission to use user data
return Socialize::with('github')->redirect();
}
public function handleProviderCallback()
{
// 2. facebook, twitter... redirects user here, where you write code to log in user
$user = Socialize::with('github')->user();
}