4

Short Question:

Why doesn't my session cookie's expiry time get updated in the browser when my session's expirty time is updated on the server?

Long Question:

I posted a similar question about this a few weeks ago but I didn't have all of the facts at the time. I now have more detail and the nature of the question has changed so I'm posting it as a new question.

First of all, in CakePHP 2, I've set up APP/Config/core.php with the following for the session:

    Configure::write('Session', array(
        'defaults' => 'database',
        'cookie' => 'mycookie',
        'timeout' => 1 // 1 minute - just for testing
    ));

So, I load a page which in my app which creates the session in the database. All good so far.

The session is stamped to expire at 1341288066 which is equal to Tue, 03 Jul 2012 04:01:06 GMT. Again, this is great because that's 1 minute from now. Exactly what I wanted.

If I look in Firefox's cookie screen, I find the cookie just as I would have expected it:

    Name: mycookie
    Content: aqm0gkmjfsuqje019at8cgsrv3
    Host: localhost
    Path: /
    Send for: Any type of connection
    Expires: Tue 03 Jul 2012 11:01:06 AM ICT  // (04:01:06 GMT)

Now, within this 1-minute window, I go back to my app and refresh the page. Then, I check the session to see if it's updated. It shows 1341288122 against the session id aqm0gkmjfsuqje019at8cgsrv3 which is equal to Tue, 03 Jul 2012 04:02:02 GMT which, again, is what I expected. The expiry of the session has been updated to be 1 minute from when I last reloaded the page.

Unfortunately, the cookie in the browser is still set to Expires: Tue 03 Jul 2012 11:01:06 AM ICT (ie: 04:01:06 GMT) and that's exactly what it does, meaning that the next time I press refresh, Cake generates a brand new session ID even though the old one is still technically valid.

My question is basically what is going on here? Why doesn't the cookie get updated with the new expiry date in the browser?

Community
  • 1
  • 1
Joseph
  • 2,737
  • 1
  • 30
  • 56
  • If you are using filesystem for your session date are the folders writable? app/tmp should be writable. – David Yell Jul 16 '12 at 14:14
  • 1
    @DavidYell The sessions are being updated fine. It's the cookie expiry date on the client machine(s) that isn't being updated. – Joseph Jul 17 '12 at 02:46
  • I could reproduce this and would have expected it to work differently, like you. Filed a bug, let's see if we got it all wrong... http://cakephp.lighthouseapp.com/projects/42648-cakephp/tickets/3047-session-cookie-timeout-is-not-refreshed – pixelistik Jul 18 '12 at 09:48
  • @pixelistik Well, Mark Story has set a milestone for it, so I guess we weren't imagining things :-) Thanks for posting the bug, I wouldn't have been able to explain it that clearly myself. Why don't you go ahead and post an answer to this question to explain that this a shortcoming of CakePHP which will be addressed in 2.3.0 and I'll mark it as the correct answer and award the bounty I promised. – Joseph Jul 19 '12 at 03:45
  • @Joseph OK, I tried to wrap it up in an answer. Thanks for spotting this! – pixelistik Jul 19 '12 at 10:09

3 Answers3

4

The issue you have spotted is indeed unexpected and ends sessions where they should stay alive.

