8

I have configured my application for close session on timeout if user do nothing during 10 minutes period. At config.yml I have this:

session:
    handler_id:  ~
    cookie_lifetime: 600 # 10 minutes
    gc_maxlifetime: 600 # 10 minutes
    gc_probability: 1
    gc_divisor: 1

I do a Ajax call every one minute to check if session will be close to expire or doesn't and this is what I check:

public function isLoggedInAction(Request $request)
{
    $response = array();
    $response['authenticated'] = FALSE;
    $status = 200;
    $securityContext = $this->container->get('security.context');
    if ($securityContext->isGranted('IS_AUTHENTICATED_FULLY')) {
        $response['authenticated'] = TRUE;
    }

    return new JsonResponse($response, $status ?: 200);
}

For some unknow reason is not working and every 10 minutes session is closed whether I'm working with page or doesn't, why? I'm missing something?

Edit 1 Tried new values, still not working:

session:
    handler_id:  ~
    cookie_lifetime: 1800
    gc_maxlifetime: 600
    gc_probability: 1
    gc_divisor: 100

While I was working on the page, performing Ajax calls and some other tasks the session was closed so is not working. The only value that apparently works for me til now is set cookie_lifetime: 86400 #1 day which is crazy to me!

Edit 2 After @acontell suggestion for fix the VM time and date I'm trying with this new values (10 minutes takes too long so I've changed to 3):

session:
    handler_id:  ~
    cookie_lifetime: 1800
    gc_maxlifetime: 180 # session will expire after 3 minutes of inactivity
    gc_probability: 1
    gc_divisor: 100

And also I fixed the date/time on the VM by enabling ntpd service and now date is just fine:

[root@webvm var]# date
 Sun Feb  1 18:35:17 VET 2015

But after 5 minutes (function call was executed 5 times) session still alive. This is how I call the function isLoggedInAction() from Javascript side:

$.post(Routing.generate('isLoggedIn',{}),{},'json').done(function (data, textStatus, jqXHR){
    if( data.authenticated ){
        var timer = window.setInterval(function(){
            $.post(Routing.generate('isLoggedIn',{}),{},'json').done(function (data, textStatus, jqXHR){
                if( !data.authenticated ){
                    window.clearInterval(timer);
                    $.growl({
                        message: 'La sesión ha expirado por inactividad, debe <a href=""><b>iniciar seción</b></a> nuevamente.'
                    }, {
                        type: "danger",
                        allow_dismiss: false,
                        timer: 10000,
                        animate: {
                            enter: 'animated fadeInDown',
                            exit: 'animated fadeOutUp'
                        },
                        onHide: function(){
                            location.reload();
                        }
                    });
                }
            }).fail(function(){});
        },60000);
    }
}).fail(function(){});

See the image below:

enter image description here

Test 3

After say all was working fine I did the latest and definitive test: open the application and leave untouched during all the night (almost 8 hours) and surprise it never closes the session. As image below show see how many request the page does and see how session still alive, why?

enter image description here

Ajax call is made every: 10.5 minutes

$.post(Routing.generate('isLoggedIn',{}),{},'json').done(function (data, textStatus, jqXHR){
    if( data.authenticated ){
        var timer = window.setInterval(function(){
            $.post(Routing.generate('isLoggedIn',{}),{},'json').done(function (data, textStatus, jqXHR){
                if( !data.authenticated ){
                    window.clearInterval(timer);
                    $.growl({
                        message: 'La sesión ha expirado por inactividad, debe <a href=""><b>iniciar seción</b></a> nuevamente.'
                    }, {
                        type: "danger",
                        allow_dismiss: false,
                        timer: 10000,
                        animate: {
                            enter: 'animated fadeInDown',
                            exit: 'animated fadeOutUp'
                        },
                        onHide: function(){
                            location.reload();
                        }
                    });
                }
            }).fail(function(){});
        }, 210000);
    }
}).fail(function(){});

Settings say that session should expire passed: 10 minutes.

session:
    handler_id:  ~
    cookie_lifetime: 630000
    gc_maxlifetime: 630000 # session will expire after 10 minutes of inactivity 
    gc_probability: 1
    gc_divisor: 100

Time at server is fine:

