> Markdown version of [Flow](https://vaadin.com/docs/v24/building-apps/security/add-login/flow). Section index: [llms.txt](https://vaadin.com/docs/v24/building-apps/llms.txt)

# Flow 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](https://docs.spring.io/spring-security/reference/servlet/authentication/index.html) for more details.

## <a id="the-login-view"></a>The Login View

The login view is a standard [Vaadin Flow view](https://vaadin.com/docs/v24/building-apps/views/add-view/flow.md). The easiest way to implement one is by using the [LoginForm](https://vaadin.com/docs/v24/components/login.md) component:

LoginView\.java

```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](https://vaadin.com/docs/v24/building-apps/views/add-router-layout.md).

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`

## <a id="configuration"></a>Configuration

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

`SecurityConfig.java`

```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 -> {
// tag::snippet[]
            configurer.loginView(LoginView.class);
// end::snippet[]
        });

        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](https://vaadin.com/docs/v24/building-apps/security/protect-views.md) guide.

## <a id="try-it"></a>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](https://vaadin.com/docs/v24/getting-started/start.md), [open](https://vaadin.com/docs/v24/getting-started/import.md) it in your IDE, and [run](https://vaadin.com/docs/v24/getting-started/run.md) 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`:

```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:

`SecurityConfig.java`

```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:

LoginView\.java

```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`:

`SecurityConfig.java`

```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 -> {
// tag::snippet[]
            configurer.loginView(LoginView.class);
// end::snippet[]
        });

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

Grant Access to Views and Layout

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

MainLayout.java

```java
import jakarta.annotation.security.PermitAll;

@Layout
// tag::snippet[]
@PermitAll
// end::snippet[]
public final class MainLayout extends AppLayout {
    ...
}
```

MainView\.java

```java
import jakarta.annotation.security.PermitAll;

@Route
// tag::snippet[]
@PermitAll
// end::snippet[]
public final class MainView extends Main {
    ...
}
```

TaskListView\.java

```java
import jakarta.annotation.security.PermitAll;

@Route("")
@PageTitle("Task List")
@Menu(order = 0, icon = "vaadin:clipboard-check", title = "Task List")
// tag::snippet[]
@PermitAll
// end::snippet[]
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](https://vaadin.com/docs/v24/building-apps/security/add-logout.md) guide.
