Laravel Google Auth using artdarek/ oauth-4-laravel - php

I'm using the Artdarek package to log in using google accounts and need to authorise the user for the app.
I'm using Laravel 4.2
This is the code from my function
public function loginWithGoogle() {
// get data from input
$code = Input::get( 'code' );
// get google service
$googleService = OAuth::consumer( 'Google' );
// check if code is valid
// if code is provided get user data and sign in
if ( !empty( $code ) ) {
// This was a callback request from google, get the token
$token = $googleService->requestAccessToken( $code );
// Send a request with it
$result = json_decode( $googleService->request( 'https://www.googleapis.com/oauth2/v1/userinfo' ), true );
// Check to see if user already exists
if($user = User::where('email', '=', $result['email'])->first())
{
$user = User::find($user['id']);
Auth::login($user);
// If user isn't activated redirect them
if ($user->deactivated == 0)
{
return View::make('dashboard')->with('user', $user);
}
return Redirect::back()->withErrors(['Sorry You have not been approved', 'Speak to your manager']);
}
else
{
// Create new user waiting for approval
$new_user = new User();
$new_user->email = $result['email'];
$new_user->first_name = $result['given_name'];
$new_user->surname = $result['family_name'];
$new_user->googleID = $result['id'];
$new_user->deactivated = 1;
$new_user->save();
return Redirect::back()->withErrors(['Your account have been created. It is awaiting activation by your manager']);
}
}
// if not ask for permission first
else {
// get googleService authorization
$url = $googleService->getAuthorizationUri();
// return to google login url
return Redirect::to( (string)$url );
}
}
When a new user grants permission for the app, I get the error 'Cannot redirect to an empty URL'
For some reason my redirectURL is empty.

Take a look at document you will find out that you have to set redirect url at 2nd arguments in OAuth::consumer method.
https://github.com/artdarek/oauth-4-laravel#usage
It means, you should use consumer with 2 arguments instead of 1 arguments
$googleService = OAuth::consumer("google","https://mydirectlink");

Related

Google always returns false verifying id token

