Security for arguments going to a php script - javascript

I am currently developing a register & login system with HTML, CSS, JavaScript and PHP.
Expiration
The user inputs his email and password in the with CSS styled input fields of html. Now if the user press the login button, JavaScript gets the user email and password of these input fields and calls the login.php script with the parameters email and password. The PHP script does the main work than and returns the access or denial to JavaScript. At last JavaScript shows the user error or give access based on the PHP script answer.
Detailsnippet of Javascript
function loginuser(email, password) {
if (email || password) {
query('./php/login.php', null, [['email', email], ['password', password]]).then(function(obj) {
console.log("REPLY");
if (obj.error) {
//ERROR
}
else {
//ACCESS
}
});
}
else {
//PASSWORD , EMAIL CAN NOT BE EMPTY
}
}
function query(url, cmd_type, data_array) {
var request = new XMLHttpRequest();
var params= '';
params = params + 'cmdtype=' + encodeURIComponent(cmd_type) + '&';
if (data_array) {
data_array.forEach(function(item) {
if (Array.isArray(item[1])) {
var serialized_tda = '';
item[1].forEach(function(tdai) {
serialized_tda = serialized_tda + "|" + tdai[0] + "," + tdai[1] + "|";
});
params = params + item[0] + '=' + encodeURIComponent(serialized_tda) + '&';
}
else {
params = params + item[0] + '=' + encodeURIComponent(item[1]) + '&';
}
});
}
return new Promise(function(resolve, reject) {
request.open('POST', url, true);
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.onreadystatechange = function() {
if (request.readyState === XMLHttpRequest.DONE) {
if (request.status === 200) {
var response = JSON.parse(request.response);
resolve(response);
}
else {
resolve({error: 'Cant connect!'});
}
}
};
request.send(params);
});
}
Doubts - The problem
Since I am calling a script with parameters it can be found in the network tab in browser dev console with all parameters I sent.
Does this disappear when I use a SSL certificate in production later, do I have to encrypt data in JavaScript before I can send it via parameters to php or is this normal?

No, using SSL will not cause that information to disappear from the Network tab in production.
SSL encrypts the data between the client (i.e. the user logging in) and the server that handles it. Sending it in plain text is generally okay, so long as it's always going via HTTPS, since that will encrypt the traffic and make it nonsense to any sniffing attack.
Furthermore, the information from the network tab is only visible to the client, who entered the password anyway (so they know it), so it should not be considered a security flaw with your app.

As the previous answer says, the browser’s developer tools only shows what the browser sees. Once it leaves your browser over HTTPS it is encrypted.
Encrypting passwords in the application before sending is no longer recommended because there will always be some other security compromise. For example, this was implemented in HTTP Digest authentication and the impact was having to store the password unhashed on the server.
Send your password as plaintext. Make sure your server only accepts HTTPS (permanent redirect) and store it in hashed form on the server.

Html click "submit" to send the form
Browser log the content of package
Browser encrypt the data if you are accessing the https site
Browser send the encrypted data
Server got your request
and you was seen the step 2 content

Related

XMLHttpRequest does not reload page

firebase.auth().onAuthStateChanged(function(user) {
if (user) {
console.log("Signed in");
return user.getIdToken(true).then(function(idToken) {
// Send token to your backend via HTTPS
// ...
console.log("Token = " + idToken);
var bearer = "Bearer " + idToken;
var xhr = new XMLHttpRequest();
xhr.open("GET", "dashboard");
xhr.setRequestHeader("Authorization", bearer);
return xhr.send();
}).catch(function(error) {
// Handle error
console.log(error);
});
}
else{
console.log("User signed out");
}
});
I am doing the following request. In my server I am receiving logs saying it has received the request and it has recognized it as an authenticated user and so on. In fact, to test, I sent it to a simple endpoint like /hello where I simply do res.render("Hello World!") in my express app but even then nothing happens on the page. Why isn't the browser refreshing the page to represent the response from the endpoint?
Why isn't the browser refreshing the page to represent the response from the endpoint?
Because the entire point of Ajax is that the response is passed to JavaScript so you can do what you like with it instead of loading a whole new page.
You can access the data with:
xhr.addEventListener("load", function () {
console.log(this.responseText);
});
What you're now building is essentially a webapp which communicates with an API from JS. Since you're doing logic client-side instead of server-side now, instead of using Express to redirect to another route after login you have to do client-side routing.
This means after you've received a successful response (200) from the API you have to direct the client to the desired route. So you would do something like:
if (user) {
window.location = "/dashboard";
}
However it seems like you're doing client-side logic by accident. Therefore I would recommend to stop using XMLHttpRequest and just use <form> as you were doing in your other post and continue your efforts to try to get that working. In that way you can continue building a server-rendered ExpressJS app.

