> Markdown version of [Without Spring Security](https://vaadin.com/docs/next/flow/security/spring/without-spring-security). Section index: [llms.txt](https://vaadin.com/docs/next/flow/llms.txt)

# Without Spring Security

Vaadin’s built-in security helpers are designed to be used with Spring Security. However, the core of view access control — `NavigationAccessControl` and the access annotations — doesn’t depend on Spring Security. It reads the current user from `HttpServletRequest.getUserPrincipal()`, and checks roles with `HttpServletRequest.isUserInRole()`. It therefore works with any authentication mechanism that sets the user on the request.

This page describes how to use view access control in a Spring Boot application that doesn’t have Spring Security on the class path. The setup is the same as in [plain servlet applications](https://vaadin.com/docs/next/flow/security/plain-servlet/setup.md), except that the parts are registered as Spring beans.

Vaadin configures navigation access control automatically only when Spring Security is present. Without it, the following aren’t available:

- `VaadinSecurityConfigurer` and the HTTP security configuration that it applies

- `AuthenticationContext`

- URL-pattern-based access checking against the Spring Security configuration — `RoutePathAccessChecker` still works with an `AccessPathChecker` of your own

- the integrations described on the other pages of this section, such as OAuth2 login

Securing an application without Spring Security takes the following:

- a way to authenticate users, and to set the user on the request

- a `VaadinServiceInitListener` bean that enables navigation access control

- a log-in view

- an access annotation on each view class and on each layout class, as described in [Annotation-Based Access Control](https://vaadin.com/docs/next/flow/security/access-control/annotations.md). The log-in view is the only exception.

## <a id="setting-the-user-on-the-request"></a>Setting the User on the Request

How users are authenticated depends on the application. With servlet container authentication, the container sets the user on the request, as described in [Container-Managed Authentication](https://vaadin.com/docs/next/flow/security/plain-servlet/container-authentication.md). Otherwise, store the authenticated user in the HTTP session, and set it on each request with a servlet filter. This is the same approach as [authentication in a plain servlet application](https://vaadin.com/docs/next/flow/security/plain-servlet/setup.md#authenticating-users), with the parts registered as Spring beans.

The following example stores the user as a `Principal` that also holds the user’s roles:

`AppUser.java`

```java
public record AppUser(String name, Set<String> roles)
        implements Principal, Serializable {

    @Override
    public String getName() {
        return name;
    }
}
```

The filter wraps each request of an authenticated user, so that the request returns the user and the user’s roles. Spring Boot registers a `Filter` bean for all requests automatically:

`AuthenticationFilter.java`

```java
@Component
public class AuthenticationFilter extends OncePerRequestFilter {

    static final String USER_ATTRIBUTE = AppUser.class.getName();

    @Override
    protected void doFilterInternal(HttpServletRequest request,
            HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        HttpSession session = request.getSession(false);
        AppUser user = session == null ? null
                : (AppUser) session.getAttribute(USER_ATTRIBUTE);
        if (user == null) {
            chain.doFilter(request, response);
            return;
        }
        chain.doFilter(new HttpServletRequestWrapper(request) {
            @Override
            public Principal getUserPrincipal() {
                return user;
            }

            @Override
            public boolean isUserInRole(String role) {
                return user.roles().contains(role);
            }
        }, response);
    }
}
```

Role names in `@RolesAllowed` are passed unchanged to `isUserInRole()`. With this filter, `@RolesAllowed("ADMIN")` therefore matches a user whose roles contain `ADMIN`.

A service logs users in by storing the user in the session, and logs them out by invalidating the session:

`AuthenticationService.java`

```java
@Component
public class AuthenticationService {

    public boolean login(String username, String password) {
        AppUser user = findUser(username, password); // (1)
        if (user == null) {
            return false;
        }
        var request = VaadinServletRequest.getCurrent()
                .getHttpServletRequest();
        request.changeSessionId(); // (2)
        request.getSession().setAttribute(
                AuthenticationFilter.USER_ATTRIBUTE, user);
        return true;
    }

    public void logout() {
        UI.getCurrentOrThrow().getPage().setLocation("./");
        VaadinSession.getCurrent().getSession().invalidate();
    }

    // ...
}
```

1. Checks the credentials against the user store of the application, and returns `null` if they don’t match. Never store passwords in plain text.

2. Gives the session a new ID, to protect against session fixation.

## <a id="enabling-navigation-access-control"></a>Enabling Navigation Access Control

Navigation access control is enabled with a `VaadinServiceInitListener` that adds `NavigationAccessControl` as a `BeforeEnterListener` to every UI. In a Spring application, Vaadin picks up the listener as a bean, so it doesn’t need to be registered under `META-INF/services` as in a plain servlet application:

`NavigationAccessControlInitializer.java`

```java
@Component
public class NavigationAccessControlInitializer
        implements VaadinServiceInitListener {

    private final NavigationAccessControl accessControl;

    public NavigationAccessControlInitializer() {
        accessControl = new NavigationAccessControl();
        accessControl.setLoginView(LoginView.class); // (1)
    }

    @Override
    public void serviceInit(ServiceInitEvent event) {
        event.getSource().addUIInitListener(uiInitEvent -> uiInitEvent
                .getUI().addBeforeEnterListener(accessControl));
    }
}
```

1. Sets the view to which users who aren’t authenticated are redirected.

To customize the access checkers or the decision resolver, pass them to the `NavigationAccessControl` constructor, as described in [Customizing Navigation Access Control](https://vaadin.com/docs/next/flow/security/plain-servlet/setup.md#customizing-navigation-access-control).

## <a id="log-in-view"></a>Log-in View

The log-in view calls the service when the user submits the form:

`LoginView.java`

```java
@Route(value = "login", autoLayout = false)
public class LoginView extends VerticalLayout {

    public LoginView(AuthenticationService authService) {
        LoginForm login = new LoginForm();
        login.addLoginListener(event -> {
            if (authService.login(event.getUsername(),
                    event.getPassword())) {
                getUI().ifPresent(ui -> ui.getPage().setLocation("./"));
            } else {
                login.setError(true);
            }
        });
        add(login);
    }
}
```

The log-in view doesn’t need an access annotation: `NavigationAccessControl` always allows navigation to the configured log-in view.

The filter sets the user on the requests that follow the log-in request, not on the log-in request itself. The log-in view therefore reloads the page after a successful login, instead of navigating to another view within the same request. The URL `./` is relative to the root of the application, because Vaadin sets the base URL of the page to it. The redirect therefore also works when the application is deployed under a context path.