I have the next code, got directly from google reference (https://developers.google.com/identity/sign-in/web/backend-auth)
public function verifyFromAndroid($idToken=null) {
if(empty($idToken)) {
$idToken = self::SAMPLE_ID_TOKEN;
}
$client = new Google_Client(['client_id' => self::CLIENT_ID]);
$payload = $client->verifyIdToken($idToken);
if ($payload) {
print_r($payload);
$userid = $payload['sub'];
// If request specified a G Suite domain:
//$domain = $payload['hd'];
} else {
var_dump($payload);
$this->lastError = "Invalid ID token";
return false;
}
}
But this method always returns false, even using a valid id token that is created and working using the oauthplayground online tool.
The next code works fine, using directly the GoogleAccessToken_Verify class. Can someone tell me why the official Google code doesn't work and yes my own code using the official Google-clien-php sdk?
try {
$verify = new Google_AccessToken_Verify();
$result = $verify->verifyIdToken($this->idToken);
if($result) {
print_r($result);
$friendlyData = $this->translateData($result, true);
if(!$friendlyData) {
return false;
}
return $friendlyData;
}
else {
$this->lastError = "Invalid token verification, no error code";
return false;
}
}
catch(UnexpectedValueException $ex) {
$this->lastError = "UnVaEx (Code {$ex->getCode()}): {$ex->getMessage()}";
return false;
}
try adding complete client ID
xxxxxxxxxxxxxx-xxxxx-yy-zz.apps.googleusercontent.com
while initiating the
$client = new Google_Client(['client_id' => self::CLIENT_ID]);
It should work i was also facing the same issue ...
Had a similar issue.Deleted my android app on firebase console and created a fresh app wirh debug key sha1.Then downloaded and replaced my google.json into my app.This fixed my issue.This has happened to me twice now. At times you just need to recreate the android app on firebase console.
Before you begin register your backend URL at https://developers.google.com/identity/sign-in/web/sign-in with Configure your project button and don't use any credidentials or api key in your code. After doing them your code should look like to this.
public function verifyFromAndroid($idToken=null) {
if(empty($idToken)) {
$idToken = self::SAMPLE_ID_TOKEN;
}
//As you notice we don't use any key as a parameters in Google_Client() API function
$client = new Google_Client();
$payload = $client->verifyIdToken($idToken);
if ($payload) {
print_r($payload);
$userid = $payload['sub'];
// If request specified a G Suite domain:
//$domain = $payload['hd'];
} else {
var_dump($payload);
$this->lastError = "Invalid ID token";
return false;
}
}
I hope it helps.
I faced the same issue. After checking different PHP versions, I found that the google client library is working in PHP7.4 but not with PHP8.0.
Please try the below code after downgrading the version of PHP to 7.4
require_once 'vendor/autoload.php';
$id_token = $_POST['credential'];
$client = new Google_Client(['client_id' => $CLIENT_ID]); // Specify the CLIENT_ID of the app that accesses the backend
$payload = $client->verifyIdToken($id_token);
if ($payload) {
$userid = $payload['sub'];
// If request specified a G Suite domain:
//$domain = $payload['hd'];
} else {
// Invalid ID token
}
Or For development and debugging, you can call google oauth2 tokeninfo validation endpoint.
https://oauth2.googleapis.com/tokeninfo?id_token=$id_token

Facebook PHP SDK: Check if a user has granted a certain set of permissions

I want to check that a user has authorized the following permissions; 'manage_pages', 'publish_pages', 'read_insights', for my app. In short, if they decline one or more permissions, I need to know, as all are required.
Here's my callback method once I get the user's access token. How do I verify they approved all permission requests?
Note: I'm using the SammyK Laravel Facebook SDK package.
public function handleFacebookCallback()
{
try {
$token = Facebook::getAccessTokenFromRedirect();
$user = Facebook::get('/me?fields=permissions', $token)->getGraphUser();
$permissions = $user['permissions']->asArray();
// permissions: 'manage_pages', 'publish_pages', 'read_insights'
if (array_key_exists('publish_pages', $permissions['data'][0]))
{
// permissions exist, proceed
}
else
{
// user denied permission(s), redirect
}
}
....
According to Facebook Graph API you can call user/permissions to get all the permissions that user has granted to application.
$request = new FacebookRequest(
$session,
'GET',
'/me/permissions'
);
$response = $request->execute();
$graphObject = $response->getGraphObject();
/* handle the result */
foreach($graphObject as $permission) {
if($permission->permission == 'publish_pages' AND $permission->status == 'granted') {
// User has granted publish_pages permission
}
}
You can debug this call here, I've not tested it but it should work.
Not sure if this is the slickest answer or how others would approach this, but here's what I came up with...
try {
$token = Facebook::getAccessTokenFromRedirect();
$request = Facebook::get('/me?fields=permissions', $token);
$user = $request->getGraphUser();
$permissions = $user['permissions'];
// if user denied ANY of the required permissions
foreach ($permissions as $p => $permission)
{
if ($permission['status'] !== 'granted')
{
return redirect()->route('connect.index')->withErrors('Error: We require all permissions in order to connect your Facebook page.');
}
}
}

Laravel Token Signature could not be verified

I'm using Laravel/Lumen as an API for the backend of a webapp and run into a hiccup.
In an example I have a route that does not need the user to be authenticated. But I do want to check in the routes controller if the user visiting has a valid token.
So I wrote the following:
if ($tokenFetch = JWTAuth::parseToken()->authenticate()) {
$token = str_replace("Bearer ", "", $request->header('Authorization'));
} else {
$token = '';
}
I believe the above will check the Bearer token is valid else it will return a blank variable.
The following is my entire Controller.
public function show($url, Request $request)
{
if ($tokenFetch = JWTAuth::parseToken()->authenticate()) {
$token = str_replace("Bearer ", "", $request->header('Authorization'));
} else {
$token = 'book';
}
return response()->json(['token' => $token]);
}
The Problem
If I a pass in a valid Token Bearer, it returns the token but if I pass in an invalid one I get the following error:
TokenInvalidException in NamshiAdapter.php line 62:
Token Signature could not be verified.
If I don't pass a token at all:
JWTException in JWTAuth.php line 195:
The token could not be parsed from the request
Is there a way to check if a token is passed and if it has then check if its valid, but also if one has not been passed then return a blank return?
You can wrap it inside try/catch block
public function show($url, Request $request)
{
try {
$tokenFetch = JWTAuth::parseToken()->authenticate())
$token = str_replace("Bearer ", "", $request->header('Authorization'));
}catch(\Tymon\JWTAuth\Exceptions\JWTException $e){//general JWT exception
$token = 'book';
}
return response()->json(['token' => $token]);
}
There are few exceptions that you might want to handle separately (jwt-auth/Exceptions)
Also as you're using laravel 5 you can global handling for JWT exceptions ,not recommended in this case but you should know of this option and choose yourself. app/Exceptions/Handler.php and inside render method add [at the top]
if ($e instanceof \Tymon\JWTAuth\Exceptions\JWTException) {
//what happen when JWT exception occurs
}
Yes it's possible to achieve what you want.
Check if a token is passed:
If you check in the documentation of parseToken you'll see that the algorithm to check if we pass a token is:
if (! $token = $this->parseAuthHeader($header, $method)) {
if (! $token = $this->request->query($query, false)) {
}
}
// which it will be in your case:
$hasToken = true;
$header = $request->headers->get('authorization');
if (! starts_with(strtolower('authorization'), 'bearer')) {
if (! $request->query('token', false)) {
$hasToken = false;
}
}
Check if a token is valid:
Please note that the NamshiAdapter use the Namshi\JOSE package so read the documentation here.
In NamshiAdapter.php as you can see the line who rise your error are:
if (! $jws->verify($this->secret, $this->algo)) {
throw new TokenInvalidException('Token Signature could not be verified.');
}
// in your case:
// + try to var_dump $this->secret, $this->algo
// + use Namshi\JOSE\JWS
// if you var_dump
$jsw = new JWS(['typ' => 'JWT', 'alg' => $algo]);
$jws = $this->jws->load($token, false);
// if you want to follow the documentation of Namshi\JOSE
$jws = JWS::load($tokenString, false, $encoder, 'SecLib');
// again var_dump for $this->secret, $this->algo
$isValidToken = ($jws->verify($this->secret, $this->algo));

Requesting facebook permissions on tab page in PHP

I am having one facebook pagetab application and I am stuck in following situation
I need to check if user login or not
if not then redirect to login url with user_likes,publish_actions,email permissions
and also user has liked page or not.
if not liked then show the like gate
Now in above I am stuck following error which I am getting in FB pagetab (iFRAM)
Refused to display 'https://www.facebook.com/v2.0/dialog/oauth?client_id=839424369402407&redire…c8682d9a9fb5b&sdk=php-sdk-4.0.9&scope=email%2Cuser_likes%2Cpublish_actions' in a frame because it set 'X-Frame-Options' to 'DENY'.
Now I am think to implement the flow with JS sdk, get the access token and then pass it to php code using ajax call
Is there any better way to solve this situation??
here is the code
try {
$session = $helper->getSessionFromRedirect();
} catch(FacebookRequestException $ex) {
error_log($ex->getCode());
error_log($ex->getMessage());
} catch(\Exception $ex) {
error_log($ex->getCode());
error_log($ex->getMessage());
}
if($_GET['error']=="access_denied"){
header("location:/login/");
exit;
}else if (isset($session) || (isset($_SESSION['fb_user_session_access_token'])) && !empty($_SESSION['fb_user_session_access_token'])) {
if(isset($session))
$_SESSION['fb_user_session_access_token'] = $session->getToken();
else{
$access_token = $_SESSION['fb_user_session_access_token'];
$session = new FacebookSession($access_token);
}
try {
$user_profile = (new FacebookRequest(
$session, 'GET', '/me'
))->execute()->getGraphObject(GraphUser::className());
$email = $user_profile->getProperty('email');
$name = $user_profile->getProperty('name');
$fb_id = $user_profile->getProperty('id');
$query = mysql_query("select id, email from ntuc_users where email = '$email'");
$user_found = mysql_num_rows($query);
if(!$user_found){
//code deleted
exit;
} catch(FacebookRequestException $e) {
error_log($e->getCode());
error_log($e->getMessage());
//if token get expired
$loginUrl = $helper->getLoginUrl(array('req_perms' => 'email'));
header("location:".$loginUrl);
exit;
}
}
else
{
$loginUrl = $helper->getLoginUrl(array('req_perms' => 'email'));
header("location:".$loginUrl);
exit;
}
thanks in advanced
After 2 days research, I got this.. here is the flow which I have implemented for my app
#BjörnKaiser mentioned Facebook policy doesn't support LIKEGATE anymore.. and its true ..
So I have go through FB policy and got the following ans
Only incentivize a person to log into your app, like your app’s Page, enter a promotion on your app’s Page, or check-in at a place. Don’t incentivize other actions. Effective November 5th, 2014, you may no longer incentivize people to like your app's Page
FB POLICY
However as ref. to above information, i tried to implement likegate flow but FB hardluck with FB APP review team
But I got one more ref. from the review team
Please note that using "user_likes" to check if someone has liked your Facebook use case is not approvable. User_likes provides information to all of a person's likes, and the entirety of this data should be used to enhance the app experience. If you need to determine who has already liked your page, please use signed requests for Page Tab apps.
FB USER LIKE POLICY
Using signed requests, at least for pagetab it works like a charm :).. but for mobile website, I have removed the it
Here is the code:
if( isset($_REQUEST['signed_request']) )
{
$user_data = $this->parse_signed_request($_REQUEST['signed_request']);
$access_token = $_SESSION['fb_user_session_access_token'];
}
if( (isset($user_data['page']["liked"]) && !empty($user_data['page']["liked"]) && $user_data['page']["liked"]) || $this->deviceType != "computer")//no like gate for mobile
{
//my code ...
}
private function parse_signed_request($signed_request) {
list($encoded_sig, $payload) = explode('.', $signed_request, 2);
$secret = FB_APP_SECRET; // Use your app secret here
// decode the data
$sig = $this->base64_url_decode($encoded_sig);
$data = json_decode($this->base64_url_decode($payload), true);
// confirm the signature
$expected_sig = hash_hmac('sha256', $payload, $secret, $raw = true);
if ($sig !== $expected_sig) {
$this->log->write('Bad Signed JSON signature!');
return null;
}
return $data;
}
private function base64_url_decode($input) {
return base64_decode(strtr($input, '-_', '+/'));
}
I hope it helps someone else...

PHP Facebook SDK login unreliable

I'm having a strange behavior on my script. Using Facebook PHP SDK I create a button with a link to getLoginUrL() :
$loginUrl = $facebook->getLoginUrl(array(
'canvas' => 1,
'fbconnect' => 0,
'scope' => 'email',
'redirect_uri' => 'http://www.myurl.com')
);
Most of the time this works very well and I can access the user information using the following bit of code
if(!isset($_SESSION['front']['user_id']) || !is_numeric($_SESSION['front']['user_id']))
{
if (isset($_REQUEST['code'])) {
try {
$user_id = $facebook->getUser();
$basic = $facebook->api('/me?access_token=' . $access_token);
if (is_array($basic) && is_numeric($user_id)) {
$user = get_user_id_facebook($basic);
$_SESSION['front']['user_id'] = $user;
$_SESSION['front']['user_name'] = $basic['name'];
$_SESSION['front']['email'] = $basic['email'];
$_SESSION['front']['fbid'] = $basic['id'];
return true;
} else {
return false;
}
} catch (Exception $e) {
return false;
}
}
}
The problem is that sometimes I really cannot access the user information... why is this so unsteady? My php version is 5.3.2
Your code is unreliable as you're only executing the code if code exists in the GET or POST request. What you really should be doing is checking if the user is logged in, e.g.
if ( $facebook->getUser() != 0 ) {
// get profile information
} else {
// log user in
}
The code parameter won't always existing on your page, as it's returned by Facebook on successful login. But not when the user accesses your page directly or via bookmark.

Categories