Docs

Documentation versions (currently viewingVaadin 24)
Documentation translations (currently viewingEnglish)

Add Login

In this guide, you’ll learn how to create a login view using Vaadin Flow. A hands-on mini-tutorial at the end will walk you through enabling Spring Security, setting up in-memory authentication, and integrating a login form into a real Vaadin application.

Warning
Never Use Hard-Coded Credentials In Production
In-memory authentication is convenient for development, but production applications must use a more secure approach, such as JDBC authentication, LDAP authentication, or OAuth 2.0. Refer to the Spring Security Reference Manual for more details.

The Login View

The login view is a standard Vaadin Flow view. The easiest way to implement one is by using the LoginForm component:

Source code
LoginView.java
@Route(value = "login", autoLayout = false) 1
@PageTitle("Login")
@AnonymousAllowed 2
public class LoginView extends Main implements BeforeEnterObserver {

    private final LoginForm login;

    public LoginView() {
        addClassNames(LumoUtility.Display.FLEX, LumoUtility.JustifyContent.CENTER,
            LumoUtility.AlignItems.CENTER);
        setSizeFull();
        login = new LoginForm();
        login.setAction("login"); 3
        add(login);
    }

    @Override
    public void beforeEnter(BeforeEnterEvent event) {
        if (event.getLocation()
                 .getQueryParameters()
                 .getParameters()
                 .containsKey("error")) {
            login.setError(true); 4
        }
    }
}
  1. Disables auto layout to prevent the login view from being embedded in a router layout.

  2. Allows anonymous access so users can access the login page without authentication.

  3. Instructs the login form to send a POST request to /login for authentication.

  4. Handles login failures by checking for the ?error query parameter and displaying an error message.

Spring Security’s form login mechanism automatically processes authentication requests sent to /login. When authentication fails, the user is redirected back to the login page with ?error, which the login view handles.

Tip
If your application’s root package is com.example.application, place the login view inside: com.example.application.security.ui.view

Configuration

To instruct Spring Security to use your login view, modify your security configuration:

Source code
SecurityConfig.java
@EnableWebSecurity
@Configuration
@Import(VaadinAwareSecurityContextHolderStrategyConfiguration.class)
class SecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // Configure Vaadin's security using VaadinSecurityConfigurer
        http.with(VaadinSecurityConfigurer.vaadin(), configurer -> {
            configurer.loginView(LoginView.class);
        });

        return http.build();
    }
    ...
}

Now, when a user tries to access the application, they’ll be redirected to the login page.

Important
By default, Vaadin restricts access to Flow views and router layouts. Unless explicitly permitted, even authenticated users will be unable to access views. This is covered in more detail in the Protect Views guide.

Try It

In this mini-tutorial, you’ll enable security and add a login form to a real Vaadin application. This serves as a foundation for future security-related mini-tutorials.

Set Up the Project

First, generate a walking skeleton with a Flow UI, open it in your IDE, and run it with hotswap enabled.

Note
Security configuration changes may require a manual restart for them to take effect. Hotswap may not be enough.
Add the Spring Security Dependency

Add the following Spring Security dependency to pom.xml:

Source code
XML
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
Create the Security Configuration Class

Create a new package: [application package].security

Inside this package, create a SecurityConfig class:

Source code
SecurityConfig.java
import com.vaadin.flow.spring.security.VaadinAwareSecurityContextHolderStrategyConfiguration;
import com.vaadin.flow.spring.security.VaadinSecurityConfigurer;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.provisioning.UserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@EnableWebSecurity
@Configuration
@Import(VaadinAwareSecurityContextHolderStrategyConfiguration.class)
class SecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // Configure Vaadin's security using VaadinSecurityConfigurer
        http.with(VaadinSecurityConfigurer.vaadin(), configurer -> {
        });

        return http.build();
    }

    @Bean
    public UserDetailsManager userDetailsManager() {
        LoggerFactory.getLogger(SecurityConfig.class)
            .warn("Using in-memory user details manager!");
        var user = User.withUsername("user")
                .password("{noop}user")
                .roles("USER")
                .build();
        var admin = User.withUsername("admin")
                .password("{noop}admin")
                .roles("ADMIN")
                .build();
        return new InMemoryUserDetailsManager(user, admin);
    }
}
Create the Login View

Create a new package: [application package].security.ui

Inside this package, create a LoginView class:

Source code
LoginView.java
import com.vaadin.flow.component.html.Main;
import com.vaadin.flow.component.login.LoginForm;
import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.BeforeEnterObserver;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.auth.AnonymousAllowed;
import com.vaadin.flow.theme.lumo.LumoUtility;

@Route(value = "login", autoLayout = false)
@PageTitle("Login")
@AnonymousAllowed
public class LoginView extends Main implements BeforeEnterObserver {

    private final LoginForm login;

    public LoginView() {
        addClassNames(LumoUtility.Display.FLEX,
            LumoUtility.JustifyContent.CENTER,
            LumoUtility.AlignItems.CENTER);
        setSizeFull();
        login = new LoginForm();
        login.setAction("login");
        add(login);
    }

    @Override
    public void beforeEnter(BeforeEnterEvent event) {
        if (event.getLocation()
                 .getQueryParameters()
                 .getParameters()
                 .containsKey("error")) {
            login.setError(true);
        }
    }
}
Update the Spring Security Configuration

Modify SecurityConfig to reference the LoginView:

Source code
SecurityConfig.java
@EnableWebSecurity
@Configuration
@Import(VaadinAwareSecurityContextHolderStrategyConfiguration.class)
class SecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // Configure Vaadin's security using VaadinSecurityConfigurer
        http.with(VaadinSecurityConfigurer.vaadin(), configurer -> {
            configurer.loginView(LoginView.class);
        });

        return http.build();
    }
    ...
}
Grant Access to Views and Layout

By default, Vaadin restricts access to all views. Grant access using @PermitAll:

Source code
MainLayout.java
import jakarta.annotation.security.PermitAll;

@Layout
@PermitAll
public final class MainLayout extends AppLayout {
    ...
}
Source code
MainView.java
import jakarta.annotation.security.PermitAll;

@Route
@PermitAll
public final class MainView extends Main {
    ...
}
Source code
TaskListView.java
import jakarta.annotation.security.PermitAll;

@Route("task-list")
@PageTitle("Task List")
@Menu(order = 0, icon = "vaadin:clipboard-check", title = "Task List")
@PermitAll
public class TaskListView extends Main {
    ...
}
Note
@PermitAll allows all authenticated users to access the view.
Test the Application

Restart your application to make sure all your changes have been applied. Navigate to: http://localhost:8080

You should now see the login screen. Login with one of the following credentials:

  • User: user / Password: user

  • Admin: admin / Password: admin

After logging in, you should be able to access the task list view.

Final Thoughts

You have now successfully added authentication to your Vaadin application. Next, learn how to log out users by reading the Add Logout guide.