> Markdown version of [Role-Based Access Control](https://vaadin.com/docs/v24/hilla/lit/guides/security/role-based-access). Section index: [llms.txt](https://vaadin.com/docs/v24/hilla/llms.txt)

# Role-Based Access Control for Views

It’s possible to restrict access for selected Hilla views, based on roles defined for the logged-in user. This article explains how to do this.

To follow the examples here, you’ll need a Hilla application with authentication enabled. The [Authentication With Spring Security](https://vaadin.com/docs/v24/hilla/lit/guides/security/spring-login.md) page will help you to get started.

## <a id="define-roles-with-spring-security"></a>Define Roles with Spring Security

Roles are a set of string attributes representing the authorities that are assigned to a user. In Spring Security, the user details used for authentication also specify roles.

Typically, roles are defined in authority strings prefixed with `ROLE_`. After successful authentication, these are accessible via the `GrantedAuthority` objects returned by `Authentication.getAuthorities()`. See the [Authentication With Spring Security](https://vaadin.com/docs/v24/hilla/lit/guides/security/spring-login.md) page for examples of configuration.

## <a id="using-roles-in-typescript"></a>Using Roles in TypeScript

A convenient way to use roles for access control in TypeScript views is to add a Hilla endpoint that gets user information, including roles, from Java during authentication. To do this, first define a bean representing information about the user:

`UserInfo.java`

```java
public class UserInfo {

    @Nonnull
    private String name;
    @Nonnull
    private Collection<String> authorities;

    public UserInfo(String name, Collection<String> authorities) {
        this.name = name;
        this.authorities = Collections.unmodifiableCollection(authorities);
    }

    public String getName() {
        return name;
    }

    public Collection<String> getAuthorities() {
        return authorities;
    }

}
```

Next, add the endpoint to get a `UserInfo` containing authorities for the logged-in user on the client side:

`UserInfoService.java`

```java
@BrowserCallable
public class UserInfoService {

    @PermitAll
    @Nonnull
    public UserInfo getUserInfo() {
        Authentication auth = SecurityContextHolder.getContext()
                .getAuthentication();

        final List<String> authorities = auth.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.toList());

        return new UserInfo(auth.getName(), authorities);
    }

}
```

Then, change the authentication implementation in TypeScript to get the user information from the endpoint. Change the `auth.ts` defined in [Authentication With Spring Security](https://vaadin.com/docs/v24/hilla/lit/guides/security/spring-login.md#client-configuration) as follows:

`auth.ts`

`auth.ts`

```typescript
import type UserInfo from 'Frontend/generated/com/vaadin/demo/fusion/security/authentication/UserInfo';
import { UserInfoService } from 'Frontend/generated/endpoints';

interface Authentication {
  user: UserInfo;
}

let authentication: Authentication | undefined;

export async function login(
  username: string,
  password: string,
  options: LoginOptions = {}
): Promise<LoginResult> {
  return await loginImpl(username, password, {
    ...options,
    async onSuccess() {
      // Get user info from endpoint
      const user = await UserInfoService.getUserInfo();
      authentication = {
        user,
      };
    },
  });
}
```

Add an `isUserInRole()` helper, which enables role-based access control checks for the UI.

`auth.ts`

`auth.ts`

```typescript
export function isUserInRole(role: string) {
  if (!authentication) {
    return false;
  }

  return authentication.user.authorities.includes(`ROLE_${role}`);
}
```

## <a id="routes-with-access-control"></a>Routes with Access Control

To enable allowed roles to be specified on the view routes, define an extended type `ViewRoute`, that has a `rolesAllowed` string, like so:

`routes.ts`

`routes.ts`

```typescript
export type ViewRoute = Route & {
  title?: string;
  children?: ViewRoute[];
  rolesAllowed?: string[];
};
```

Add a method to check access for the given route by iterating `rolesAllowed`, using `isUserInRole()`, as follows:

`routes.ts`

`routes.ts`

```typescript
export function isAuthorizedViewRoute(route: ViewRoute) {
  if (route.rolesAllowed) {
    return route.rolesAllowed.find((role) => isUserInRole(role));
  }

  return true;
}
```

Then use the method added in the route action to redirect on unauthorized access like this:

`routes.ts`

`routes.ts`

```typescript
export const routes: ViewRoute[] = [
  {
    path: 'protected',
    component: 'protected-view',
    title: 'Protected',
    rolesAllowed: ['ADMIN'],
    action: async (context, commands: Commands) => {
      const route = context.route as ViewRoute;
      if (!isAuthorizedViewRoute(route)) {
        return commands.prevent();
      }
      await import('./protected-view');
      return undefined;
    },
  },
];
```

## <a id="hiding-unauthorized-menu-items"></a>Hiding Unauthorized Menu Items

Filter the route list using the `isAuthorizedViewRoute()` helper defined earlier. Then use the filtered list of routes as menu items:

`main-view.ts`

`main-view.ts`

```typescript
private get menuRoutes() {
    return routes.filter((route) => route.title).filter(isAuthorizedViewRoute);
  }
```
