> Markdown version of [Customizing Navigation Access Control](https://vaadin.com/docs/next/flow/security/spring/navigation-access-control). Section index: [llms.txt](https://vaadin.com/docs/next/flow/llms.txt)

# Customizing Navigation Access Control

`VaadinSecurityConfigurer` enables [navigation access control](https://vaadin.com/docs/next/flow/security/access-control/navigation-access-control.md) automatically. This page describes how to customize it in a Spring application.

## <a id="configuring-the-access-checkers"></a>Configuring the Access Checkers

When using `VaadinSecurityConfigurer` for configuring Spring Security, the Navigation Access Control feature is enabled by default. You can disable it by calling the `enableNavigationAccessControl(false)` method on the configurer. By default, only the `AnnotatedViewAccessChecker` is active.

For a fine-grained configuration, you can expose a bean of type `NavigationAccessControlConfigurer`. `NavigationAccessControlConfigurer` allows activating out-of-the-box navigation access checkers or adding new ones, providing a custom decision resolver, completely disable the functionality, etc.

> **Note:** If `VaadinSecurityConfigurer` is not used, exposing the `NavigationAccessControlConfigurer` bean is mandatory to activate navigation access control.

In the following example, Navigation Access Control is configured to activate route path checker, a custom checker instance and all available `NavigationAccessChecker` beans that extend `VotingNavigationAccessChecker`. It also provides a custom decision resolver.

Customize NavigationAccessControl in Spring Project

```java
@Bean
NavigationAccessControlConfigurer navigationAccessControlConfigurerCustomizer() {
    return new NavigationAccessControlConfigurer()
            .withRoutePathAccessChecker() // (1)
            .withNavigationAccessChecker(new CustomChecker()) // (2)
            .withAvailableNavigationAccessCheckers(checker ->
                checker instanceof VotingNavigationAccessChecker  // (3)
            )
            .withDecisionResolver(new CustomDecisionResolver()); // (4)
}
```

1. Activates the route path access checker. The implementation is provided by the Vaadin Spring module and exposed as a bean.

2. Adds a custom navigation access checker, by creating a new instance.

3. Activates all registered navigation access checker bean, that matches the predicate.

4. Sets a custom decision resolver.

> **Important:** When using `VaadinSecurityConfigurer` in the same configuration class where you define the `NavigationAccessControlConfigurer` bean, make sure to declare the bean method as `static` to prevent bootstrap errors due to circular dependencies in bean definitions.

Define NavigationAccessControlConfigurer Bean with VaadinSecurityConfigurer

**VaadinSecurityConfigurer**

```java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    static NavigationAccessControlConfigurer navigationAccessControlConfigurer() {
        return new NavigationAccessControlConfigurer()
            .withRoutePathAccessChecker()
            .withDecisionResolver(new CustomDecisionResolver());
    }

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.with(VaadinSecurityConfigurer.vaadin(), configurer -> {
            // VaadinSecurityConfigurer will use the NavigationAccessControlConfigurer bean
        }).build();
    }
}
```

Consult the `NavigationAccessControlConfigurer` Javadoc for more information on how navigation access control can be customized.

## <a id="url-pattern-based-security"></a>URL-Pattern-Based Security

With `RoutePathAccessChecker`, a Flow route is protected by Spring Security request matchers for its path, in the same way as any other URL. The path used to navigate to the view is evaluated with Spring’s `WebInvocationPrivilegeEvaluator`.

Only `AnnotatedViewAccessChecker` is active by default, so first activate `RoutePathAccessChecker` with a `NavigationAccessControlConfigurer` bean, as described in [Configuring the Access Checkers](#configuring-the-access-checkers):

```java
@Bean
static NavigationAccessControlConfigurer navigationAccessControlConfigurer() {
    return new NavigationAccessControlConfigurer()
            .withAnnotatedViewAccessChecker() // (1)
            .withRoutePathAccessChecker(); // (2)
}
```

1. Keeps checking the access annotations. Leave this out to use only the request matchers.

2. Checks the route paths against the request matchers.

Then protect the route paths with request matchers:

**VaadinSecurityConfigurer**

```java
@Route("admin")
public class AdminView extends Div { }

@Route("protected/profile")
public class ProfileView extends Div { }

@Route("special/preview-feature")
public class PreviewFeatureView extends Div { }

@Route("")
public class HomeView extends Div { }

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(auth -> auth
                .requestMatchers("/admin").hasRole("ADMIN")
                .requestMatchers("/protected/**").authenticated()
                .requestMatchers("/special/**")
                    .access((authentication, object) -> {
                        // Custom authorization logic
                        return new AuthorizationDecision(isPremiumUser(authentication));
                    })
                .requestMatchers("/")
                .permitAll()
        );

        http.with(VaadinSecurityConfigurer.vaadin(), configurer -> {
            // Configure Vaadin security settings
        });

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

When both checkers are active, the access annotations and the request matchers for the same view must agree. If one of them allows the navigation and the other denies it, the default decision resolver rejects the navigation, as described in [Decision Resolver](https://vaadin.com/docs/next/flow/security/access-control/navigation-access-control.md#decision-resolver). To keep the rules for a view in one place, use only one of the two mechanisms for it.
