Architecture
Module Structure
| Module | Artifact | Description |
|---|---|---|
security-core | security-core | Generic, framework-neutral security concepts and decision logic |
security-vaadin | security-vaadin | Vaadin Flow adapter โ view and navigation security |
security-rest | security-rest | Framework-light REST adapter โ request and handler security |
demo-vaadin | demo-vaadin | Vaadin reference implementation (WAR) |
demo-rest | demo-rest | Runnable REST reference: JDK-only HTTP server + CLI client |
Dependency Rules
security-core -> (no project deps)
security-vaadin -> security-core
security-rest -> security-core
demo-vaadin -> security-core, security-vaadin
demo-rest -> security-core, security-restsecurity-core has no Vaadin, Servlet, or REST-framework dependencies.
security-vaadin and security-rest never depend on each other.
Core rule
Library modules do not define project-specific permissions. Concrete roles, permissions, and business operations belong to consuming applications or demo modules.
security-core provides generic types such as SecuritySubject,
RoleName, PermissionName, AccessContext, AuthorizationDecision,
evaluator contracts, plus the reusable building blocks listed below.
security-vaadin maps security decisions to Vaadin navigation behavior.
It owns Vaadin session access through VaadinSessionSubjectStore, login
redirection, access-denied rerouting, and BeforeEnterListener
integration.
security-rest maps semantic authorization decisions to REST behavior.
It uses minimal abstractions (RestRequest, RestResponse,
RestHandler, BodyRestRequest) and does not pull in Spring Security,
Jakarta Security, OAuth2/OIDC, or a web framework.
Decision Model
The library uses two decision types:
| Type | Module | Purpose |
|---|---|---|
AuthorizationDecision | security-core | Adapter-neutral: Granted / Unauthenticated / Forbidden |
AccessDecision | security-core | Vaadin-oriented (legacy, kept for backward compatibility) |
Adapters map these to framework-specific behavior:
security-vaadinโ navigation: continue, reroute to login, or reroute to error.security-restโ HTTP status:200/handler,401, or403.
Annotation-Driven Protection
SecurityAnnotationScanner scans classes, methods, or any
AnnotatedElement for restriction annotations meta-annotated with
@SecurityAnnotation. Both adapters use the same scanner.
Generic annotations (in security-core):
@RequiresRole({"ROLE_ADMIN"})โRequiresRoleEvaluator@RequiresPermission("document:delete")โRequiresPermissionEvaluator@ProtectedBy(...)โProtectedByEvaluator
Project-specific annotations are encouraged for Vaadin views (e.g.
@VisibleFor).
Reusable security building blocks
| Type | Module / package | Purpose |
|---|---|---|
PermissionGuard | security-core/.../authorization/api | Stateless hasPermission / requirePermission (and role variants) on any HasPermissions/HasRoles. Throws AccessDeniedException. |
StaticRolePermissionMapping | โฆ/api/permissions | Immutable role โ permissions map with a builder. |
RolePermissionResolver | โฆ/api/permissions | Merges permissions across multiple roles. |
SecuredOperationDescriptor, SecuredOperationRegistry, OperationVisibilityService | โฆ/api/operations | Generic operation discovery with subject-aware filtering. Adapter metadata (HTTP method, path, view class) goes into the descriptor’s attributes. |
BootstrapConfigurationLoader, BootstrapStatus | security-core/.../bootstrap | Centralised sysprop+env+default loading with TTL parsing; leak-safe status snapshot. |
RestHeaders, BearerTokenExtractor | security-rest | Case-insensitive header lookup and Bearer-token parsing. |
RestAuthenticationFilter | security-rest | 401-only filter for authenticated-only endpoints. |
BodyRestRequest | security-rest | Body-capable RestRequest. Avoids concrete-class casts in handlers. |
BootstrapRestStatusMapper | security-rest | InitialAdminCreationResult โ HTTP status code + stable error code. |
Stable vs. Experimental API
Stable: role-based access, REST adapter contracts, SecuritySubject,
AccessContext, AuthorizationDecision, scanner.
Experimental (marked with @ExperimentalSecurityApi):
permission-based access types โ PermissionBasedAccessEvaluator,
PermissionName, HasPermissions, PermissionAuthorizationService.
May change in incompatible ways in future releases.
Project-specific permissions live in applications
Library modules contain no concrete business permissions. Examples like
document:read belong in demo-rest. Real applications define their own
catalog (e.g. shortlink:create, audit:read) inside the consuming
project.