How to authenticate an already logged in facebook user with facebook api - codeigniter

I am using facebook login in my codeigniter application. I have set up the controller to handle the login and it seems like it's working on all user-state cases except when the user is logged into facebook and is trying to log into my application but has never authenticated it.
Here is my facebook controller index function:
$data=array(
'redirect_uri' => site_url('facebookcontroller/handle_facebook_login'),
'scope' => 'publish_stream,email'
);
redirect($this->fbconnect->getLoginUrl($data));
Does ->getLoginUrl() direct only to the facebook login page but not the authentication page?
I appreciate any help

It seems you are using an old version of the facebook sdk. I recommend taking a look here, as some of those functionalities are not working anymore.
then take into consideration that, when someone is logged into facebook and you ask for the profile info like this:
$data['user_profile'] = $profile = $this->facebook->api('/me');
It may be using an out of date access token, so you have to enclose that call in a try-catch block, like this:
try {
$data['user_profile'] = $profile = $this->facebook->api('/me');
}catch (Exception $e){
$this->facebook->setAccessToken($this->facebook->getAccessToken());
try {
if($this->facebook->getUser()) {
$this->facebook->api(array('method' =>'auth.revokeAuthorization' ));
}
}catch(Exception $e) {
redirect('<login controller>');
}
redirect('<login controller>');
}

Related

How to access Redirect Url of Paypal through

Using Paypal for payment it is working fine when I hit html form from a browser then It redirect's me to Paypal page for payment but on other side when I try to hit it from postman api then it gives error on postman as it is redirecting so my question is that how I would access that redirect or url of that redirect in Postman API?
I used this code
try {
$response = $this->gateway->purchase(array(
'amount' => $order_amount->total_price,
'currency' => env('PAYPAL_CURRENCY'),
'returnUrl' => url('success'),
'cancelUrl' => url('error'),
))->send();
if ($response->isRedirect()) {
$response->redirect(); // this will automatically forward the customer
} else {
// not successful
return $response->getMessage();
}
} catch (Exception $e) {
return $e->getMessage();
}
You cannot "access" redirect URLs from Postman, nor from any other automated system. The redirect URL mus be opened in a browser, and a payer account must sign in to give approval. On return from PayPal to the provided return_url, the ID of the order or payment will be in the URL. This should then be used to capture/execute it.
For best results, do not use any redirects. At all. Redirects returned by the API are for old websites, and should not be used by new integrations.
Instead, use the following approval flow from the payment page, which keeps your site loaded in the background (no redirect away): https://developer.paypal.com/demo/checkout/#/pattern/server
A full stack example in node can be found at: https://developer.paypal.com/docs/checkout/standard/integrate/ ; its backend can of course be implemented in PHP/laravel or any other web environment capable of returning the JSON from the API.

Do I need to store the FB access token on the backend in my Laravel Socialite+JWT and Ionic app?

I am slightly confused about the correct flow to Register and Login a user with cordova-plugin-facebook4 and Laravel Socialite + tymondesigns/jwt-auth. My front end is in Ionic 2 and the backend is in Laravel 5.4
My flow: (heavily borrowed from this blog post)
Using the cordova-plugin-facebook4 , perform a FB.login(). This returns the following json
{
status: "connected",
authResponse: {
session_key: true,
accessToken: "EAACgZAhHOaPsBAIjUUASeKSLnbEkashdkashdkhakdhakdh",
expiresIn: 5183979,
sig: "...",
secret: "...",
userID: "634565435"
}
}
Post the "accessToken" to http:///auth/facebook
Retrieve the user profile using the Socialite "userFromToken" method.
$profile = Socialite::driver('facebook')->userFromToken($token);
Check if the user exists in the DB.
IF it does create and return a new access token using JWTAuth
ELSE create a new user in the DB and return a new access token using JWTAuth
$provider = "facebook"
try{
$profile = Socialite::driver($provider)->userFromToken($token);
}
catch(Exception $exception)
{
return response()->json([
'error'=>'User retrieval failed from provider'
],401);
}
//Check if the user registered earlier with this provider.
try{
$existingUser = User::where('provider','=',$provider)
->where('provider_id','=',$profile->getId())
->firstOrFail();
//If user is found and no exception was raised
if ($existingUser)
{
return response()->json([
'token'=>JWTAuth::fromUser($existingUser),
'user'=>$existingUser
]);
}
}
catch (ModelNotFoundException $exception)
{
$user=new User();
$user->email=$profile->getEmail();
$user->name=$profile->getName();
$user->password=$this->random_password();
$user->provider=$provider;
$user->provider_id=$profile->getId();
$user->save();
return response()->json([
'token'=>JWTAuth::fromUser($user),
'user'=>$user
]);
}
My Confusion:
Are the "Login with Facebook" and "Register/Signup with Facebook" two exclusive functions? How would subsequent logins work for a mobile app after the user registers on Laravel the first time?
In Step 4 when I check if the user exists in the backend I'm querying the table on the "provider_id" returned by Socialite::driver($provider)->userFromToken($token)->getId(). I don't understand how this value is unique to a particular user.
In both cases for step 2 - a new JWT Auth token is created from the user and returned to the front end. I plan to save this token on the front end and use it for protected resource access. However, I'm not sure if I need to store the FB Access_Token in the DB and share it with the front end to be cached as well.
How will the login process work when the app is reopened. The user should be auto logged in but would this happen via Facebook, via Laravel Social or just the locally stored JWT?
Thanks
Sam

