A user is logged in to my website and I have all the details I need to retrieve information on their account. I know how to retrieve the users profile image url, but I am not sure if this is a 'static' link. If it is not a static link, I have to fetch the URL each time which seams like a bad idea. I would really be hammering google with all my requests. (I'm not worried about googles servers, I am more worried about my api quota.)
So is there a way to get a static link to a users profile image. If not, what is the best option?
The developer policies at https://developers.google.com/+/policies state, in section B1c:
Don’t use stale data. You can cache or store data you’ve obtained through the Google+ API, but to the extent reasonably possible within the context of your application, use fresh data recently fetched from the API. If the fresh data reveals that content is gone (for instance, because a user deleted it), delete it and don’t use your stale copy. For clarity, if you comply with these requirements, you may cache data longer than specified by the cache header.
The guideline is vague, clearly, but it does say that you shouldn't need to re-fetch the profile info/photo every time... but you should re-fetch it periodically and store it, at least during a session.
Since you're talking photo, consider that people may change their photo somewhat frequently. I would say that it makes sense to cache the image during a user session, but might be reasonable to refresh it when they sign in for a new session.
I'm using this to get users info (and image info, and save that to db for later usage)
$google_client_id = "MY GOOGLE CLIENT ID";
$google_client_secret = "MY GOOGLE CLIENT SECRET";
$redirect_URL = "http://url.to.redirect";
$gClient = new Google_Client ();
$gClient->setApprovalPrompt ("auto");
$gClient->setApplicationName ("My Application Name");
$gClient->setClientId ($google_client_id);
$gClient->setClientSecret ($google_client_secret);
$gClient->setRedirectUri ($redirect_URL);
$google_oauthV2 = new Google_Oauth2Service ($gClient);
//If user wish to log out, we just unset Session variable
if (isset ($_REQUEST["reset"]))
{
unset ($_SESSION["google"]["token"]);
$gClient->revokeToken ();
header ("Location: ".filter_var ($redirect_URL, FILTER_SANITIZE_URL));
}
if (isset ($_GET["code"]))
{
$gClient->authenticate ($_GET["code"]);
$_SESSION["google"]["token"] = $gClient->getAccessToken ();
header ("Location: ".filter_var ($redirect_URL, FILTER_SANITIZE_URL));
return;
}
if (isset ($_SESSION["google"]["token"]))
{
$gClient->setAccessToken ($_SESSION["google"]["token"]);
}
if ($gClient->getAccessToken ())
{
//Get user details if user is logged in
$google_data = $google_oauthV2->userinfo->get ();
$google_user = array (
"id" => $google_data["id"],
"email" => filter_var ($google_data["email"], FILTER_SANITIZE_EMAIL),
"profil_url" => filter_var ($google_data["link"], FILTER_VALIDATE_URL),
"picture" => filter_var ($google_data["picture"], FILTER_VALIDATE_URL)."?sz=200"
);
$_SESSION["google"]["token"] = $gClient->getAccessToken ();
// we have users data now so we do with it what we want... save to db?
}
else
{
//get google login url and redirect user to it
$login_url = $gClient->createAuthUrl ();
header ("Location: $login_url");
exit;
}
Related
I need to develop a very secure login system.
I have an API layer, and my plan is to create a token table. I'll send the username/password (Post) to my API and I generate a unique token (One time token with limited time), I return the token in JSON.
My questions are:
What should be saved in the sessions while user is logged in. I want to store as little as possible information. Should I save the token only? Is it safe?
I don't want to store the access levels and user info in session, then I need to get these info each time via token.. what do you think? Advice!
Any other advice to develop more secure login system.
Thank you in advance.
Since you'd like to keep sessions as logged in identification, you will probably encounter a problem: some clients can't be kept session.
For example, cell phones, web-based app.
I'm creating a similar project. And my solution is
Creating a table named session (or whatever you want), that keeps UserToken (randomly generated), UserID, TokenExpire.
Once the user logged in, create a record at session table, and return the token to the user (encoded into JSON).
User keeps the token their own, and attached the token on every request. (No matter body or header, I'm using header to separate from the data).
Check the token every time before they asking for something. For Example, Is the token exists? Is the token expired? Is the user be blocked?
By the step 4., you can also get what the user is by querying relatively.
That is my solution. It's similar to your way.
Additionally, To improve the security, follow the ways if could
Use SSL (HTTP) to secure the connection between server and clients.
Don't keep their Password plaintext. You should encrypt them.
You can generate the token as longer as possible.
The token field of session table, should be Case Sensitive. Change the collation different from _ci (means Case Insensitive)
Check the POST data to prevent SQL Injection. Never trust what users give to you.
The instructions above are fundamental. I always do that.
this is just a small list on how you can handle it with sessions, cookies and of course a database and php:P not with JSON
you can use a database like this
so the session should contain an array with an index of login, so you can later check if the session isset and restrict acces to a user_only_page. like this:
$_SESSION = array(
"login" => true,
"data" => array(
"username" => $row["username"], // is not a must and not unsafe / you can let it out if you want
"email" => $row["email"], // this is also not a must
"time" => time()+60*10 // so here you can set a time how long the session is available. for this example it is 10min.
)
);
set a cookie for a "remember_me" checkbox like this:
if (isset($_POST["remember_me"]) && $_POST["remember_me"] === "accepted") {
$_SESSION = array(
"login" => true,
"data" => array(
"username" => $row["username"], //not a must
"email" => $row["email"], //also not a must
"time" => time() +3600*24*30 //set the time higher, so that the user won't bee kicked out after 10min when he logged in.
)
);
setcookie('remember_me', md5($emailUsername . time()), time() +3600*24*30);
}
then you can write a file, that is included in every page and handles all sessions or cookies. like this:
ob_start(); //Turns on the output buffering
if (isset($_SESSION["login"])) { //here we check if the session isset(true)
if ($_SESSION["data"]["time"] >= time()) { //here we check if the session time we set before to 10min is greater than the actual time
if(isset($_COOKIE["remember_me"])) { //if you want to let the user stayed in check if the cookie isset, and if redirect him directly to the userarea
header('Location: ../path_to_theuserarea/userarea.php'); //the redirect
exit();
}
}
else { // here we go if the session time is lower than the actual time and kick the user out
$_SESSION["login"] = false; //he has to log_in again
header('Location: ../path_to_the_login/login.php'); //redirect to the login.php
exit();
}
}
else { //here we check if the requested basename of a file is not login.php and if, redirect him to login.php. thats the part that will be included in your userarea.php
if (basename($_SERVER["REQUEST_URI"]) !== "login.php") {
header('Location: ../path_to_the_login/login.php'); //redirect back to login
}
}
ob_end_flush(); //end buffering
also good for a secure login/register system are:
Account_Activation_Token: send a token after successful registered to the email that the user entered and only let him log in if he clicked on that link. I used this method for myself and also used $_GET for the activation token. Send a link like https://YOUR_URL/log_reg/activateAccountWithToken.php?id=USERID&activation_token=RANDOMLY-STRING-WITH-50-CHARAKTERS
you can also .htaccess to rewrite the url so that the URL is shown better. like this:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /log_reg/
RewriteRule ^activate/([a-z]+)/?$ activationToken.php?id=$1 [NC,L]
</IfModule>
after that you can use a url like https://YOUR_URL/log_reg/activate/USERID/
You can use a Cronjob for deleting all activation tokens from your db after some time, so that the user has to activate his account again.
NEVER store PLAINTEXT_PASSWORDS, use functions like password_hash() and password_verify()
use password_needs_rehash() function when the user loggs in so that the hash from the db will be regenerated everytime he loggs in.
force SSL with .htaccess and use prepared-statements for inserting the data to the database
I have a problem with requesting data from Facebook. I have tried a few different ways to get the number of likes for an individual page on a website that I manage, but each time I send a specific URL I get the same information back. The share and like and comment totals are the same for each URL that I pass to Facebook.
So for instance I send:
http://api.facebook.com/restserver.php?method=links.getStats&urls=http://thiswebsite.com/page21/
or
http://api.facebook.com/restserver.php?method=links.getStats&urls=http://thiswebsite.com/page49/
and I get the same information returned.
I have Open Graph tags on the site and I think they are implemented correctly but even when I pass URLs directly as show above I get the same results. Could the og tags I have on the site be effecting the results Facebook returns, even if I am manually passing them to Facebook?
Well you have two options to take. One's overly complicated but once you have it working you'll never have to worry about it. The other takes some time but requires a lot less effort.
I'll start with the simple one. Go to https://developers.facebook.com/tools/explorer. Once you get there your uid should already be there just delete every thing after it including the ? and paste in
/accounts?fields=id,name,likes
You will have to make and access token to see the data. You need the manage_pages permission checked on the extend permissions tab.
Once you do that hit submit and you should see in the results all the pages you're admin on the UID of the page, name and number of likes.
The other way is to build an app that handles this for you. Which you will have to register with Facebook and get an app id from them. With that app you can build a program that gets the information for you using php and or java script
Here's a sample of some php you can use.
require "facebook.php";
$config = array(
'appId' => 'app_id',
'secret' => 'app_secret',
'fileUpload' => false, // optional
'allowSignedRequest' => false, // optional, but should be set to false for non-canvas apps
);
$facebook = new Facebook($config);
$user_id = $facebook->getUser();
if($user_id) {
// We have a user ID, so probably a logged in user.
// If not, we'll get an exception, which we handle below.
try {
$path = '/' .$pageId .'?fields=likes';
$pageData = $facebook->api($path,'GET');
$likes = $pageData['likes'];
} catch(FacebookApiException $e) {
// If the user is logged out, you can have a
// user ID even though the access token is invalid.
// In this case, we'll get an exception, so we'll
// just ask the user to login again here.
error_log($e->getType());
error_log($e->getMessage());
}
} else {
// No user, print a link for the user to login
$login_url = $facebook->getLoginUrl();
}
If you choose the longer route let me know I have this whole thing already built.
I'm implementing the facebook php sdk and using it for user login/connect.
Everything works as expected, however, at the top of each page, I need to call
$facebook->api('/me') to determine if the user is logged in or not..
This call is very slow, sometimes, taking up to 2 seconds to return.
So, any interaction by the user, always has a 1-2 sec delay before any page loads..
I suspect, it's because, the $facebook->api('/me') call is using httpS ..
Any suggestions....
$facebook = new Facebook(array( 'appId' => 'xxxxxxxxxxxxxxx', 'secret' => 'xxxxxxxxxxxxxxxxx',));
$user = $facebook->getUser();
if ($user)
{
try { $user_profile = $facebook->api('/me','GET'); }
catch (FacebookApiException $e) { error_log($e); $user = null; }
}
$login_parms = array('scope' => 'user_birthday', 'redirect_uri' => 'http://xxx.com/login');
$login_link = $facebook->getLoginUrl($login_parms);
if($user)
{
/* logged in */
}
else
{
/* not */
}
You really shouldn't perform the Facebook API request on each page load. Only do it once when the user logs in. Then you can store the "logged in" flag in the session (or a signed cookie).
If you need to store e.g. some of the user's facebook profile information, also put it in the session or your database.
Add some spinning wheel where login form is, then call ajax on document ready to your php script, script returns false or loged in user data (or more data if you need - redirect url) and then depending on result show form to login or display currently loged in user.
What i mean Javascript will handle all logic depending on what is returned from server, redirects, change UI etc.
Another way is to cache (session with expiration) first call to facebook if user is loged in remember it. And check if that Session variable is present and not yet expired. Only call again when doing some sensitive tasks or get expired.
If you do not need to get "fresh" values from $facebook->api("/me").
Then I would suggest you cache the response, if you use any PHP-framework (eg. Zend, Yii, Codeigniter) this should be really straight forward.
If you're not using a PHP-framework i suggest you still look into the excellent ZF documentation for their cache solution.
Zend Framework - Cache
If you, however, need fresh values each load you can make a simple page that only returns the $facebook->api("/me") part and returns it as bare HTML. Then simply keep a or similar that recieves the response when it's finished.
An easy solution would be using jQuery and just write:
$("#div-id").load("/page-that-returns-facebook-api-me-result");
Is there a way to use the facebook connect api in a static way?
When we use the facebook php sdk the link or button to login to facebook is something like https://www.facebook.com/dialog/oauth..................
what I want is to eliminate the include of the php sdk on every page, because it will cause some extra processing and server load in peak times.
I want to make a session check to know if the user is logged in, by checking for exemple if his facebook user id and name are stored in the session, then if not, display a static login button. then after login with facebook he gets to facebook-login.php which will include the facebook php sdk and process his data and store them in the session, so that he remains logged without including the php sdk in each page.
the url structure that I get with $facebook->getLoginUrl() is:
https://www.facebook.com/dialog/oauth?client_id={MY_APP_KEY}&scope={PERMISSIONS}&redirect_uri={MY_SITE/facebook-login.php}&state={A_32_CHAR_CODE_LIKE_MD5_MAYBE}
The final question is: WHAT WOULD BE THE URL IN THE LOGIN BUTTON?
just load the sdk and do something like:
echo 'Connect to Facebook';
that url will always be valid for a logged out user
This is a good question. First, a user is logged into you app means that you have a valid access token for the user.
And there is no way to be sure that an access token is valid before making an API call with this access token. So if you want to make sure the user is still logged in on each page, you have to make an API call to Facebook on each of them. Kind of heavy, but there is no other solution.
What you can do is assume that the access token you have is valid and check only once a while (when you really need to be sure the user is logged in).
You can have different scenario :
you have no Facebook data about the user : the user is not logged in your app for sure.
you can read the user ID, but you may not have an access token for this user : the user may not be logged in.
you can read an access token, but it may not be valid (has expires or revoked by the user) : the user may not be logged in.
you have a valid access token : the user is logged in for sure.
You can read the user ID and the access token in the session. The session array looks like that :
[fb_148195765253871_access_token] => 14819576525...
[fb_148195765253871_user_id] => 1536397056
The number in the keys of the array (here 148195765253871) is your app ID.
So what you can do on each page is to check if those keys are set and if they are not, load the SDK and double-check (because the access can be store in some other places that the SDK is reading) :
if (isset($_SESSION['fb' . YOUR_APP_ID . 'access_token'])) {
// assume to user is logged in
// and keep going
} else {
require "facebook.php";
$facebook = new Facebook(array(
'appId' => YOUR_APP_ID,
'secret' => YOUR_APP_SECRET,
));
// Make an API call to be sure the user is logged in
// ie : that you have a valid access token
$user = $facebook->getUser(); // User ID
if ($user) {
try {
$user_profile = $facebook->api('/me');
} catch (FacebookApiException $e) {
$user = null;
}
}
if ($user) {
// The user is logged in for sure
} else {
// The user is not logged in for sure
// Make him log in
echo 'Login with Facebook';
}
}
Hope that helps !
The selected answer does not really answer the question.
If you would like to isolate all the Facebook code necessary for generating the getLoginUrl function call into a separate file you can do this easily by using meta refresh.
So in your header point the link "Login With Facebook" to "facebook_login.php". On this page include the necessary calls from the SDK for getLoginUrl and than add the following line of HTML.
<meta http-equiv="refresh" content="0;URL=<?=$helper->getLoginUrl(array('email', 'user_friends'));?>">
I tested this out multiple times and it works.
FYI using Facebook SDK 4.0.
I've been going through FB docs but I think I am totally lost now. My task is quite simple: I need to have an "import" link, user clicks it and receives FB popup where he authorizes the site, user is redirected back to my site, I access user's FB profile and retrieve some data. Also: I need to access and retrieve profile in PHP.
The first part goes well. I created mysite.com?page=import link which opens in popup and then redirects to https://graph.facebook.com/oauth/authorize?...
User then allows access and the popup is redirected back to mysite.com?...#access_token=...&expires_in=4031
Then I am going to close the popup and instead refresh the parent window that opened this popup by redirecting it to something like this mysite.com?page=register&access_token=...&expires_in=4031
Then I was going to use their PHP SDK hoping that it can take this access token and allow me to get user's data. However I have no luck so far. I've tried lots of things and went through facebook.php but can't see a solution. Please let me know how to do this: authorize user in a popup and then gather the profile data in php.
here is your working example.
it has a redirect and works entirely in php, i didnt do javascript beacuse this is easier and faster to write.
the main difference is that the returned code after the authorization page is only a code which allows you to fetch the actual access token incombination with your client secret.
otherwise anyone could get an access token for yuor application or you would have to pass your secret token in the url.
thats the reason for the second step.
in javascript we dont need that because facebook only redirects back to a whitelisted domain
and as the access token is in the url fragment after the # tag the server cant access it, only the client. and this is ensured to be yours erver as your domain must be whitelisted.
but it needs more client interaction...
well anyway. you can use the code i wrote for yuo and you can also do it in a popup. you just have to pass your variables to the form or whatever you are doing but this shouldnt be a problem. i did it this way because you said you needed it in php. a good javascript example can be found on the facebook connect page here: http://developers.facebook.com/docs/guides/web#login
any questions? comment!
ps: i put the # sign before the file_get_contents function because you might geht ssl errors, you should actually use curl for that and do error handling!
save this file as whatever.php to your server, check the 4 config variables in the top and hit it
<?
// your app id
$app_id = "123";
// your secret token
$mysecret = '***';
// your website correctly set up in facebook app config
$redirecturl = "http://www.yourdomain.com/whatever/thisfile.php?action=authorized";
// what you want to fetch
$scopes = array('email','user_interests'); // whatever you want
if($_GET['action'] == 'authorize') {
$url = "https://graph.facebook.com/oauth/authorize?client_id=".$app_id."&redirect_uri=";
$url .= urlencode($redirecturl);
$url .= "&display=popup";
$url .= "&scope=".implode(',',$scopes);
header("Location: $url");
exit();
} else if($_GET['action'] == 'authorized') {
$code = $_GET['code'];
$tokenurl = 'https://graph.facebook.com/oauth/access_token'.
'?client_id='.$app_id .
'&redirect_uri='.urlencode($redirecturl).
'&client_secret='.$mysecret.
'&code='.$code;
$token = #file_get_contents($tokenurl);
$token = preg_match('/access_token=(.*)&/',$token,$extracted_token);
$token = $extracted_token[1];
$dataurl = 'https://graph.facebook.com/me?access_token='.$token;
$result = #file_get_contents($dataurl);
$data = json_decode($result);
echo "<pre>".print_r($data,true)."</pre>";
} else {
?>click here to immport your data<?
}
?>