Authentication
Authentication answers: who is this request? Kona ships session guards for browsers, bearer-token guards for APIs, password hashing, reset brokers, and middleware that gate routes.
AuthServiceProvider registers hashing, an in-memory user provider (swap in CadenceUserProvider for Cadence models), web + api guards, the password broker, personal access tokens, and the Auth facade.
Simple path
Section titled “Simple path”- Keep
AuthServiceProvider(andSessionServiceProviderfor web) on your bootstrap list —kona newdoes this. - Ensure
StartSessionruns before auth middleware on HTML routes. - Log in with credentials; protect routes with
Authenticate.
auth.setRequest(request)if (auth.attempt(mapOf("email" to email, "password" to password), remember = true)) { val intended = Authenticate.pullIntended(request, "/") return Response.redirect(intended)}auth.setRequest(request);if (auth.attempt(Map.of("email", email, "password", password), true)) { String intended = Authenticate.pullIntended(request, "/"); return Response.redirect(intended);}Auth facade and manager
Section titled “Auth facade and manager”AuthManager resolves named guards. The Auth object mirrors the manager after the provider boots:
| Call | Meaning |
|---|---|
attempt / login / logout |
Persist (or clear) the session user |
check / guest / id / user |
Inspect the current user |
validate |
Check credentials without logging in |
once / onceUsingId |
Authenticate for this request only |
loginUsingId |
Log in by primary key |
viaRemember |
True when restored from a remember cookie |
guard("api") |
Switch guard |
Auth.setRequest(request)Auth.attempt(mapOf("email" to "a@b.c", "password" to "secret"))val user = Auth.user()Guards
Section titled “Guards”web(SessionGuard) — storeslogin_{guard}_id(and password hash) in the request session attribute"session".api(TokenGuard) — readsAuthorization: Bearer {id}|{secret}viaPersonalAccessTokenManager.
Register custom guards with auth.extend("admin", SessionGuard("admin", users)).
Remember me
Section titled “Remember me”When login / attempt is called with remember = true:
- A remember token is stored on the user (
Authenticatable.setRememberToken). - A long-lived
remember_{guard}cookie ({id}|{token}) is queued on the request. - Middleware that flushes auth cookies (built into
Authenticate,RedirectIfAuthenticated, andAuthenticateSession) writesSet-Cookieon the response.
On a later visit with no session id, SessionGuard recalls the user from the cookie and viaRemember() returns true. Logout clears the token and queues a forgetting cookie.
UserProvider.retrieveByToken / updateRememberToken power this; InMemoryUserProvider and CadenceUserProvider both implement them.
Cadence user provider
Section titled “Cadence user provider”For apps whose users live in Cadence models, register CadenceUserProvider instead of (or alongside) the in-memory provider. The model must implement Authenticatable and expose credential columns (typically email + password) plus optional remember_token:
class User : Cadence<User>(), Authenticatable { override val fillable = setOf("email", "password", "remember_token") companion object : CadenceCompanion<User>(User::class.java) override fun getAuthIdentifier(): Any = getAttribute("id")!! override fun getAuthPassword(): String = getAttribute("password")?.toString() ?: "" override fun getRememberToken(): String? = getAttribute("remember_token")?.toString() override fun setRememberToken(token: String?) { setAttribute("remember_token", token) }}
val users = CadenceUserProvider(User::class.java, Hash.manager().driver())auth.provider("users", users)auth.extend("web", SessionGuard("web", users))CadenceUserProvider<User> users = new CadenceUserProvider<>(User.class, Hash.manager().driver());auth.provider("users", users);auth.extend("web", new SessionGuard("web", users));Credential keys other than the password key become equality filters on the model query. Remember-token updates call save() on the model.
Middleware
Section titled “Middleware”| Middleware | Role |
|---|---|
Authenticate |
Require login; redirect to /login (or throw 401 when redirectTo = null); stores url.intended on GET |
RedirectIfAuthenticated |
Bounce already-logged-in users away from guest pages |
AuthenticateSession |
Log out when the password hash no longer matches the hash captured at login |
router.get("/dashboard", handler).middleware(Authenticate(auth))router.get("/login", handler).middleware(RedirectIfAuthenticated(auth, "/home"))router.middleware(AuthenticateSession(auth))After a successful login, send the user to Authenticate.pullIntended(request, "/").
Hashing
Section titled “Hashing”Hash.make("secret")Hash.check("secret", hash)Hash.needsRehash(hash)Bcrypt is the default (hash.driver=bcrypt, hash.rounds default 10). Passwords longer than 72 bytes are truncated to bcrypt’s limit.
Argon2id is registered as argon2 / argon2id. Switch the default with hash.driver=argon2 (optional hash.argon2.memory, hash.argon2.iterations, hash.argon2.parallelism). Register another Hasher with HashManager.extend when you need a custom algorithm.
Password resets
Section titled “Password resets”PasswordBroker issues reset tokens through a PasswordResetTokenRepository and applies resets through a callback. The default store is in-memory (auth.passwords.driver=array). For durable tokens that survive restarts, set auth.passwords.driver=database (optional auth.passwords.table) and ensure Database is registered before AuthServiceProvider.
val token = broker.createToken(mapOf("email" to email))val result = broker.reset(mapOf("email" to email, "token" to token, "password" to next)) { user, password -> // persist Hash.make(password)}You can also construct PasswordBroker(..., tokens = DatabasePasswordResetTokenRepository(connection)) explicitly.
For form validation rule lists, use PasswordRules.min(8) / PasswordRules.confirmed() with the HTTP validator (see Validation).
API tokens
Section titled “API tokens”PersonalAccessTokenManager.create(user, name, abilities) returns a plain-text token once (id|secret) and stores a SHA-256 hash. Check abilities with token.can("read") / token.cant("write").
The default repository is in-memory (auth.tokens.driver=array). Set auth.tokens.driver=database (optional auth.tokens.table) for JDBC-backed tokens, or pass DatabasePersonalAccessTokenRepository when constructing the manager.
Authenticate with bearer tokens via TokenGuard or AuthenticateWithToken middleware.