Javascript request to cross orgin PHP application

I have a PHP application that I want to run through XMLHttpRequests on my front end part, this works fine as it's pratically the same as "normal". This works fine.
I get really confused when I start trying to do secure cross origin requests. For instance, some requests I want to only permit if a user is logged in. But, when testing if a session is still there, it doesn't exist anymore. I just don't want random people tapping into someones profile, for instance. Or gain any sort of data I don't want random people to see.
What I want
Requests through this model shown below, but make them secure. Because some data I want for protect to logged-in users only. How do you do that? I can't wrap my mind around that.
Basically, I now have the issue that I can't check on the PHP end if a user has a active session, as PHP sees it as a totally new thing. Essentially, how do you do it like web broswers do it? It's probably just really stupid, but I can't wrap my mind around it.
What I've tried
I've tried requesting where one sets the $_SESSION, then requesting it where it returns $_SESSION, but it return nothing. This means I can't check if the request comes from a loggedin user.
You can use JSON Web Tokens for communicating securely across devices.
JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA.
Source
You basically send a token with each request to sources you want to secure behind a login. Then server side you veryfy that token. Upon login you generate that token and include it in your response. In your frontend you can store the token in local storage on the client machine. For example jQuery has this plugin for local storage.
Here is a super basic example of what you need to do in PHP.
Do your login using javascript/jQuery. Send username/password to login.php for example and authenticate the user like you would normally do.
login.php
use \Firebase\JWT\JWT;
$salt = 'some_salt_string';
$algo = 'HS256'; // allowed ones
$params = array(
"iss" => 'http://example.com', // your own identification
"aud" => ['user_id'=>4324], // client identification
"iat" => time(), // start validity
"exp" => time()+(3600*24) // end validity
);
$token = JWT::encode($params, $salt, $algo);
// example data
$data = [
'example_1'=>'value 1',
'example_2'=>'value 2'
];
$response = array_merge($data,['token'=>$token]);
header('Content-Type: application/json');
echo json_encode($response);
auth.php
use \Firebase\JWT\JWT;
/**
* http://stackoverflow.com/questions/40582161/how-to-properly-use-bearer-tokens
* Get header Authorization
* */
function getAuthorizationHeader(){
$headers = null;
if (isset($_SERVER['Authorization'])) {
$headers = trim($_SERVER["Authorization"]);
}
else if (isset($_SERVER['HTTP_AUTHORIZATION'])) { //Nginx or fast CGI
$headers = trim($_SERVER["HTTP_AUTHORIZATION"]);
} elseif (function_exists('apache_request_headers')) {
$requestHeaders = apache_request_headers();
// Server-side fix for bug in old Android versions (a nice side-effect of this fix means we don't care about capitalization for Authorization)
$requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders));
//print_r($requestHeaders);
if (isset($requestHeaders['Authorization'])) {
$headers = trim($requestHeaders['Authorization']);
}
}
return $headers;
}
/**
* http://stackoverflow.com/questions/40582161/how-to-properly-use-bearer-tokens
* get access token from header
* */
function getBearerToken() {
$headers = $this->getAuthorizationHeader();
// HEADER: Get the access token from the header
if (!empty($headers)) {
if (preg_match('/Bearer\s(\S+)/', $headers, $matches)) {
return $matches[1];
}
}
return null;
}
$token = getBearerToken();
$salt = 'some_salt_string';
$algo = 'HS256';
$decoded_token = JWT::decode($token, $salt, $algo); // returns object
// you can access the audience properties to verify the user id against a requested resource
$user_id = $decoded_token->aud->user_id;
// finally check user id and either deny or allow access
javascript
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-storage-api/1.9.4/jquery.storageapi.min.js"></script>
<script>
var storage=$.localStorage;
function login() {
$.ajax({
url: 'https://example.com/api/login',
type: 'POST',
data: {
username:'Username',
password:'Password'
},
success: function (data) {
storage.set('auth_token',data.token); // store returned token to local storage using the jQuery plugin"value"
},
error: function () {
alert('Error occured');
},
});
}
function testApi() {
$.ajax({
url: 'https://example.com/api/test',
type: 'GET',
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', 'bearer '+storage.get('auth_token')); // append the token. Mind the space.
},
data: {
query:'value'
},
success: function () {
},
error: function () {
},
});
}
</script>
Include the auth snippet in your secure pages or better said API endpoints.
CORS or cross origin request are to allow other domains to access your web-services. The feature you are asking is user level access or we can say which is public and which is restricted to user roles. It's not something related to CORS. Secondly session is restricted to one system. Please read this page of w3schools for better understanding of session https://www.w3schools.com/php/php_sessions.asp
You can also maintain an user level variable in your mysql or whatever db you are using on the server side to know what is the user level and then bring it to the correct session and with each request check the session value for the type of user like $_SESSION["user_type"] which you can bring from your db and then destroy the session on logout.

