Facebook announced that all apps must migrate to OAuth 2.0 by 1st of October 2011
October 1, 2011 OAuth 2.0 Migration As we announced in May, all apps
must migrate to OAuth 2.0 for authentication and expect an encrypted
access token. The old SDKs, including the old JS SDK and old iOS SDK
will no longer work.
Read more here: https://developers.facebook.com/docs/oauth2-https-migration/
Now I am pretty confused by all the different flows and versions. I have a simple authentication going on that looks basically like this (I stripped the un essential parts)
## setup ###
$url = "https://graph.facebook.com/oauth/authorize?client_id=".$this->appid."&redirect_uri=".$myurl;
header("Location: $url");
exit();
and when the user returns...
## authentication check ##
$code = isset($_GET["code"]) ? $_GET["code"] : false;
if(!$code) {
// user has not authenticated yet, lets return false so setup redirects him to facebook
return false;
}
$url = "https://graph.facebook.com/oauth/access_token?client_id=".$this->appid."&redirect_uri=";
$redirecturl = urlencode($redirecturl);
$url .= $redirecturl;
$url .= "&client_secret=".$this->secret;
$url .= "&code=".$code;
$data = $this->get_data($url); // fetches content over https
parse_str($data,$data);
$token = $data['access_token'];
$data = $this->get_data('https://graph.facebook.com/me?access_token='.urlencode($token));
$data = json_decode($data);
$id = $data->id;
if($id > 0) {
// yeah authenticated!
} else {
// login failed
}
Is this method ready for the compulsory migration?
short answer... it is..................
Related
I' m having a difficulty in getting a clear view on Joomla (I'm using version 3.6.x) authentication and login.
I've seen many approaches and snippets on how to "Login" in a Joomla site from an external source (which is what i m interesting in).
But what i see after testing and testing (and more testing), is that at the end of the day, you re simply not logged in.
You may have the ability to verify that the user who's attempting to login is a valid registered user and also to be able to retrieve his name, email, phone and blah blah blah but in Joomla backend, this user is still not logged in.
I created a brand new user in Administrator Panel (it shows the user NEVER visited the site), I wrote the login script in external PHP, I "authenticated" the new user a dozen times and when i go back to the Backend, the user still NEVER been there. Not even once.
Which, i guess, it also means that i can't retrieve a list of "active" users, since Joomla can't see them as logged in users.
So what i want to achieve is users to be able to login from outside the Joomla site and to have the ability to know IF they're logged in or not. So I can get a list of them and assign tasks to them.
I guess it has something to do with tokens and cookies. But no matter how much i searched to that direction, i can't find any examples to enlighten me.
Any help (and specially "scripting" help) is much appreciated.
Thank you.
<?php
if (version_compare(PHP_VERSION, '5.3.1', '<')) {
die('Your host needs to use PHP 5.3.1 or higher to run this version of Joomla!');
}
define('_JEXEC', 1);
if (file_exists(__DIR__ . '/defines.php')) {
include_once __DIR__ . '/defines.php';
}
if (!defined('_JDEFINES')) {
define('JPATH_BASE', __DIR__);
require_once JPATH_BASE . '/includes/defines.php';
}
require_once JPATH_BASE . '/includes/framework.php';
$app = JFactory::getApplication('site');
$app->initialise();
require_once (JPATH_BASE .'/libraries/joomla/factory.php');
$credentials['username'] = $_GET["usrname"];
$credentials['password'] = $_GET["passwd"];
$db = JFactory::getDbo();
$query = $db->getQuery(true)
->select('id, password')
->from('#__users')
->where('username=' . $db->quote($credentials['username']));
$db->setQuery($query);
$result = $db->loadObject();
if ($result) {
$match = JUserHelper::verifyPassword($credentials['password'], $result->password, $result->id);
if ($match === true) {
$user = JUser::getInstance($result->id);
$session =& JFactory::getSession();
echo "<p>Your name is {$user->name}, your email is {$user->email}, and your username is {$user->username}</p>";
$session->set('userid', $user->id);
if ($user->guest) {
echo 'SORRY, NO LOGIN YET...';
} else {
echo 'user is LOGGED IN !';
}
} else {
die('Invalid password');
}
} else {
die('Cound not find user in the database');
}
?>
Joomla log in is handled in authentication plugins, by writing and enabling your own you can bypass the token verification and allow logging in by a simple get request.
Keep in mind that Joomla! keeps administrator and frontend sessions separate (you can be logged into the administrator, and browse the site as a guest). Additionally, a user needs a Manager, Administrator or Super User group membership to login to the backend.
Administrator
The common use case for admin login is to run a background script.
In order to bypass the Joomla Authentication in the backend, check out the /cli folder as it contains some examples.
Frontend
The use case for frontend login is much wider: server-to-server communication, app authentication, single sign on etc.
The best practice to perform frontend authentication is to build your own authentication plugin. The authentication will be implemented by the onUserAuthenticate() function. Check out the /plugins/authentication/joomla/ plugin for an example.
If you need extra data for the authentication plugin to perform its magic (e.g. the remote token/api key to authenticate using a remote service) you might want to check out the user plugin group, for example the /plugins/user/profile plugin.
Verify last login date/time
The frontend approach should automatically work, showing users as logged in in the administrator control panel.
However, if you use the CLI approach to login to the administrator, this may not work depending on how you perform login.
To be able to check if a user is logged in only authentication is not enough but you need a forced login. Only then you will be able to view them at the backend.
This is the code you can use to check if a user is logged in or not
<?php
if (version_compare(PHP_VERSION, '5.3.1', '<')) {
die('Your host needs to use PHP 5.3.1 or higher to run this version of Joomla!');
}
if (!ini_get('display_errors')) {
ini_set('display_errors', '1');
}
echo ini_get('display_errors');
define('_JEXEC', 1);
define('JPATH_BASE', "C:\Vertrigo\www\joomla" );//Define the Base path as per your installation directory
if (!defined('_JDEFINES'))
{
require_once JPATH_BASE . '/includes/defines.php';
}
require_once JPATH_BASE . '/includes/framework.php';
// Instantiate the application.
$app = JFactory::getApplication('site');
$app->initialise();
require_once (JPATH_BASE .'/libraries/joomla/factory.php');
//Check if a user exists else create one with forced login
$user = JFactory::getUser();
jimport('joomla.plugin.helper');
$credentials = array();
$credentials['username'] = JRequest::getVar('username', '');
$credentials['password'] = JRequest::getVar('passwd', '');
if (!$user->get('gid')){
$forcevars = array();
$forcevars['silent'] = true;
$forcevars['forecelogon'] = true;
$response = $app->login($credentials, $forcevars);
if($response){
echo "Login Successful";
}else{
echo "Login Unsuccessful. Check Username and Password. Give just Plain password.";
}
}
?>
I have modified the code as you neeeded to call username and password in url. better to use getVar in joomla rather than GET method. You url will be in the format http://www.yoursite.com/thisscript.php?username=yourusername&passwd=yourpassword
I'm trying to show the feed and events of a Facebook fanpage on a website. I'm using the php sdk to call the Facebook graph api. I also created an app on my Facebook account and have an app ID, app secret and app token.
I don't want to log in the user of the website. I just want to integrate the events and news data of the Facebook fanpage on the website.
My question is: Can I use the static app token to make graph api calls with php from my server and build my website after that, so that no one will receive the app token? Or is this bad because of security issues?
Here is the code:
$app_ID = '{appID}';
$app_secret = '{appSecret}';
$app_token = "{staticAppTokenFromFacebookDeveloperSettings}";
$facebook_page_ID = '{facebookPageID}';
$fb = new Facebook\Facebook([
'app_id' => $app_ID,
'app_secret' => $app_secret,
'default_graph_version' => 'v2.7',
]);
$fb->setDefaultAccessToken($app_token);
try {
$response = $fb->get('/' . $facebook_page_ID . '/feed');
//$response = $fb->get('/' . $facebook_page_ID . '/events');
// ...
} catch(Facebook\Exceptions\FacebookResponseException $e) {
// When Graph returns an error
echo 'Graph returned an error: ' . $e->getMessage();
exit;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
// When validation fails or other local issues
echo 'Facebook SDK returned an error: ' . $e->getMessage();
exit;
}
Thank you very much!
You have to put the App Secret somewhere in order to use an App Access Token, and the server is the only place where it is safe. Just keep in mind that there are limits to API calls, you should cache results in your own database. Do not call the feed and events endpoints for every single user hit.
I am trying to do a simple soap call to a weather service and I keep getting Invalid ZIP error. Can someone tell me what I am doing wrong below is my code.
Thanks
require_once 'SOAP/Client.php';
$client = new Soap_Client('http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL');
$method = 'GetCityWeatherByZIP';
$params = array('ZIP' => '07108');
$result = $client->call($method, $params);
if (PEAR::isError($result)) {
echo $result->getMessage();
} else {
print_r($result);
}
Use PHP's in-built SOAP client. The one in PEAR was written at a time PHP did not have one itself.
Their service is no SOAP service. The wiki states:
$url = "http://wsf.cdyne.com/WeatherWS/Weather.asmx/GetCityForecastByZIP";
$url .= "?ZIP=" . $this->ZipCode;
$this->response = simplexml_load_file($url) or die("ERROR");
In my javascript I have a click event that triggers an ajax call to the php page where I send my notification from. I chose to do it this way because the documentation advises against using your app secret in any client side code, and the notifications parameters requires an access token that you can only get using the app secret.
The problem I'm having is that even though I'm logged in, $facebook->getUser() is returning 0 in php, so the api call I make afterwards to send the notification wont work. My user is already logged in via the client side code, so how do I get the message to the php that they're logged in so the notification can be sent.
//JS
$.ajax({
url : "http://xxxxxo/bn/notification.php",
type : 'POST',
data: {notify: notify },
success : function (result) {
console.log(result);
},
error : function () {
alert("error sending notification");
}
});//closes ajax
//PHP
<?php
require_once(dirname(__FILE__).'/php-sdk/facebook.php') ;
$APPLICATION_ID = '1402xxxxx7';
$APPLICATION_SECRET = 'ce71d6bbxxxxx5f55a';
$fb_app_url = "http://apps.facebook.com/myAPP";
$config = array();
$config['appId'] = $APP_ID;
$config['secret'] = $APP_SECRET;
$config['cookie'] = true;
$facebook = new Facebook($config) or die('Error is here!');
$facebook = new Facebook(array(
'appId' => $APP_ID,
'secret' => $APP_SECRET,
'fileUpload' => true
));
$notify = $_REQUEST['notify'];
$userid = $facebook->getUser();
/*IF WE HAVE A LOGGED IN USER AND THE 'NOTIFY' REQUEST VALUE, THEN SEND THE NOTIFICATION.
BUT MY USER ID IS 0. HOW DO I GET PHP TO RECOGNIZE ME AS LOGGED IN WITHOUT HAVING TO FORCE MY USER TO LOG IN VIA PHP AFTER THEY'VE ALREADY LOGGED IN CLIENT SIDE?*/
if($userid && $notify){
$token_url ="https://graph.facebook.com/oauth/access_token?" .
"client_id=" . $APP_ID .
"&client_secret=" . $APP_SECRET .
"&grant_type=client_credentials";
$app_token = file_get_contents($token_url);
$app_token = str_replace("access_token=", "", $app_token);
$data = array(
'href'=> 'https://apps.facebook.com/thebringernetwork/',
'access_token'=> $app_token,
'template'=> 'test'
);
$sendnotification = $facebook->api('/1622649653/notifications', 'post', $data);
}else{
//handle error
}
?>
The first thing I noticed is that you define your app id as $APPLICATION_ID but use it as $APP_ID (and the same goes for your app secret). But since you didn't mention any errors and $facebook->getUser(); executes I'm guessing this is just a bad copy-paste.
Now for the sake of answering this question I'm going to presume that you are using the latest versions of both JS and PHP SDKs. These use oauth 2.0 and change the way you pass the login information from JS to PHP.
According to Facebook Developer Blog removing $config['cookie'] = true; and setting oauth to true in your JS configuration should work. Just make sure to refresh the site after the login.
The solution I've found in my own project is to disable cookies altogether and simply pass the access token to my PHP script.
In your JS call your PHP script like this (make sure to call this after the JS login!):
$.ajax({
url : "http://xxxxxo/bn/notification.php",
type : 'POST',
data: {
notify: notify,
token: FB.getAuthResponse()['accessToken'] // add your access token
},
success : function (result) {
console.log(result);
},
error : function () {
alert("error sending notification");
}
});
And in your PHP script add this after creating the FB object.
$facebook->setAccessToken($_POST['token']); // set the users access token
Doing things this way will also get rid of any need to refresh the website after the login.
Yes, this is a common problem when using the PHP SDK in combination with AJAX:
When you make an AJAX request, the PHP SDK deletes the cookies where the authorization information are stored, and then the next call to getUser will just return 0, because this method tries to find the current user id in those cookies – apparently there is something in the OAuth 2.0 spec that demands this behavior to prevent some sort of click-jacking attack.
But the info will still be stored in the session, so you can read the user id (and the user access token, should you need it) from there:
$user_id = $_SESSION['fb_YourAppIdHere_user_id'];
$user_access_token = $_SESSION['fb_YourAppIdHere_access_token'];
Replace YourAppIdHere with your app id (so it becomes fb_1234567890_user_id resp. fb_1234567890_access_token) to get the correct names of those session keys.
When a user comes into my app via an apprequest, Facebook appends a request_id to the URL.
I am trying to access this object before the user authorizes my application. When I try to make the api call:
FB.api('/'+requestId, function(response){ console.log(response); });
it returns the following:
error: Object
message: "An access token is required to request this resource."
But I should have access since it was my app that sent the request in the first place!
I did some digging, and I noticed that on the PHP side, it will use the user_access_token if available, and the app_access_token otherwise.
Is this a security limitation (i.e: cannot expose the app_access_token on the client side) or am I doing something wrong?
Any insight would be helpful. Thanks!
when you make a request to /{user_id}/apprequests you have to have authorized the user already...
Since the request was created by your application - only your application can manage -ie delete or read requests that were sent. Essentially, before the user authorizes you app he/she is anonymous to your application - therefore it would not be possible to read that users requests because you "dont know" who they are...
Hope this helps...
The following blog posts describes how to interact with requests and should hopefully answer your questions.
http://developers.facebook.com/blog/post/464
<?php
$app_id = 'YOUR_APP_ID';
$app_secret = 'YOUR_APP_SECRET';
$token_url = "https://graph.facebook.com/oauth/access_token?" .
"client_id=" . $app_id .
"&client_secret=" . $app_secret .
"&grant_type=client_credentials";
$access_token = file_get_contents($token_url);
$signed_request = $_REQUEST["signed_request"];
list($encoded_sig, $payload) = explode('.', $signed_request, 2);
$data = json_decode(base64_decode(strtr($payload, '-_', '+/')), true);
$user_id = $data["user_id"];
//Get all app requests for user
$request_url ="https://graph.facebook.com/" .
$user_id . "/apprequests?" .
$access_token;
$requests = file_get_contents($request_url);
//Print all outstanding app requests
echo '<pre>';
print_r($requests);
echo '</pre>';
//Process and delete app requests
$data = json_decode($requests);
foreach($data->data as $item) {
$id = $item->id;
$delete_url = "https://graph.facebook.com/" .
$id . "?" . $access_token . "&method=delete";
$result = file_get_contents($delete_url);
echo("Requests deleted? " . $result);
}
?>
You have access to the app generated requests as the user follows the request via your app token but you need the user token to access the rest of the users requests.