BK15
(Bhavith Kulal)
October 27, 2025, 9:52am
1
Hi,
I am using a ThymeLeaf login page for my Vaadin App.
Login is handled with spring security,
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(
auth -> auth.requestMatchers("/login", "/css/**").permitAll().anyRequest().authenticated())
.formLogin(form -> form.loginPage("/login").loginProcessingUrl("/process-login")
.defaultSuccessUrl("/home", true).failureUrl("/login?error=true").permitAll())
.logout(logout -> logout.logoutUrl("/logout").logoutSuccessUrl("/login?logout=true").permitAll())
.csrf(csrf -> csrf.disable());
http.sessionManagement(session -> session.invalidSessionUrl("/login?timedOut"));
return http.build();
}
and timeout

server.servlet.session.timeout=10m
After the session expires (as per the session.timeout setting),we see a banner with the message:
“Invalid JSON from server:” followed by the HTML source of the login page.
and on clicking that the redirect to login page happens.
Ideally, when the session expires, I want to display a custom session expired message or redirect to the login page rather than showing the “Invalid JSON” banner.
How can I achieve this?
knoobie
(Christian Knoop)
October 27, 2025, 10:00am
2
BK15
(Bhavith Kulal)
October 27, 2025, 11:51am
3
Forcing a Page Reload After an Invalid Server Response
If the XHR response can’t be parsed as JSON, Vaadin looks for a “Vaadin-Refresh” string anywhere inside the response text. If it’s present, Vaadin reloads the page instead of showing an error message. Usually such responses are served by some 3rd party servers and then you need to add the refresh token as a meta tag to the HTML page served by it.
Based on the docs my understanding is adding
<meta name="refresh" content="Vaadin-Refresh">
should trigger the page reload in the event of an invalid response. However, it doesn’t seem to resolve the issue on my end.
knoobie
(Christian Knoop)
October 27, 2025, 12:05pm
4
Are you sure you have applied it correctly? Does your Notification’s content change / is the refresh information in there?
BK15
(Bhavith Kulal)
October 27, 2025, 12:32pm
5
Yes the refresh meta tag is also shown.
knoobie
(Christian Knoop)
October 27, 2025, 12:59pm
6
Then I would suggest to create a bug report.
Guttorm
(Guttorm Vik)
October 27, 2025, 4:21pm
7
Something missing from the documentation is that you can tell Vaadin which url to go to.
We have this in the login page html from our Vaadin7 days:
<!-- This tells Vaadin to load "/ptsmc/app" if the server responds to an ajax request with this page (when user session is no longer valid): -->
<!-- Vaadin-Refresh:/ptsmc/app -->
1 Like
BK15
(Bhavith Kulal)
October 28, 2025, 11:37am
8
Adding the space after the Vaadin-Refresh token fixes the issue.
(e.g. <meta name="refresh" content="Vaadin-Refresh "> )
opened 02:06PM - 27 Oct 25 UTC
workaround
Impact: Low
Severity: Major
### Description of the bug
According to the docs [forcing-a-page-reload-after-a… n-invalid-server-response](https://vaadin.com/docs/latest/flow/advanced/modifying-the-bootstrap-page#forcing-a-page-reload-after-an-invalid-server-response)
Adding `<meta name="refresh" content="Vaadin-Refresh">` to the response should refresh the page for Invalid server response, but it doesn't seem to be working.
[Forum Post ](https://vaadin.com/forum/t/redirecting-on-session-timeout/178699)
without refresh meta tag
<img width="1593" height="122" alt="Image" src="https://github.com/user-attachments/assets/01ccf09d-ad86-4161-ab1a-f4425f8ee3c9" />
with refresh meta tag
<img width="1593" height="162" alt="Image" src="https://github.com/user-attachments/assets/72eae838-01d0-4ea8-918e-25814c52df51" />
### Expected behavior
The page refreshes without showing the Invalid server error notification.
### Minimal reproducible example
Download a starter project,
add the following
`spring-boot-starter-thymeleaf` dependency
**login.html** page under resources/templates/
```
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta name="refresh" content="Vaadin-Refresh">
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<form th:action="@{/process-login}" method="post">
<h2>Login</h2>
<div>
<label>Username:</label>
<input type="text" name="username" required />
</div>
<div>
<label>Password:</label>
<input type="password" name="password" required />
</div>
<button type="submit">Login</button>
</form>
</body>
</html>
```
**LoginController.java**
```
@Controller
public class LoginController {
@GetMapping("/login")
public String login() {
return "login";
}
}
```
**SecurityConfig.java**
```
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
var user = User.withUsername("user").password(passwordEncoder.encode("user")).roles("USER").build();
return new InMemoryUserDetailsManager(user);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(
auth -> auth.requestMatchers("/login", "/css/**").permitAll().anyRequest().authenticated())
.formLogin(form -> form.loginPage("/login").loginProcessingUrl("/process-login")
.defaultSuccessUrl("/home", true).failureUrl("/login?error=true").permitAll())
.logout(logout -> logout.logoutUrl("/logout").logoutSuccessUrl("/login?logout=true").permitAll())
.csrf(csrf -> csrf.disable());
http.sessionManagement(session -> session.invalidSessionUrl("/login?timedOut=true"));
return http.build();
}
}
```
add a session timeout `server.servlet.session.timeout`
Once the session times out the invalid json from server : {login page html} is shown even though the refresh meta tag is added.
### Versions
- Vaadin / Flow version:24.9.0
- Java version:21