CSRF protection for REST API browser-client with CORS enabled

There is an API behind api.sample.com and a browser-based webapp (Single-Page, Javascript-driven) behind app.sample.com as well as other, non-browser based clients.
The API supports Basic and Token-based authentication with the token packed into a cookie for browsers.
To make the setup work for browsers, CORS has to be enabled and withCredentials set:
var cors = new EnableCorsAttribute("https://app.sample.com", "*", "GET,POST,PUT,DELETE");
cors.SupportsCredentials = true;
cors.PreflightMaxAge = 3600;
config.EnableCors(cors);
Now I played around with CSRF vulnerabilities and found that AJAX is blocked by the origin setting, <img> or <a> don't see any response data, but <form>-submissions are open to exploits.
To protect forms, I'm adding an anti-forgery token to the mix and validate it for every request to a controller action that doesn't have the AllowAnonymousAttribute set.
I'd like to use the System.Web.Helpers.AntiForgery class, but it requires the principal identity to be set, which is not the case when validating credentials on login - only on subsequent requests.
So I came up with the idea that the browser client requests a CSRF-Token right after validating credentials, sends the token as a header on every request and the server validates the token in a FilterAttribute. E.g.
[HttpGet, Route("xsrf"), AllowAnonymous]
public IHttpActionResult GetCSRFToken()
{
// AllowAnonymous is set to allow requests without csrf token to reach this action
if (User.Identity.IsAuthenticated)
{
string cookieToken, formToken;
AntiForgery.GetTokens(null, out cookieToken, out formToken);
// or set a cookie
return Ok(cookieToken + ":" + formToken);
}
return Unauthorized();
}
and
public class ValidateXSRFTokenAttribute : AuthorizationFilterAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
// apply only if cookie-authentication and no AllowAnonymousAttribute set on the action
if (actionContext.RequestContext.Principal.Identity.AuthenticationType == DefaultAuthenticationTypes.ApplicationCookie &&
!actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any())
{
try
{
string cookieToken = "";
string formToken = "";
IEnumerable<string> tokenHeaders;
if (actionContext.Request.Headers.TryGetValues("X-XSRF-Token", out tokenHeaders))
{
var tokens = tokenHeaders.First().Split(':');
if (tokens.Length == 2)
{
cookieToken = tokens[0].Trim();
formToken = tokens[1].Trim();
}
}
AntiForgery.Validate(cookieToken, formToken);
}
catch
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
ReasonPhrase = "Anti-XSRF Validation Failed."
};
}
}
base.OnAuthorization(actionContext);
}
}
Is this implementation correct? Anything to improve?
It is still possible to make the server send the CSRF-token using a <form> or <iframe> submission, so the protection is depending on not being able to read that response in javascript according to same-origin-policies.
Or better roll my own CSRF-Token that can be set directly when logging in?

Chrome extension to make it possible for people to surf non-standard .bit sites

