Skip to content
Flag of Europe
Made in the European Union · Independently built · Released under EUPL 1.2
Quick Start

Quick Start

Build

Requirements: Maven 4 (4.0.0-rc-5+, pinned via ./mvnw), Java 26+.

mvn clean install

mvn install is required at least once because the demos depend on each other through the local ~/.m2 repository (demo-vaadin-rest-client depends on demo-rest for tests, and demo-rest-shared is consumed by both REST-side modules).

Pick the right demo

You want to see …Run
Vaadin role/permission UI in a single JVM, no backenddemo-vaadin
Pure REST security (HTTP server + interactive CLI), no UIdemo-rest
Vaadin UI talking to a separate REST backend (real two-tier setup)demo-vaadin-rest-client
CLI / desktop app with no UI framework — pure Core Javademo-standalone

Both Vaadin demos ship with a role + user admin UI (/admin/roles, including a new-user dialog with ConfirmDialog-protected deletes), a red lockout notification on repeated failed logins, and an audit-log grid (/audit) backed by RingBufferAuditSink.

demo-vaadin — Standalone Vaadin demo

cd demo-vaadin && mvn jetty:run
# Browser: http://localhost:8080/

First run shows the bootstrap setup (the demo prints a token to the console). After setup, log in as the chosen admin. Demo users user/user and demo/demo are pre-populated; admin is created via the bootstrap flow. Visit /admin/roles (admin only) for the role + user administration UI, /audit for the audit log.

demo-rest — REST server + CLI

# Terminal 1 — JDK-only HTTP server on http://localhost:8080
mvn -pl :demo-rest exec:java
# Prints a bootstrap token to the console (TRANSIENT_CONSOLE mode).

# Terminal 2 — interactive CLI
mvn -pl :demo-rest exec:java \
    -Dexec.mainClass=com.svenruppert.vaadin.security.demo.rest.cli.DemoRestCli
# Use `init-admin` to create the first admin via the bootstrap token.
# Then `login admin <new-password>` and play with `operations` / `call …`.

Demo users: editor/editor, viewer/viewer. admin is created via the bootstrap flow; with -Dsecurity.bootstrap.mode=DISABLED the default admin/admin is pre-populated instead.

REST endpoints relevant to the new subsystems:

  • GET /api/audit — read recent audit events (admin only)
  • GET /api/admin/users — list users (admin only)
  • POST /api/admin/users — create user (admin only, UserCreated audit)
  • PUT /api/admin/users/{username} — set role (admin only)
  • DELETE/api/admin/users/{username} — delete user (admin only, UserDeleted audit)

Repeated failed logins are throttled by LoginAttemptPolicy. The server responds with 429 Too Many Requests + Retry-After once the configured limit is reached.

demo-vaadin-rest-client — Vaadin UI + REST backend

# Terminal 1 — backend (same as the REST demo above)
mvn -pl :demo-rest exec:java
# Prints a bootstrap token to the console.

# Terminal 2 — Vaadin UI
mvn -pl :demo-vaadin-rest-client jetty:run
# Browser: http://localhost:9090/

Browser opens /setup (because the backend has no admin yet). Paste the token from the backend console, choose a username and password, submit — the Vaadin UI calls POST /api/bootstrap/admin against the backend, no in-JVM auth. Then log in. The UI never speaks HTTP directly: only the encapsulated DemoBackendClient does. The /admin/roles UI is backend-driven through GET/POST/PUT/DELETE /api/admin/users.

demo-standalone — Library CLI (Core Java)

mvn -pl :demo-standalone exec:java \
    -Dexec.mainClass=com.svenruppert.vaadin.security.demo.standalone.DemoApp

Plain interactive shell — no Vaadin, no REST — against an in-memory book library. Seeded users admin/admin, librarian/librarian, alice/alice. Same @RequiresPermission / @RequiresRole annotations, enforced by a dynamic-proxy via Secured.wrap(LibraryService.class, new InMemoryLibraryService()). Brute-force throttling and audit events work identically — same SPI services. See Standalone Integration for the API.

Tests

# Whole reactor — 1655+ tests across 14 modules
./mvnw verify

# Single module
./mvnw -pl :security-core -am test
./mvnw -pl :security-standalone -am test
./mvnw -pl :demo-rest -am test
./mvnw -pl :demo-vaadin-rest-client -am test

