Vaadin refreshes current page after timeout and hearbeats

Hello everyone!

We are facing a behavior problem: when timeout reaches, after three hearbeats, current page is refreshed instead of being forwarded to login page because user is supposed not being logged in anymore.

current config for testing is:

server:
  servlet:
    session:
      timeout: 30
vaadin:
  closeIdleSessions: true
  heartbeatInterval: 20

if I change to this:

server:
  servlet:
    session:
      timeout: 30
vaadin:
  closeIdleSessions: true
  heartbeatInterval: -1

With no hearbeat at all, the page is still displayed but any request to server will forward to login page as user has been logged off by timeout.

I am using :

  • Vaadin 24.8.3
  • Spring boot 3.5.6
  • Java 21

Thank you for your help to understand this tricky behavior

20 seconds is too short value for a heartbeat. Browser tab sleep mechanism can interfere in that case and cause three lost heart beats ans explains the behavior. The default 5 minutes is ok in most cases. No point to use less than minute.

These configs are just for testing.
In production timeout is set to 30 minutes et heartbeat to 5 minutes.
Same behavior as described

Do you have token based SSO login?

No SSO Login, simple login/password, session managed by SpringSecurity inside one app

I think there is a bit of confusion here about the role of the heartbeats.
The heartbeat goal is to keep the server-side UI alive while the browser page is still open on a Vaadin application page. If the browser gets close, the heartbeats are not sent anymore, and after 3 missing requests, the server-side UI is closed.

What I think you want is something different: if the user is idle and the session timeout is reached, you want the browser to be redirected to the login page.

So there is a distinction between UI expiration and User session expiration (and by User session here we mean the Vaadin session, not the HTTP session)

You can look at the linked documentation for a better explanation, but in short:

the heartbeats keep the UI active, but if there are only heartbeat requests for the amount of time defined as HTTP session timeout, the Vaadin session gets closed and a Session expired message is sent to the client, that reacts based on the SystemMessages settings (usually the client reloads the current page).

However, as pointed out in the docs, User session expiration does not mean HTTP session expiration

User session expiration does not imply the underlying HTTP session being invalidated. HTTP session invalidation can be performed by invoking invalidate on the WrappedSession accessible through VaadinSession.

This means that when page reload happens, the HTTP session is still valid, so the user is still authenticated.

To make sure the user is logged out, you need to invalidate the http session explicitly

You can handle user session expiration on the server side with a SessionDestroyListener , as described in User Session.

I hope this clarifies things for you

2 Likes

Thank you very much for your explanations :+1:
Handling user session expiration with SessionDestroyListener solved the problem.

So, ok my UI is closed after three missing heartbeats. Fine.
Session was not supposed to be destroyed/closed if no UI is active?

Quote from the docs

Note, however, that the heartbeat mechanism is only effective as long as there is at least one open UI. This happens because the detection of closed UIs on the server is only done every time there is a Vaadin request to the same session. Thus, if the user closes the entire browser window, waiting for three missed heartbeats doesn’t automatically free the UIs for garbage collection. The normal User Session Expiration mechanism covers situations where all UIs have been closed.

So if you close the browser and there are no other requests to the server, the VaadinSession will be closed when the HTTP session expires

Ok!
If I set

  • closeIdleSession to true
  • heartbeatinterval to 60
  • session timeout to 200 //(3 * 60 + 20)

Case 1: one tab, login, user doing nothing with tab opened
UI never closes
session will be destroyed after session timeout

Case 2: one tab, login, user open new blank tab, user closes UI tab
UI closes at heartbeatinverval * 3
session will be destroyed after session timeout

Case 3: one tab, login, user closes browser
UI closes at heartbeatinverval * 3
session will be destroyed after session timeout

am I right?
maybe there is a mechanism telling you must achieve one heartbeat before it procs?

I would say that:

Case 1: heartbeat will keep the HTTP session alive; however, after 200 seconds (?) the UI gets closed as inactive and the browser page is reloaded (SystemMessages default). HTTP session will not expire (unless you do it manually in a Vaadin SessionDestroyListener)

Case 2: I don’t understand the blank tab; but if the UI tab is closed and there are no other tabs making requests to the VaadinServlet the UI will not be closed, but the HTTP session will expire after timeout

Case 3: it seems to me exactly the same as Case 2 (unless I misunderstood the blank tab): UI gets closed after three missing heartbeats only if some other request for the same session comes in.

Thank you for your answer!
Blank tab case is “new tab is opened on browser”

Ok so there is no shortcut at all using heartbeat to close Vaadin Session when no UI is active.
In Vaadin 14 that was the case wasn’t it?
Is there such mechanic in Vaadin 24 ?

Heartbeat is based on requests from the client, so if there are no browsers contacting the server for a given HTTP session, nothing will do the cleanup job. The session will be destroyed after its defined timeout, causing then the invocation of Vaadin listeners (e.g., SessionDestroyListener)

I don’t remember how it works in Vaadin 14, but I guess it is the same or similar.

Ok so there is no shortcut at all using heartbeat to close Vaadin Session when no UI is active.

Can you explain what you exactly want to achieve?

According to Documentation and your answer everything is clear.

What I want to achieve is closing a VaadinSession when its last attached UI has been closed without waiting for session timeout.
Of course if user click properly on logout button everything is fine!

I think you should set up your own cleanup job for this; something like getting references to created VaadinSession and periodically checking their UI state (e.g. VaadinService.isUIActive()). Once all UIs are inactive, close the session.
You can take a look at how cleanup is done in VaadinService.cleanupSession().

Perhaps someone else has better suggestions.

After several tests, doing WrappedSession.invalidate like we talked here works, it’s a fact.

Just, sometimes WrappedSession has already bean invalidated or is about to be invalidated so IllegalStateException may pop out.

Why do I need this?
The case I saw is :

server:
  servlet:
    session:
      timeout: 120
vaadin:
  closeIdleSessions: true
  heartbeatInterval: 60

In this case, if user idles on an opened tab, if I do not invalidate manualy the session, it will remain forever.

this case does not

server:
  servlet:
    session:
      timeout: 70
vaadin:
  closeIdleSessions: true
  heartbeatInterval: 60

I think something goes wrong when timeout and heartbeat are sent at same time, what would you think about this everyone?

Just a guess: session timeout is expressed in seconds, so with 70 it could be that the heartbeat is never sent because the session expires before

Heartbeats are sent.
Vaadin Session destroy operates at 2 minutes, not 1:10 (70s)
Because it needs to fail a heartbeat to trigger destroy actions

Makes sense. Heartbeat keeps HTTP session active, but on on the second heartbeat (120) vaadin detects that there were no UIDL requests in 70 seconds, so the UI is closed

If timeout is 120 and heartbeat is 60, spring session idle time does not exceed 60

If timeout is 70 and heartbeat is 60, idle time can reach 60 when checked…
But…
Why Spring session compares timeIdle to 60 as maxInactiveInterval??
Because my timeout may be rounded by 60.
So 70 turns into 60.

This example works only because Spring session expires at the same time of the first heartbeat.