This is the result of how CakePHP uses the Session functions of PHP. There is an entry (#3047) in the CakePHP bugtracker, where Mark Story (CakePHP developer) agrees this should be fixed

I can agree that the cookies should be updated alongside the session times stored in the session. However, that's not how PHP's internal features for session handling work. There seem to be a few different ways to workaround this issue.

As this will change the current behavior (however weird it may be), the fix is postponed to version 2.3, though.

I think managing the cookie state outside of PHP is going to be the most appropriate solution. I don't know how safe of a change this is for existing applications though. Changing how sessions works can be dramatic change and allowing users to stay logge din much longer might not be what all developers are expecting.

pixelistik
  • 7,541
  • 3
  • 32
  • 42
  • Thank you for confirming that I'm not crazy :-) I just marked your answer as correct and awarded the bounty. – Joseph Jul 20 '12 at 02:50
  • I always wondered myself what the problem was. Until then you can use the AutoLogin component for your users not to notice the continuous logouts: http://www.dereuromark.de/2012/02/02/more-persistent-sessions-in-cake2-x/ – mark Jul 25 '12 at 12:50
  • Was this issue addressed in version 2.3 or above? I've read the release notes, but can't find anything obvious. – Bill Rollins Apr 01 '14 at 14:29
3

This appears to be how PHP handles sessions. PHP does not update the cookie on each request (see: http://php.net/manual/en/function.session-set-cookie-params.php#100672). Instead of relying on the expiry time in this cookie, CakePHP compares the current time with the actual session timeout in Session::_validAgentAndTime().

jeremyharris
  • 7,884
  • 22
  • 31
  • I wouldn't expect PHP to update the cookie on each request but if I specifically set a new expiry time for the session in CakePHP and that expiry time is *past* the expiry time of the cookie, shouldn't CakePHP be making some sort of effort to modify the cookie expiry time? If it can't, then why is it possible to extend the life of the session beyond the life of the cookie as it was initially set? An extended session is useless if the cookie has already expired and can't be extended. – Joseph Jul 17 '12 at 02:51
  • Maybe it should, maybe it shouldn't. It's just two different behaviors. 1 (current behavior): user moves around site *longer* than cookie, session ends when they close the browser because the cookie has expired; 2 (possible other behavior by updating cookie): user moves around site, session ends X seconds after last visit. If you prefer the cookie to extend on each request, you could write a custom session handler. – jeremyharris Jul 17 '12 at 14:55
  • But how can CakePHP know the session ID, if the cookie has already expired in your scenario 1? That's what it boils down to, IMO. – pixelistik Jul 17 '12 at 15:42
  • When cookies are cleared is up to the browser. Chrome clears them as they expire, but Firefox seems to keep it around (I couldn't find consistency). This would mean, in Fx, that the PHP session would remain valid because the cookie still exists. I don't know if PHP internally manually invalidates the cookie or not, but I don't think it does judging from the fact that sessions exist past the cookie's expiration time. I imagine in Chrome, you'd be logged out right after the cookie expired. Inconsistent :/ – jeremyharris Jul 17 '12 at 16:21
  • @pixelistik That's exactly the problem, CakePHP 'forgets' the session ID as soon as the cookie expires even through the session is still valid. This is the whole point of my question. – Joseph Jul 18 '12 at 02:26
  • @jeremyharris I don't need to write a custom session handler to keep updating the expiry time of the session because CakePHP already does this. You can see proof of this by watching the UNIX timestamp update in the session file every time you refresh the browser. The problem is that the timestamp on the session will eventually update beyond the timestamp on the timestamp on the cookie (which remains fixed) and then, as pixelistik pointed out, CakePHP will no longer know the session ID to use because there is no valid cookie. – Joseph Jul 18 '12 at 02:29
  • I'm completely on the same page as you, FWIW. The custom session handler idea was so you could update the cookie on each request, not the session. I've used Cake's (which in turn is PHP's) default session behavior on many apps. All I'm saying is that this is PHP's default behavior, albeit misguided perhaps. Why Cake doesn't force update the cookie? Dunno, but less magic is always good thing. – jeremyharris Jul 19 '12 at 14:07
0

The problem can be solved by using the two parameters in combination.

Configure::write('Session', array(
    'cookie' => 'CAKEPHP',
    'defaults' => 'php',
    'timeout' => 60,                // 60 minutes: Actual Session Timeout
    'cookieTimeout' => 1440,        // 1440 minutes: 24 hrs: Actual Cookie Timeout
    'autoRegenerate' => true,
    'requestCountdown' => 1,
    'checkAgent' => false,
));
  • autoRegenerate: generates Session Cookie after refresh. The refresh count after which the Session Cookie should be regenerated is determined by the next parameter.
  • requestCountdown: keep the value of this parameter as low as possible. This is the number of refresh/reload after which the Session Cookie will regenerated.
Abhishek Mugal
  • 511
  • 3
  • 9