# Mutation testing (Pitest) — library modules carry 70–97% mutation
# coverage. See Architecture → Quality.
./mvnw -P mutation verify -pl :security-core -am

Add the dependency

Current release: 00.72.00.

For a Vaadin application:

<dependency>
  <groupId>com.svenruppert</groupId>
  <artifactId>security-vaadin</artifactId>
  <version>00.72.00</version>
</dependency>

For a REST handler / servlet application:

<dependency>
  <groupId>com.svenruppert</groupId>
  <artifactId>security-rest</artifactId>
  <version>00.72.00</version>
</dependency>

For a plain Core-Java application (CLI, desktop, batch):

<dependency>
  <groupId>com.svenruppert</groupId>
  <artifactId>security-standalone</artifactId>
  <version>00.72.00</version>
</dependency>

security-core is pulled in transitively by any of the three adapters.

Optional add-on modules (00.72.00)

These are strictly opt-in — none is pulled in transitively, and security-core carries no third-party dependency without them:

<!-- Durable persistence: swaps every InMemory*Store for an Eclipse-Store
     backend. Registration via META-INF/services/, no code change.
     See Persistence. -->
<dependency>
  <groupId>com.svenruppert</groupId>
  <artifactId>security-persistence-eclipsestore</artifactId>
  <version>00.72.00</version>
</dependency>

<!-- Compile-time @Secured method-security processor. See Method Security. -->
<dependency>
  <groupId>com.svenruppert</groupId>
  <artifactId>security-processor</artifactId>
  <version>00.72.00</version>
  <scope>provided</scope>
</dependency>

<!-- Reusable test fixtures (FakeAuthenticationService, JUnit-5 extension). -->
<dependency>
  <groupId>com.svenruppert</groupId>
  <artifactId>security-test</artifactId>
  <version>00.72.00</version>
  <scope>test</scope>
</dependency>

<!-- Store contract test suites for your own persistence adapter. -->
<dependency>
  <groupId>com.svenruppert</groupId>
  <artifactId>security-persistence-testkit</artifactId>
  <version>00.72.00</version>
  <scope>test</scope>
</dependency>

<!-- Modern password hashing: Argon2id / bcrypt / scrypt via BouncyCastle
     (lightweight API, no global JCA mutation). See Credential Hardening. -->
<dependency>
  <groupId>com.svenruppert</groupId>
  <artifactId>security-crypto-bc</artifactId>
  <version>00.72.00</version>
</dependency>

<!-- Breached-password check via Have I Been Pwned (k-anonymity; JDK
     HttpClient only, no extra runtime dependency). -->
<dependency>
  <groupId>com.svenruppert</groupId>
  <artifactId>security-credentials-hibp</artifactId>
  <version>00.72.00</version>
</dependency>

<!-- Developer experience: typed fluent bootstrap (VaadinSecurity /
     RestSecurity / StandaloneSecurity). -->
<dependency>
  <groupId>com.svenruppert</groupId>
  <artifactId>security-dx-vaadin</artifactId>   <!-- or -rest / -standalone -->
  <version>00.72.00</version>
</dependency>

<!-- @SecurityAutoService — generate META-INF/services automatically. -->
<dependency>
  <groupId>com.svenruppert</groupId>
  <artifactId>security-autoservice-annotations</artifactId>
  <version>00.72.00</version>
  <scope>provided</scope>
</dependency>

Fastest start — fluent bootstrap (00.72)

Instead of writing META-INF/services files by hand, configure every subsystem in one typed call and let the bootstrap report what it wired:

SecurityRuntime runtime = VaadinSecurity.bootstrap()   // or RestSecurity / StandaloneSecurity
    .subjectType(User.class)
    .authentication(new MyAuthService())
    .authorization(new MyAuthzService())
    .audit(a -> a.ringBuffer(256).logging())
    .sessions(s -> s.idleTimeout(Duration.ofMinutes(30)).rotateOnLogin())
    .loginRoute("/login")
    .mode(SecurityBootstrapMode.PRODUCTION)   // COMMUNITY_DEFAULTS / DEVELOPMENT / PRODUCTION / STRICT
    .install();

runtime.log();   // secret-free startup log; runtime.warnings() lists gaps
// And drop the hand-written service file entirely:
@SecurityAutoService(AuthenticationService.class)
public final class MyAuthService implements AuthenticationService<Credentials, User> {  }

See Developer Experience for the full tour.