I am working on a Chrome extension to makes it possible for people to, without a proxy, surf .bit domains which are not available via any standard DNS servers (as .bit is managed by the peer-to-peer Namecoin network with no central authority).
By using the chrome.proxy API (developer.chrome.com/extensions/proxy) I have been able to make an extension that works pretty ok for http (port 80) by using ajax to get the IP of the .bit domain from an app server (app.dotbit.me/domain.bit) and then making a proxy request to that IP thereby keeping the .bit domain name intact in the address field.
The Chrome extension works ok but I am not very happy with the solution. It seems to not load the correct .bit site at times requiring a page reload to work and it does not work for https sites at all.
Is there a better way for a Chrome extension to make a host->IP lookup from a non-default DNS server or app server and then redirect the browser to that domain? Preferably something that would work for https sites as well.
I know it can be achieved by having the user change the computer DNS server to one that supports the .bit domain but that is too complex for most - it would be great if there was a way to do this in a browser extension.
The current Chrome extension is available at https://github.com/Tagide/chrome-bit-domain-extension
The relevant code is as follows:
chrome.webRequest.onBeforeRequest.addListener(function (details) {
var parser = document.createElement('a');
parser.href = details.url;
var tld = parser.hostname.slice(-3);
if (tld != 'bit') {
return;
} else {
// alert('Getting request for '+details.url);
var xhr = new XMLHttpRequest();
var url = "http://app.dotbit.me/"+parser.hostname;
if (parser.protocol == "https:") {
var port = "443";
var access = "HTTPS";
} else {
var port = "80";
var access = "PROXY";
}
xhr.open("GET", url, false);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
var bitip = xhr.responseText;
console.log('Access via '+access+' IP: '+bitip+', port '+port+' and server url '+url);
var config = {
mode: "pac_script",
pacScript: {
data: "function FindProxyForURL(url, host) {\n" +
" if (dnsDomainIs(host, '"+parser.hostname+"'))\n" +
" return '"+access+" "+bitip+":"+port+"';\n" +
" return 'DIRECT';\n" +
"}"
}
};
console.log('Config is: '+JSON.stringify(config));
chrome.proxy.settings.set({value: config, scope: 'regular'},function() {});
}
}
xhr.send();
}
}, {
urls: ['*://*/*']
}, ['blocking']);
If you would like to test the extension it's available on the Chrome web store, you can find all .bit sites that's currently running a http server at dotbit.me/proxy/

How do I renew a Facebook user_access_token if I deal with a lot of AJAX?