Using laravel socialite and jwt-auth without session

Short version: What would be the appropriate way to send the JWT generated from Facebook login (laravel/socialite) to the angularjs front end without using session.
Long Version
I am making an app that has angularjs front end and laravel 5.2 backend. I am using tymondesigns/jwt-auth for authentication instead of session.
I am also using laravel/socialite for social Facebook authentication. For that I am using the stateless feature of socialite so that I don't need session in any ways.
The basic authentication works perfectly. But, when I try to use Facebook login, I follow these steps
User clicks on a button on the angular side that redirects to the provider login page of the back end.
public function redirectToProvider() {
return Socialite::with('facebook')->stateless()->redirect();
}
2. User gives his login information. After logging in he is redirected to my handlecallback function.
try {
$provider = Socialite::with('facebook');
if ($request->has('code')) {
$user = $provider->stateless()->user();
}
} catch (Exception $e) {
return redirect('auth/facebook');
}
return $this->findOrCreateUser($user);
Next I use the findorcreate function to determine whether the user exists or not. If not than I just create a new user and create JWT from that.
$user = User::where('social_id', '=', $facebookUser->id)->first();
if (is_object($user)) {
$token = JWTAuth::fromUser($user);
return redirect()->to('http://localhost:9000/#/profile?' . 'token=' . $token);#angular
} else {
$result = array();
$result['name'] = $facebookUser->user['first_name']
$result['email'] = $facebookUser->user['email'];
$result['social_id'] = $facebookUser->id;
$result['avatar'] = $facebookUser->avatar;
$result['gender'] = $facebookUser->user['gender'];
$result['status'] = 'active';
$result['login_type'] = 'facebook';
$result['user_type'] = 'free_user';
try {
$user = User::create($result);
} catch (Exception $e) {
return response()->json(['error' => 'User already exists.'], HttpResponse::HTTP_CONFLICT);
}
$token = JWTAuth::fromUser($user);
return redirect()->to('http://localhost:9000/#/profile?' . 'token=' . $token);#angular
}
My problem is, in the last block of code I am having to send the jwt to my frontend via url. Which isn't secure at all. What would be the right way to send the generated JWT to the frontend without using session. Thank you
The official documentation of Laravel Socialite says:
Stateless Authentication
The stateless method may be used to disable session state verification. This is useful when adding social authentication to an API:
return Socialite::driver('google')->stateless()->user();
Then, you can authenticate using the jwt-auth method:
JWTAuth::fromUser($user)
If you're using $http on the Angular side, try returning the token as a JSON response from Laravel:
return response()->json(compact('token'));
Then store the token in localStorage or sessionStorage or what have you.
If you're generating your Angular page from within Laravel (i.e. not using Laravel as an API, but showing your Angular page from /public/index.php, for instance) you could load the view with the token in the data for the view.
As long as you're using HTTPS either of these two scenarios are better than passing the token in the redirect URL.
You can store token and use client side redirect without storing to browser history to redirect user to profile page without token in URL:
document.location.replace({profile-url})

Laravel 5 and Socialite - New Redirect After Login

