How often is a Facebook Connect session refreshed? - oauth

I have set up Facebook Connect on my site, and the login is working fine. I have set up a listener to detect a login state change, as follows:
FB.Event.subscribe('auth.sessionChange', function() {
window.location.reload();
});
All good. Except that leaving a browser window open causes the page to reload after perhaps 20mins. So the auth.sessionChange is firing at some interval. Which can caused havoc, particularly if the last page was a POST form submission.
In the FB docs it says "Sessions are refreshed over time as long as the user is active with your app." How often is this session refreshed?
And how can I protect the page from reloading if it doesn't need to? A conditional maybe within that function??
EDIT - adding information for clarification:
I thought I would add some info to give those offering the advice some more to go on (thanks so far BTW):
the reason I have the listener triggering a reload is because I wanted users to be logged in to the site every time they visit - if they already had a session in FB. I was detecting an active session with the JS SDK, which I know could do log in on its own, but I needed to trigger a page reload after the JS had done the detection, in order to set a PHP session for the site - required step. I couldn't do the PHP login without first letting the JS detect the FB session in the browser.

Usually you can see the length of the validity of the session just by looking at the session itself. However in many cases, I suggest requesting the offline_access permission to ensure the access_token remains valid as long as the user doesn't change their password and doesn't remove your application.

Andy, if you are only listening for login state then subscribe to auth.login and auth.logout instead of auth.sessionChange.
If you need an active session for a user to take an action on your site, use FB.getLoginStatus() or FB.getSession() to check the session object.
http://developers.facebook.com/docs/reference/javascript/FB.getLoginStatus/
http://developers.facebook.com/docs/reference/javascript/FB.getSession/

It really depends on your App work-flow and the below is just a general approach.
You can have a flag that presents in all your pages (maybe in your main layout if you are using a template system) with a setter function to be executed once you don't need a page reload to happen. Something like:
var do_reload = true; // By default, we always allow a reload
FB.Event.subscribe('auth.sessionChange', function() {
if( do_reload ) {
window.location.reload();
}
});
// Call this whenever you don't want 'auth.sessionChange' to reload the page
function turnoff_reload() {
do_reload = false;
}
// Call this to return to default behavior
function turnon_reload() {
do_reload = true;
}
Now if you are "redirecting" the user (e.g.: after a form post) to a page that doesn't require a reload then you need to set the flag in the first line to false.
Another scenario if you have an ajax loaded content based on the user interaction, if the page reloads by itself that content will be lost and the user needs to interact again to view that content, what can be done here is setting the flag to false after the Ajax call.

Related

Laravel Nova Redirect to a custom path after login

I need to redirect user after login to a different place according to its role.
The logic is simple. I tried to put it in redirectPath() function in Nova LoginController.php, but I have a very weird behavior - sometimes after login I reach the right place, sometimes Nova redirects me to panel.
Any idea?
After a couple of hours of investigation, I figured out that the solution is quite simple.
All I had to do is to add the following function to nova LoginController:
protected function sendLoginResponse(Request $request)
{
$request->session()->regenerate();
$this->clearLoginAttempts($request);
$redirectPath = $this->redirectPath();
redirect()->setIntendedUrl($redirectPath);
return redirect()->intended($redirectPath);
}
Explanation:
This function is implemented in trait AuthenticatesUsers.
intended function (member of Redirector class) create a redirect response, based on previously intended location, and if not exists - on given url.
If no url.intended is set in session, user will be redirected to url generated by LoginController::redirectPath. However, if there an entry of url.intended does exist in session, we need to delete it in order to force redirecting user to the url we are interested in.
The only problem which I see is that we loose the feature of redirecting user to the same page he was before he was logged out. So it is a simple matter of choice as a developer...

Benefits of Post-Redirect-Get

When I started with ZF2 the first module I used was ZfcUser. When I debug it's controller's code I found a weird way (at least for me) to manage actions. I found code like
$prg = $this->prg('zfcuser/changepassword');
if ($prg instanceof Response) {
return $prg;
} elseif ($prg === false) {
return array(
'status' => $status,
'changePasswordForm' => $form,
);
}
//VALIDATE FORM AND DATABASE STUFF
(...)
The behaviour is as follows:
The first load $prg is false, so it returns the form.
When you submit the page, $prg is an instance of Response, so it returns $prg.
When $prg is returned, the same function is called again and $prg becomes an array with all the posted data, so it jumps to the validation of form and database stuff.
I thought it was a weird approach so I override all the needed functions replacing this with the simple request->isPost(). I found it easier to handle the first load/data posted.
I didn't give it more importance until now. I'm facing the Post-Redirect-Get approach again when I'm trying to upload files: it seems that is needed to prevent user to re-select the file and re-upload when a validation error rises on a form.
What's the point of the Post-Redirect-Get? When do you recommend the use of it (apart of the commented file upload)?
As the documentation states:
When a user sends a POST request (e.g. after submitting a form), their browser will try to protect them from sending the POST again, breaking the back button, causing browser warnings and pop-ups, and sometimes reposting the form. Instead, when receiving a POST, we should store the data in a session container and redirect the user to a GET request.
So the purpose of this plugin is to improve user experience. You must have came across this problem when you submit a form and try to refresh the page you get a pop-up message like (example from google chrome):
Confirm Form Resubmission: The page that you're looking for used information that you entered. Returning to that page might cause any action you took to be repeated. Do you want to continue?
You can get more details in the docs for Post/Redirect/Get Plugin, or File Post/Redirect/Get Plugin if your form handles files uploads.
NOTE: For the File Post/Redirect/Get Plugin - Example Usage there's a typo on line 16, you should use $this->filePrg() instead of $this->prg(). It should be like the line below.
$prg = $this->filePrg($myForm, '/user/profile-pic', true);

