Skip to content

Release notes

Notable changes to javalin-security. This changelog follows Keep a Changelog; versioning follows Semantic Versioning.

[2.0.0] - Unreleased

Current version: 0.2.0.

Nothing has shipped yet, so this is the first release. It is versioned 2.0.0 because the extension API went through several breaking redesigns before release: concrete-identity classes were replaced with a generic-on-identity design, then the generic was dropped in favour of the Identity interface, and roles were moved off Identity onto Authentication (carried by scheme-specific *Details records). Identity types are brought by the caller and read back with ctx.identity<T>() — an unchecked cast, like ctx.attribute<T>().

Roles owned by Authentication, not Identity

  • Identity no longer has roles. It keeps name only. Roles are supplied to Authentication.authenticated(identity, roles) by each extension.
  • Scheme-specific *Details records carry roles alongside identity:
  • BasicUserDetails(identity, encodedPassword, roles) — replaces core PasswordCredentials and lives in the basic-auth module.
  • ApiKeyDetails(identity, roles) — ApiKeyLookup now returns ApiKeyDetails?.
  • OpaqueTokenDetails(identity, expiresAt, roles) — renamed from TokenRecord.
  • SessionDetails(identity, roles) — SessionManager.create / validate take/return it.
  • JWT keeps JwtRolesMapper (input is DecodedJwt). identityMapper and rolesMapper may be used together; the built-in Jwt identity no longer carries roles.
  • Migration:
// Before
data class User(override val name: String, override val roles: Set<RouteRole>) : Identity
PasswordCredentials(User("alice", setOf(Role.USER)), "pw")
sessionManager.create(ctx, User("alice", setOf(Role.USER)))

// After
data class User(override val name: String) : Identity
BasicUserDetails(User("alice"), "pw", setOf(Role.USER))
sessionManager.create(ctx, SessionDetails(User("alice"), setOf(Role.USER)))

Extension API — no generic on the factory

  • No <I> on the factory. basicAuth { }, apiKey { }, opaqueToken { }, session { }, and jwt { } are all non-generic. Configure userLookup / lookup / sessionManager / identityMapper with your own Identity type; read it back with ctx.identity<YourType>().
  • Non-generic SPI types. BasicUserDetails, ApiKeyDetails, OpaqueTokenDetails, SessionDetails, UserLookup, ApiKeyLookup, OpaqueTokenLookup, JwtIdentityMapper, SessionManager, and HttpSessionManager are all non-generic — their identity field is typed as Identity.
  • HttpSessionManager Serializable check. The default session manager now checks details.identity is Serializable at create time and throws IllegalArgumentException with a descriptive message when it isn't — the same guarantee the previous compile-time bound provided, surfaced eagerly at SessionManager.create(...) instead of at replication time.
  • Single jwt { } overload. The generic jwt<I> { } overload (and the Java JwtSecurity.jwtWithIdentity(...) companion) is gone; set identityMapper on the same non-generic jwt { } block to map verified tokens to your own domain identity. The default path (no identityMapper) still attaches the built-in Jwt identity.

Basic Auth encoded password is not on the identity

  • UserLookup returns BasicUserDetails (identity + encoded password + roles kept separate), so the encoded password used for verification is never reachable via ctx.identity<I>().

Session

  • Ships a default HttpSessionManager — session { } works with zero configuration.
  • Session create/invalidate is the caller's responsibility: keep a reference to your SessionManager and call create / invalidate from login/logout handlers with a SessionDetails payload. The strategy only validates sessions on each request.
  • Default HttpSessionManager rotates the session id on create for session-fixation defense.

Added

  • Core (javalin-security): HTTP and WebSocket guards (installed with the plugin), security { } configuration, authentication() / identity() / identityOrNull() accessors, AuthenticationStrategy.sync / .async factory helpers.
  • Authentication SPI: sync and async strategies, AuthenticationResult, Identity, unauthorized handlers.
  • Authorization: built-in rules, rule tables, Anyone, deny-by-default fallback, path patterns (Javalin syntax), CORS preflight bypass.
  • WebSocket: Origin allow-listing at upgrade.
  • Basic Auth (javalin-security-basic-auth): basicAuth { }, user lookup returning BasicUserDetails, password encoder, optional WWW-Authenticate challenge.
  • API Key (javalin-security-api-key): apiKey { }, key lookup returning ApiKeyDetails, header/query/cookie resolvers.
  • Opaque Token (javalin-security-opaque-token): opaqueToken { }, token lookup returning OpaqueTokenDetails, expiry validation, optional WWW-Authenticate: Bearer challenge.
  • Session (javalin-security-session): session { } with a default HttpSessionManager, SessionDetails, session-id rotation on create, runtime Serializable check on the default manager. Callers wire SessionManager.create / invalidate themselves.
  • JWT (javalin-security-jwt): single jwt { } factory — default Jwt identity, opt into your own via identityMapper; decoder SPI, key sources, roles mapping (combinable with identityMapper), optional bearer challenge.
  • Decoder adapters: Nimbus and Auth0 (JWKS caching, RSA / EC / HMAC).
  • Java interoperability across modules.

Compatibility

  • Java 17+, Javalin 7.2.x, Kotlin 2.0+.

Pre-release

While the version is 0.2.0, the public API may still change before the first stable release.