Another newb question here, but hopefully someone can shed some light:
I am using Socialite with Laravel 5, and I want to be able to redirect the user to a page on the site after they have logged in. The problem is that using
return redirect('any-path-I-put-here');
simply redirects back to 'social-site/login?code=afkjadfkjdslkfjdlkfj...' (where 'social-site' is whatever site is being used i.e. facebook, twitter, google, etc.)
So, what appears to me to be happening is that the redirect() function in the Socialite/Contracts/Provider interface is overriding any redirect that I attempt after the fact.
Just for clarification, my routes are set up properly. I have tried every version of 'redirect' you can imagine ('to', 'back', 'intended', Redirect::, etc.), and the method is being called from my Auth Controller (though I have tried it elsewhere as well).
The question is, how do I override that redirect() once I am done storing and logging in the user with socialite? Any help is appreciated! Thank you in advance.
The code that contains the redirect in question is:
public function socialRedirect( $route, $status, $greeting, $user )
{
$this->auth->login( $user, true );
if( $status == 'new_user' ) {
// This is a new member. Make sure they see the welcome modal on redirect
\Session::flash( 'new_registration', true );
return redirect()->to( $route );// This is just the most recent attempt. It originated with return redirect($route);, and has been attempted every other way you can imagine as well (as mentioned above). Hardcoding (i.e., 'home') returns the exact same result. The socialite redirect always overrides anything that is put here.
}
else {
return redirect()->to( $route )->with( [ 'greeting' => $greeting ] );
}
}
... The SocialAuth class that runs before this, however, is about 500 lines long, as it has to determine if the user exists, register new users if necessary, show forms for different scenarios, etc. Meanwhile, here is the function that sends the information through from the Social Auth class:
private function socialLogin( $socialUser, $goto, $provider, $status, $controller )
{
if( is_null( $goto ) ) {
$goto = 'backlot/' . $socialUser->profile->custom_url;
}
if( $status == 'new_user' ) {
return $controller->socialRedirect($goto, $status, null, $socialUser);
}
else {
// This is an existing member. Show them the welcome back status message.
$message = 'You have successfully logged in with your ' .
ucfirst( $provider ) . ' credentials.';
$greeting =
flash()->success( 'Welcome back, ' . $socialUser->username . '. ' . $message );
return $controller->socialRedirect($goto, $status, $greeting, $socialUser);
}
}
I managed to workaround this problem, but I am unsure if this is the best way to fix it. Similar to what is stated in question, I got authenticated callback from the social media, but I was unable to redirect current response to another url.
Based on the callback request params, I was able to create and authenticate the user within my Laravel app. It worked good so far but the problems occured after this step when I tried to do a return redirect()->route('dashboard');. I tried all the flavours of redirect() helper and Redirect facade but nothing helped.
The blank page just stared at my face for over 2 days, before I checked this question. The behaviour was very similar. I got redirect from social-media to my app but could not further redirect in the same response cycle.
At this moment (when the callback was recieved by the app and user was authenticated), if I refreshed the page manually (F5), I got redirected to the intended page. My interpretation is similar to what's stated in this question earlier. The redirect from social-media callback was dominating the redirects I was triggering in my controller (May be redirect within Laravel app got suppressed because the redirect from social-media was still not complete). It's just my interpretation. Experts can throw more light if they think otherwise or have a better explaination.
To fix this I issued a raw http redirect using header("Location /dashboard"); and applied auth middleware to this route. This way I could mock the refresh functionality ,redirect to dashboard (or intended url) and check for authentication in my DashboardController.
Once again, this is not a perfect solution and I am investigating the actual root of the problem, but this might help you to move ahead if you are facing similar problem.
I believe you are overthinking this. Using Socialite is pretty straight forward:
Set up config/services.php. For facebook I have this:
'facebook' => [
'client_id' => 'your_fb_id',
'client_secret' => 'your_fb_secret',
'redirect' => '>ABSOLUTE< url to redirect after login', //like: 'http://stuff'
],
Then set up two routes, one for login and one for callback (after login).
In the login controller method:
return \Socialize::with('facebook')->redirect();
Then in the callback function
$fb_user = \Socialize::with('facebook')->user();
// check if user exists, create it and whatnot
//dd($fb_user);
return redirect()->route('some.route');
It should be pretty much similar for all other providers.
We are using the Socialite login in our UserController as a trait. We simply overrode the AuthenticatesSocialiteLogin::loginSuccess() in our controller.
use Broco\SocialiteLogin\Auth\AuthenticatesSocialiteLogin;
class UserController extends BaseController
{
use AuthenticatesSocialiteLogin;
public function loginSuccess($user)
{
return redirect()->intended(url('/#login-success'));
}
....

How to get Facebook user detail from Access Token using Codeigniter?

I'm really struggling to understand what's happening here. I can get a Users details fine in the OpenGraph tester or just hitting the URL https://graph.facebook.com/me?access_token=VALID_TOKEN or using file_get_contents, but when trying the Codeigniter Facebook Library I get error "An active access token must be used..." and if I just try a CURL GET I get no output. I know the access_token is valid so why aren't they working? The overall objective is to get an access_token from iOS App and use this to do a Like via the web server using og.likes.
My test function:
function me_test(){
$access_token = "VALID_TOKEN";
$url = 'https://graph.facebook.com/me?access_token=';
$url_full = $url.$access_token;
$result = file_get_contents($url_full);
echo $result;
// Try Codeigniter Facebook Library
try {
$user = $this->facebook->api('/me?access_token='.$access_token);
} catch (Exception $e) {
print_r($e);
}
// Codeigniter CURL Library
$this->load->library('curl');
echo $this->curl->simple_get($url_full);
$info = $this->curl->info;
print_r($info);
}
I have also faced this issue and find the alternate way to get userdata. You can try this
function me_test(){
$userId = $this->facebook->getUser(); //This will return the current user id
// Try Codeigniter Facebook Library
try {
$user = $this->facebook->api('/'.$userId);
//When you pass the userid you dont need to provide access token
} catch (Exception $e) {
print_r($e);
}
}

Resources