Skip to content
Flag of Europe
Made in the European Union · Independently built · Released under EUPL 1.2
jSentinel iris — green eye framed by bracket lids; logo of the project jSentinel iris — green eye framed by bracket lids; logo of the project

jSentinel Lightweight Security for Core Java, REST and Vaadin.

Pluggable authentication, authorization, and annotation-driven protection — wired through Java SPI, no Spring or Jakarta required.

jsentinel.eu

Annotation-Driven, Three Adapters

Same @RequiresRole / @RequiresPermission annotations protect Vaadin views (navigation listener), REST handlers (filter), and plain Java services (Secured.wrap(…) dynamic-proxy). One scanner, three call sites.

Framework-Neutral Core

security-core has no Vaadin, Servlet, or REST-framework dependencies. Adapters map a single decision model to navigation or HTTP status.

Java SPI by Design

Authentication, authorization, audit, action, login-attempt, session-policy, password-hashing, logout — every contract pluggable via META-INF/services/. One SecurityServiceResolver resolves them all.

Hardened First-Run Bootstrap

The first administrator is created via a one-time token. POSIX 0600 file, atomic creation, PBKDF2-HMAC-SHA256, never logged, never echoed.

Granted / 401 / 403 — That's It

AuthorizationDecision collapses to three outcomes. REST adapters map them to status codes; Vaadin maps them to navigation. Error bodies are short and generic.

Four Reference Demos

Standalone Vaadin (demo-vaadin), JDK-only REST server + CLI (demo-rest), two-tier setup (demo-vaadin-rest-client), and a pure Core-Java CLI library (demo-standalone) — one annotation set, four call shapes. Both Vaadin demos ship a role-admin UI, user CRUD, and an audit-log view.

Production Hardening

SecurityAuditService with 16 sealed event types and a ring-buffer sink. LoginAttemptPolicy brute-force protection with 429 + Retry-After and lockout UI. SessionPolicy with idle/absolute lifetime and session-id rotation after login.

Multi-Session Logout

LogoutService.logout(SubjectId, LogoutScope) — sign the subject out of the current session or every active session of theirs. Adapter-specific cleanup (Vaadin session, HTTP session, bearer token) plugs in via LogoutListener.

Action Authorization with Audit

Stable ActionAuthorizationService SPI for isAllowed / requireAllowed. Every denied action emits an ActionDenied audit event automatically — no manual instrumentation.

Mutation-Tested Library

Line coverage tells you tests executed the code.
Mutation testing changes the bytecode at runtime and asks the harder question: did the tests catch the change?

Line coverage
Code ran during a test
Easy to game
vs.
Mutation coverage
Tests detected a real bug
What you actually want

A surviving mutation is a real gap. Here's where the library stands.

security-core
91%
test strength
497 of 547 reached mutations killed
Line
82%
Mutation
79%
Strength
91%
security-vaadin
93%
test strength
163 of 175 reached mutations killed
Line
91%
Mutation
90%
Strength
93%
security-standalone
98%
test strength
44 of 45 reached mutations killed
Line
86%
Mutation
98%
Strength
98%
security-rest
95%
test strength
57 of 60 reached mutations killed
Line
93%
Mutation
95%
Strength
95%

Test strength = killed mutations / covered mutations. A 91% value means: of every 100 mutations the tests reached, 91 were detected. Line coverage measures whether code runs; test strength measures whether the assertions actually catch the bugs the code paths produce. Demos have intentionally lower numbers (UI / wire code is harder to mutation-test in isolation); the library code is what carries the production-quality guarantee.