Please tell me if I'm understanding correctly. (because I might not be.)
User posts something on my site. (He checked "also post to Facebook".)
Client sends an AJAX POST request to my server, and my server inserts the record in my database.
The server realizes the the facebook user access token is expired, so it sends the response back to the client, while storing the post in a session.
The client does a window.location.replace(facebook_oauth_dialog_url)
Then the user will see a sudden "flash", going to Facebook, then coming back to the website. My server picks up the new access token.
My server checks the session to see what should be posted to Facebook. And then, it uses the new access token to post that to Facebook.
Is it really this tedious? Why can't I renew the app server-side without the user going through the dialog?
My entire site is Backbone.js. That means, it's one big page. I can't jump the user back and forth between Facebook and my website like this.
The idea is to make use of the Facebook JS-SDK methods:
User check the Post To Facebook option
you check if the current user is connected to your app (using FB.getLoginStatus())
if the user is connected, you have two options:
post directly using the FB.api method or
Send the access_token to your server to complete the post process there
if the user is not connected (or not logged in to Facebook), use the FB.login() method
Here's a quick example (with a Live Demo!) for you to get started:
<!DOCTYPE html>
<html xmlns:fb="http://www.facebook.com/2008/fbml">
<body>
<div id="fb-root"></div>
<script>
var fbLoaded = false;
window.fbAsyncInit = function() {
FB.init({
appId : 'YOUR_APP_ID', // App ID
//channelUrl : '//WWW.YOUR_DOMAIN.COM/channel.html', // Channel File
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
fbLoaded = true;
// Additional initialization code here
};
function postForm() {
var msg = document.myForm.msg.value;
// do form validation here, e.g:
if(!msg.length) {
alert("You should enter a message!");
return false;
}
// do we need to post to Facebook?
if(document.myForm.toFB.checked) {
// is the library loaded?
if(!fbLoaded) {
alert("Facebook JS-SDK is not yet loaded. Please try again later or uncheck Post To Facebook option");
return false;
}
FB.getLoginStatus(function(response) {
if (response.status === 'connected') {
var uid = response.authResponse.userID;
var accessToken = response.authResponse.accessToken;
/*
* message can be posted to Facebook directly
* using the FB.api method or accessToken
* can be sent to the server and do the call
* from there
*/
myAjaxCall(msg, accessToken);
} else {
// status is either not_authorized or unknown
FB.login(function(response) {
if (response.authResponse) {
var accessToken = response.authResponse.accessToken;
myAjaxCall(msg, accessToken);
} else {
alert('User cancelled login or did not fully authorize.');
}
}, {scope: 'publish_stream'});
}
});
} else {
myAjaxCall(msg);
}
return false;
}
function myAjaxCall(m,a) {
alert("Here you make the ajax call\nMessage: " + m + "\nAccess Token: " + a);
}
// Load the SDK Asynchronously
(function(d){
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
}(document));
</script>
<form id="myForm" name="myForm" action="post" onSubmit="return postForm()">
<p><label>Your Message:</label><br/><textarea name="msg"></textarea></p>
<p><label>Post to Facebook?</label><input type="checkbox" value="1" name="toFB" /></p>
<p><input type="submit" value="Submit"></p>
</form>
</body>
</html>
Before posting to the server, call FB.getLoginStatus() on the client to get the latest access token. There is no flash when using this method and no user interaction, as it simply grabs a new access token.
FB.getLoginStatus( function ( response ) {
if ( response.authResponse ) {
var accessToken = response.authResponse.accessToken;
//post to server
};
} );
I hope you known that if you have publish_stream permission you don't need access token here is documentation for publish_stream and Below is the solution for four scenarios
1.The token expires after expires time (2 hours is the default).
2.The user changes his/her password which invalidates the access token.
3.The user de-authorizes your app.
4.The user logs out of Facebook.
To ensure the best experience for your users, your app needs to be prepared to catch errors for the above scenarios. The following PHP code shows you how to handle these errors and retrieve a new access token.
When you redirect the user to the auth dialog, the user is not prompted for permissions if the user has already authorized your application. Facebook will return you a valid access token without any user facing dialog. However if the user has de-authorized your application then the user will need to re-authorize your application for you to get the access_token.
<?php
$app_id = "YOUR_APP_ID";
$app_secret = "YOUR_APP_SECRET";
$my_url = "YOUR_POST_LOGIN_URL";
// known valid access token stored in a database
$access_token = "YOUR_STORED_ACCESS_TOKEN";
$code = $_REQUEST["code"];
// If we get a code, it means that we have re-authed the user
//and can get a valid access_token.
if (isset($code)) {
$token_url="https://graph.facebook.com/oauth/access_token?client_id="
. $app_id . "&redirect_uri=" . urlencode($my_url)
. "&client_secret=" . $app_secret
. "&code=" . $code . "&display=popup";
$response = file_get_contents($token_url);
$params = null;
parse_str($response, $params);
$access_token = $params['access_token'];
}
// Attempt to query the graph:
$graph_url = "https://graph.facebook.com/me?"
. "access_token=" . $access_token;
$response = curl_get_file_contents($graph_url);
$decoded_response = json_decode($response);
//Check for errors
if ($decoded_response->error) {
// check to see if this is an oAuth error:
if ($decoded_response->error->type== "OAuthException") {
// Retrieving a valid access token.
$dialog_url= "https://www.facebook.com/dialog/oauth?"
. "client_id=" . $app_id
. "&redirect_uri=" . urlencode($my_url);
echo("<script> top.location.href='" . $dialog_url
. "'</script>");
}
else {
echo "other error has happened";
}
}
else {
// success
echo("success" . $decoded_response->name);
echo($access_token);
}
// note this wrapper function exists in order to circumvent PHP’s
//strict obeying of HTTP error codes. In this case, Facebook
//returns error code 400 which PHP obeys and wipes out
//the response.
function curl_get_file_contents($URL) {
$c = curl_init();
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($c, CURLOPT_URL, $URL);
$contents = curl_exec($c);
$err = curl_getinfo($c,CURLINFO_HTTP_CODE);
curl_close($c);
if ($contents) return $contents;
else return FALSE;
}
?>
for more details info you can visit this link
Thanks
UPDATE
well you are doing something wrong you do not need to renew access token even if its expired all you need is sending user facebook id & content you want to post together to your server by ajax then post it without access token Just check up here
Publish Stream from the application - for non logged in user, using Graph API, php SDK
if you have publish_stream permission you dont need access token
this is documentation for publish_stream
https://developers.facebook.com/docs/reference/api/permissions/
Enables your app to post content, comments, and likes to a user's
stream and to the streams of the user's friends. With this permission,
you can publish content to a user's feed at any time, without
requiring offline_access. However, please note that Facebook
recommends a user-initiated sharing model.
I've got the problem in another project.
The way I handle it is to create a hidden iframe. The first time you need the user to accept the privilege, use your main window to redirect. then, when you are sure that the user has already accepted the privilege, use the hidden iframe to communicate with facebook.
The user will not see the "flash" because it will done in an iframe.
I've done it with GWT. Here is the code I used : it communicates with Facebook via the iframe and do a check on access token every 500ms to see if the token is valid.
The code is in java (compiled in javascript using gwt).
public class FacebookConnector extends Composite
{
public static final String ARG_ACCESS_TOKEN_EXPIRES = "fb_accessTokenExpires";
public static final String ARG_GAME_FACEBOOK_NAME = "gameFBName";
public static final String ARG_GAME_FACEBOOK_ID = "gameFBId";
private static FacebookConnectorUiBinder uiBinder = GWT.create(FacebookConnectorUiBinder.class);
interface FacebookConnectorUiBinder extends UiBinder<Widget, FacebookConnector>
{
}
private static FacebookConnector me;
public static FacebookConnector getInstance()
{
if (me == null)
{
me = new FacebookConnector();
}
return me;
}
#UiField
IFrameElement iframe;
private Date accessToken;
private Timer timer;
protected FacebookConnector()
{
initWidget(uiBinder.createAndBindUi(this));
if (ArgManager.getArg(ARG_ACCESS_TOKEN_EXPIRES) != null)
{
accessToken = new Date(Long.parseLong(ArgManager.getArg(ARG_ACCESS_TOKEN_EXPIRES)));
}
}
public void checkAccessToken(final AbstractAsyncCallback<Void> callback)
{
if (accessToken == null || accessToken.before(new Date()))
{
// send authentication
String url = "https://graph.facebook.com/oauth/authorize?client_id="
+ ArgManager.getArg(ARG_GAME_FACEBOOK_ID) + "&scope=user_birthday,email&redirect_uri="
+ ArgManager.getArg(ArgManager.ARG_URL_FACEBOOK_BASE) + "page/facebook-step2%3FgameName%3D"
+ ArgManager.getGameShortcut();
iframe.setSrc(url);
// check url
timer = new Timer() {
#Override
public void run()
{
ClientFactory.getInstance().getService().getAccessTokenExpires(new AbstractAsyncCallback<Date>() {
#Override
public void onSuccess(Date result)
{
super.onSuccess(result);
if (result != null && result.after(new Date()))
{
accessToken = result;
// call the callback
callback.onSuccess(null);
}
else
{
// try again in one second
timer.schedule(1000);
}
}
});
}
};
// launch timer in 500 milliseconds
timer.schedule(500);
}
else
{
callback.onSuccess(null);
}
}
}
Hope it will help you.
You can't simply do a server side exchange because that bypasses the user's control of the authorization.
Like others have said, you should use the javascript sdk to facilitate updating the access token. By default, it uses an iframe and falls back on a popup to handle communicating with Facebook. This should work well with your backbone.js application.
I like to define a javascript function that takes success and denied callbacks to execute after checking the facebook auth status:
function checkFBAuth(success, denied, scope) {
FB.getLoginStatus(function (response) {
if (response.status === 'connected') {
success(response);
} else {
FB.login(function(response) {
if (response.status === 'connected') {
success(response);
} else {
denied(response);
}
}, scope);
}
});
};
This will go ahead and run FB.login if the user's session has expired. In your success callback, you could also pass response.authResponse.signedRequest as signed_request in your AJAX POST data. This will allow most FB SDK's (for example, the PHP SDK) to recognize and validate the signed request and set the user id and access token. You could also pass the whole response.authResponse data with your POST. That has the accessToken, userID, and expiresIn time.
See https://developers.facebook.com/docs/reference/javascript/FB.getLoginStatus/ for the docs on the Facebook Developers site.
Also, if you enable the offline access deprecation migration, you can exchange access token to extend the expiration date to 60 days instead of the default 2 hours. See https://developers.facebook.com/docs/offline-access-deprecation/
Like #ThinkingStiff said, the key point is that you need to call FB.getLoginStatus() on the client to get the latest access token
These days, all the cool kids are handling their logins and retrieving their access tokens via JavaScript with the SDK. And hey, why not? The users love it!
After the JavaScript SDK retrieves the access token, all AJAX requests to your server will have access to that access token as well. That is, it is automatically passed along with each
AJAX request in the form of a cookie.
So, on the server side, you can retrieve the access token via cookies (our friend StackOverflow has some Answers related to finding that cookie). However, if you do the other cool thing and use the PHP SDK you won't even have to give it a second thought, because it will automatically grab the cookie for you, if it's there!

Categories

Resources