[root@webvm sencamer.dev]# date
Mon Feb  2 07:26:53 VET 2015

What else should I check?

Test 5

Ok, I'm still doing test because this has not a good behavior. So, this is what I've do for this test:

  • Open the application and start working on it
  • At some moment stop working and leave the the application made the Ajax call to check whether session still alive or not. (session still alive see image below)
  • After that first call I continue working on the application as image 2 shows but surprise session ends and the application gets close.

Why? What is causing that behavior? Is that right based on my parameters?

This image shows the first and only call to the function

enter image description here

After the call was made I continue working but session gets closed

enter image description here

ReynierPM
  • 17,594
  • 53
  • 193
  • 363
  • have you added session_start() in the top of your php script ? have you restarted your Apache server after updating your yml file ? – Halayem Anis Jan 30 '15 at 16:04
  • @HalayemAnis `session_start()`? That applies here? I don't think so since Symfony does the job perhaps I'm mistaken but is what I understand unti now – ReynierPM Jan 30 '15 at 16:06
  • watch out your gc_probability and gc_divisor. You have both to one and that means that the probability that the garbage collector (GC) process is started on every session initialization is gc_probability / gc_divisor = 1/1 = 1. – acontell Jan 30 '15 at 16:06
  • @acontell I'm not following you, what is wrong with that? – ReynierPM Jan 30 '15 at 16:07
  • it means that there's a 100% chance that the GC process will start on each [request](http://symfony.com/doc/current/reference/configuration/framework.html#session). It could be related to the problem you mention because it throws an error. Try setting gc_divisor to 100 and see if it helps – acontell Jan 30 '15 at 16:09
  • @acontell so, what is the idea? What I should do in order to fix the issue? Change one value? To less or more? Change both? – ReynierPM Jan 30 '15 at 16:10
  • Try changing gc_divisor to 100 and if we're lucky it might solve the problem :) – acontell Jan 30 '15 at 16:11
  • @acontell still not working man, can you give me another idea? – ReynierPM Feb 01 '15 at 22:18
  • @ReynierPM are you using a Virtual Machine? Is the date of the server of your VM set properly? I mean, does it have the correct date? The resulting session cookie will be stamped with an expiry time of time() + cookie_lifetime where the time is taken from the server. It could be possible that, if the server had a bad date, the cookie would expire inmediately. Imagine: server date 2015-01-31, your browser 2015-02-01. Server sends cookie that expires on 2015-01-31 at 11pm, your browser receives a cookie that would expire inmediately. – acontell Feb 01 '15 at 22:45
  • @acontell it's outdated `Fri Jan 30 08:06:07 VET 2015` let me fix this and see if that solves the issue – ReynierPM Feb 01 '15 at 22:48
  • that makes sense :) even the date, if you have a look at it, it makes sense that one day of expiry time worked – acontell Feb 01 '15 at 22:49
  • please, let me know if it works and I could prepare an answer so that if it happens to someone else they know what to do :) – acontell Feb 01 '15 at 22:54
  • @acontell still not working further details on __Edit 2__ at main post – ReynierPM Feb 01 '15 at 23:04
  • @ReynierPM check your configuration, you set `cookie_lifetime: 1800` which means 30 minutes – acontell Feb 01 '15 at 23:06
  • @acontell and should be? which value should be there in order to kill session at 3 (for testing) or 10 (development & production) minutes? – ReynierPM Feb 01 '15 at 23:07
  • it's meassured in seconds, so you should use 180 for 3 minutes and 600 for ten minutes. So `cookie_lifetime: 180` for testing purposes and `cookie_lifetime: 600` for production – acontell Feb 01 '15 at 23:09
  • we can carry on in my answer, here it's getting messy – acontell Feb 01 '15 at 23:15
  • So, have you solved it? – sectus Apr 05 '16 at 11:12
  • @sectus No, I didn't but I move on from this project so I can't test anymore. I am starting a new one and I am pretty sure I will need this so maybe I will come back with the same. Are you working on this? Do you have any solution? – ReynierPM Apr 05 '16 at 13:08
  • @ReynierPM, sadly, no. – sectus Apr 06 '16 at 01:13
  • @sectus are you actively working on something like this? – ReynierPM Apr 06 '16 at 10:46
  • @ReynierPM , I blame this: http://stackoverflow.com/questions/3476538/php-sessions-timing-out-too-quickly , but it need to be tested either. – sectus Apr 07 '16 at 01:24
  • @ReynierPM, wrong, symfony uses its own local path. It seems that session garbage collector uses creation time of session instead of update time. – sectus Apr 07 '16 at 09:20
  • @sectus so, what's the solution? Create our own session timeout? I have read http://stackoverflow.com/questions/3476538/php-sessions-timing-out-too-quickly, http://stackoverflow.com/questions/1516266/how-long-will-my-session-last/1516284 and http://stackoverflow.com/questions/520237/how-do-i-expire-a-php-session-after-30-minutes/1270960#1270960 and still not get a proper solution for the issue, did you test any of them? If so let me know the results on your side – ReynierPM Apr 07 '16 at 13:12
  • 1
    @ReynierPM , stupid, stupid me. ... :^ ) But I have found the solution. It's very easy. Do not specify `cookie_lifetime`. After first visit you got cookie with expiration time which does not update anymore. – sectus Apr 08 '16 at 03:19
  • @ReynierPM, so not setting `cookie_lifetime` helped you? does it solve your issue? – Oleg Abrazhaev Sep 25 '17 at 15:52
  • Hi @OlegAbrazhaev that whas a while ago and I don't remember if I found a solution or which was the solution, I can only say give it a try and let us know if it worked – ReynierPM Sep 25 '17 at 17:23