How to redirect and reload the right way in Dart?

What are the preferred ways to do a redirection and a reload in Dart?
Do we just use: window.location.href = window.location.href?
There are a few different ways to handle URI changes and each have their own purpose.
When you want to send the user to another URI:
window.location.assign('http://google.com')
This one sends the user to Google, keeping the browsing history (the back button history). This is like clicking on a link.
window.location.href = 'http://google.com'
The same as above, just another way to do it. href is a setter, and causes the assignment to happen. I feel the previous version is cleaner.
window.location.replace('http://google.com');
However, the replace() method on LocalLocation object does not only send the user to Google, but also does not put the originating page in the session history, which means the user will not suffer from the never-ending back-button nightmare.
This is essentially the same as an HTTP redirect. The history is skipped.
When you want to do a reload/refresh.
window.location.assign(window.location.href)
Reloads the current page to the exact same URI. This does not contain POST data. Some of the resources (like images, etc.) may me reloaded from the cache, so it might not be a full reload.
This is essentially the same as pressing F5 and skipping the sending of POST data.
window.location.href = window.location.href
Again, the same as previous.
window.location.reload()
This way of reloading the page causes also the POST data to be sent. The "JavaScript version" of window.location.reload() also supports a parameter that specifies whether to skip the cache or not. However, the current Dart implementation does not support that parameter, and defaults to fetch the resources from cache.
This cache parameter may be added to Dart at some point, but it's not there yet. When it arrives, you most likely just pass true as the first parameter and then it would be like Ctrl + Shift + R.
Summary
I want to simulate a click on <a> tag.
Use window.location.assign(url).
I want to redirect to a new website like the HTTP redirection and skip the back-button history.
Use window.location.replace(url).
I want to do an F5 with POST data.
Use window.location.reload().
I want to do an F5 without POST data.
Use window.location.assign(window.location.href).
I want to do an Ctrl + Shift + F5.
Not available, maybe in the future. It would probably be window.location.reload(true).

Store cookie even if the session is closed

What would be the best approach for a Play! application to remember the user? I think the only possible solution is to use the client side cookies, right? But as soon as the browser shuts down, this session is destroyed and not valid for the next request? How did/do you solve(d) this?
As for now, I ser the crypted userid in the session (per session), like this:
session("userid", user.id);
And then I use the interceptor to avoid passing parameters every when I need them oft, like described here: How to avoid passing parameters everywhere in play2?
But how to remember the user, or even beter, automatically log the user in on the next request?
EDIT: 2016-03-11
Be aware that some browser may store the session cookie for a longer period. For instance you can set in Chrome to remember the open tabs on next visit. This means that the Play Session cookie will be restored next time you open the browser.
And as of Play 2.4 the session cookie maxAge (you need to set in the application.conf) is renamed to: play.http.session.maxAge
To make the session not time-out when a users closes their browser you can use the session.maxAge parameter in the application.conf.
e.g.:
# Set session maximum age in seconds (4w)
session.maxAge=2419200
Quoting from Play 2.0 Session Documentation:
There is no technical timeout for the Session. It expires when the user closes the web browser. If you need a functional timeout for a specific application, just store a timestamp into the user Session and use it however your application needs (e.g. for a maximum session duration, maxmimum inactivity duration, etc.).
For security reasons, modern browsers will invalidate cookies on exit, and this is not something you can change simply because it would allow hackers to bad things with credentials that they do not rightfully have.
I would reevalutate whether or not you truly want the user to stay logged in, since it is usually a security risk to do so. If, however, you decide that you still want the user to stay logged in, you will have to try something that is not cookie based, and at the moment, I'm not sure what that would look like.
If you don't force a newSession or the user doesn't remove the cookies, the user should still be logged in.
It may be that your browser is set up to remove cookies when closing, or you are suffering from an external sideeffect. But I can confirm that cookies persist in my dev environment (in both Chrome and Firefox) after closing the browser.
I tried this and it worked for me. It's basically a composed Action.
def RememberAction(f: Request[AnyContent] => Result): Action[AnyContent] = {
Action { request =>
if(!request.session.get("email").isDefined && request.cookies.get("remember-email").isDefined) {
f(request).asInstanceOf[PlainResult].withSession("email" -> request.cookies.get("remember-email").get.value)
} else {
f(request)
}
}
}
Then you can use this Action in your controllers like this:
def index = RememberAction { implicit request =>
Ok("Hello World!")
}

Firefox abort content.location load

I'm developing a firefox extension. Inside my extension I use:
content.location.assign(url)
Depending on the users input content.location.assign(url) gets called again after a short time. It seems like my 2nd assign gets ignored. I'm looking for a way to abort the in process request to push trough the current one.
If I'm not wrong, try using either of this methods:-
reload(forceget)
Reload the document from the current URL. forceget is a boolean, which, when it is true, causes the page to always be reloaded from the server. If it is false or not specified, the browser may reload the page from its cache.
replace(url)
Replace the current document with the one at the provided URL. The difference from the assign() method is that after using replace() the current page will not be saved in session history, meaning the user won't be able to use the Back button to navigate to it.
You shouldn't use content.location to load a new page into the browser; instead use loadURI(url[, referrer[, postData[, allowThirdPartyFixup]]]) to load a page and BrowserStop() to cancel a load.

Resources