Vaadin Integration
To secure a Vaadin Flow application, implement the SPI contracts below and
register them via META-INF/services/ files. The demo-vaadin module is
the reference implementation.
1. Define a user type
public record MyUser(String username, Set<String> roles) {}2. Implement AuthenticationService<T, U>
Validates credentials and loads the user subject.
public class MyAuthenticationService
implements AuthenticationService<Credentials, MyUser> {
@Override
public boolean checkCredentials(Credentials credentials) { /* ... */ }
@Override
public MyUser loadSubject(Credentials credentials) { /* ... */ }
@Override
public Class<MyUser> subjectType() { return MyUser.class; }
}Register in
META-INF/services/com.svenruppert.vaadin.security.authorization.api.AuthenticationService:
com.example.MyAuthenticationService3. Implement AuthorizationService<U>
Maps a user to roles. Only rolesFor() is required — permissionsFor()
has a default implementation returning empty permissions.
public class MyAuthorizationService implements AuthorizationService<MyUser> {
@Override
public HasRoles rolesFor(MyUser subject) { /* ... */ }
}Register in
META-INF/services/com.svenruppert.vaadin.security.authorization.api.AuthorizationService.
4. Define a restriction annotation with @SecurityAnnotation
@Retention(RUNTIME)
@SecurityAnnotation(MyRoleAccessEvaluator.class)
public @interface VisibleFor {
MyRole[] value();
}Or use the generic annotations from security-core:
@RequiresRole("ROLE_ADMIN")
@RequiresPermission("demo:edit")5. Implement AccessEvaluator
public class MyRoleAccessEvaluator
implements AccessEvaluator<VisibleFor> {
@Override
public AccessDecision evaluate(AccessContext context, VisibleFor annotation) {
// return AccessDecision.granted() or AccessDecision.denied("login", false)
}
}Or extend RoleBasedAccessEvaluator:
public class MyRoleAccessEvaluator
extends RoleBasedAccessEvaluator<VisibleFor, MyUser> {
@Override
public Set<RoleName> requiredRoles(VisibleFor annotation) { /* ... */ }
@Override
public String alternativeNavigationTarget(
AccessContext context, VisibleFor annotation) { /* ... */ }
}Register in
META-INF/services/com.svenruppert.vaadin.security.authorization.api.AccessEvaluator.
6. Extend LoginListener<U>
public class MyLoginListener extends LoginListener<MyUser> {
@Override
public Class<? extends LoginView> loginNavigationTarget() {
return MyLoginView.class;
}
@Override
public Class<? extends Component> defaultNavigationTarget() {
return MainView.class;
}
}Register in
META-INF/services/com.svenruppert.vaadin.security.authorization.LoginListener.
7. Extend LoginView
Create your login UI by extending the abstract LoginView base class.
8. Annotate route views
@Route("admin")
@VisibleFor(MyRole.ADMIN)
public class AdminView extends Div { /* ... */ }How the Vaadin adapter behaves
- Detects security annotations before navigation.
- Checks whether a subject is present.
- Redirects unauthenticated users to the login view.
- Runs the matching evaluator.
- Maps the resulting decision to Vaadin navigation operations.
Hiding buttons or menu entries is only a usability measure. The actual protection boundary is server-side navigation and service-level authorization.