3 Answers3

1

First, watch out your gc_probability and gc_divisor. If both are set to one, that means that the probability that the garbage collector (GC) process is started on every session initialization is gc_probability / gc_divisor = 1/1 = 1 (100%).

You could leave it to the defaults or give it a higher number in order to reduce the chance of the GC being called.

For instance:

session:
        # handler_id set to null will use default session handler from php.ini
        handler_id:  ~
        cookie_lifetime: 600 # Ten minutes
        gc_probability: 1
        gc_divisor: 10000

Also, if you're using a Virtual Machine, check the date of your server, the resulting session cookie will be stamped with an expiry time of time() + cookie_lifetime where the time is taken from the server.

It could be possible that, if the server had a bad date, the cookie would expire inmediately. Imagine: server date 2015-01-31, your browser 2015-02-01. Server sends cookie that expires on 2015-01-31 at 11pm, your browser receives a cookie with an expiration date that has already passed.

acontell
  • 6,792
  • 1
  • 19
  • 32
  • Still not working, I've changed the values, cleared the cache but PHP side still say `authenticated` on Ajax has made five calls already. The worst part here is that sometimes I'm just working and session just expire and that is killing my brain since I can't find where the problem is. Is there any chance to compare values between cookie and PHP session? Something that gives a better clue? – ReynierPM Feb 01 '15 at 23:17
  • Are you sure that you changed `cookie_lifetime`? in your post you have the variable `gc_maxlifetime` = 180 and `cookie_lifetime` = 1800. In theory, it should work. If no request is made from that session in 3 minutes, the session should expire. – acontell Feb 01 '15 at 23:19
  • Yes, the values are `cookie_lifetime: 180 gc_maxlifetime: 180` and none request has been made other than the Ajax request for check if session still alive or doesn't – ReynierPM Feb 01 '15 at 23:20
  • How often are you making that AJAX request? I mean, you have to make one AJAX request, wait 3 minutes (let's say 3:30) and make another one. If you make one request every minute, the session won't expire – acontell Feb 01 '15 at 23:22
  • Ummm that could be the issue, the only doubt I have is how to make the next call on `3:30` minute? – ReynierPM Feb 01 '15 at 23:25
  • No worries, in the timer that makes the AJAX call just change the 60000 to, let's say 210000 (three minutes and a half). First AJAX call should succeed, but the one within the timer shouldn't – acontell Feb 01 '15 at 23:29
  • Excellent, for now it works if I have any problem or question I'll comeback thanks for your time – ReynierPM Feb 01 '15 at 23:34
  • Well, is not working man, I don't know why and what else to do at this point, any other clue? – ReynierPM Feb 02 '15 at 12:04
  • @ReynierPM Your settings are wrong. First off, your cookie lifetime is 630000 seconds which translates in more than a week (not 10 minutes of inactivity but more than a week). It is completely natural that the session didn't expire. Secondly, you are making ajax calls every 210000 ms which translates in 3.5 minutes (not 10.5 minutes as you suggest in your post). – acontell Feb 02 '15 at 12:20
  • Waits a minute, that values are expressed on miliseconds or seconds? That's a confusion for me – ReynierPM Feb 02 '15 at 12:23
  • The timer of the setInterval in javascript is expressed in milliseconds so 210000 = 3.5 minutes. `cookie_lifetime` is expressed in seconds so 630000 = more than a week. – acontell Feb 02 '15 at 12:24
  • So, right values are: for `setInterval` `630000` miliseconds which translate into 10.5 minutes and for `cookie_lifetime` and `gc_maxlifetime` `630` seconds which translate in 10.5 minutes, those are right? – ReynierPM Feb 02 '15 at 12:27
  • Yes, that sounds correct :) set the `cookie_lifetime` to 600 to make the session expire after 10 minutes of inactivity – acontell Feb 02 '15 at 12:28
  • sorry man to bother you again but see __Test 5__ edit something is wrong with this, can you help me around this new behavior? It's right? – ReynierPM Feb 02 '15 at 16:12
  • @ReynierPM it's difficult to track an error without knowing exactly what you've been doing and this can become endless. From my experience, Symfony manages sessions pretty well, it sometimes throws you out of sessions because of the GC process, but you can either get rid of it (`gc_probability: 0`, never tried this approach though) or lower its chance to get called (what I usually do, `gc_divisor: 10000`). I think the rest is ok and should work. I can't help you further, good luck :) – acontell Feb 02 '15 at 16:49
0

try with these parameters :

gc_probability: 0
gc_divisor    : 1000
Halayem Anis
  • 7,654
  • 2
  • 25
  • 45
0

I know this question is old but this is tricky question and it helped me building something so here is how you can build it in symfony 4+

It is explained in the doc https://symfony.com/doc/current/components/http_foundation/session_configuration.html but still tricky, so there is a sample configuration

parameters.yaml

parameters:
    session_lifetime: 1800 # 30 minutes

framework.yaml

framework:
    session:
        handler_id: 'session.handler.native_file'
        save_path: '%kernel.project_dir%/var/sessions/%kernel.environment%'
        use_cookies: true
        cookie_secure: auto
        cookie_samesite: lax
        cookie_lifetime: 0 # cookie is destroyed when the browser is close
        gc_divisor: 100
        gc_probability: 100 # garbage collector process on each request (100/100)
        gc_maxlifetime: '%session_lifetime%' # session is destroyed after lifetime of user idle

twig.yaml

twig:
     globals:
         session_lifetime: '%session_lifetime%' # so you can use the variable in any template

AbstractController

// extend this one in the controllers
class AbstractController extends SymfonyAbstractController
{
    /**
     * @Route("/is-logged-in", name="is_logged_in")
     */
    public function isLoggedIn(Security $security)
    {
        $response = ['authenticated' => false];
        if ($security->isGranted('IS_AUTHENTICATED_FULLY')) {
            $response['authenticated'] = true;
        }

        return new JsonResponse($response);
    }
}

app.js

checkLoggedIn = function (isLoggedInUrl, loginUrl, sessionLifeTime) {
    
    let timer = window.setInterval(function () {
            $.ajax({
                url: isLoggedInUrl,
                method: 'GET',
                success: function (data) {
                    if (data['authenticated'] === true) {
                        console.log('checkLoggedIn OK');
                    } else {
                        window.clearInterval(timer);
                        // you can use any message system you want here instead of Toasts
                        $(document).Toasts('create', {
                            title: 'Warning',
                            body: 'Session expired, <a href="' + loginUrl + '">please reconnect</a>',
                            class: 'bg-danger',
                        });
                    }
                }
            })
        },
        (sessionLifeTime + 60) * 1000 // the login check will be sent 60 sec after session supposed expiration
    );
}

your_base_template.html.twig

<script>
    checkLoggedIn("{{ path('is_logged_in') }}", "{{ path('security_login') }}", {{ session_lifetime }});
</script>
job3dot5
  • 862
  • 7
  • 7