module

KemalIdentity::Kemal

The Kemal adapter.

This is the only layer that knows HTTP::Server::Context exists. Everything under src/kemal_identity/{core,accounts,sessions,passwords} is framework-agnostic, which is what makes spec/unit runnable without a server and leaves the door open to an Amber or Lucky adapter without touching the core (docs/01-architecture.md).

Wiring

require "kemal"
require "kemal_identity/kemal"

KemalIdentity.configure(
  accounts: MyAccountRepository.new,
  sessions: KemalIdentity::Postgres::SessionRepository.new(db),
)

use KemalIdentity::Kemal::ErrorHandler.new          # outermost: catches what guards raise
use KemalIdentity::Kemal::AuthenticationHandler.new # populates env.auth; never rejects
use KemalIdentity::Kemal::CSRFHandler.new           # after authentication: the token binds to the session
use KemalIdentity::Kemal::PathGuard.new(prefix: "/admin")

Order matters and is not obvious, so it is spelled out in the README. Two rules: nothing authentication-related is registered at position 0 (that position takes over Kemal's temporary-file cleanup), and ErrorHandler goes outside anything that raises.

Class methods

validate_middleware_order!(registered : Array(Tuple(Int32 | Nil, HTTP::Handler)) = ::Kemal::Config::CUSTOM_HANDLERS) : Nil

Checks that the handler chain is in an order that works, at boot rather than at the first request.

Order here is a security property and a silent one: every wrong arrangement compiles, most of them start, and the symptom arrives later as a 500 where a 401 belonged, a CSRF token that anchors on nothing, or a guard reading a principal that has not been resolved yet.

use KemalIdentity::Kemal::ErrorHandler.new(login_path: "/login")
use KemalIdentity::Kemal::AuthenticationHandler.new
use KemalIdentity::Kemal::CSRFHandler.new

KemalIdentity::Kemal.validate_middleware_order!
Kemal.run

Raises ConfigurationError naming every problem it found, not just the first — a chain with two things wrong should take one round trip to fix, which is what Django's system checks do with admin.E408 and its siblings. ASP.NET Core goes further and ships a compile-time analyzer (ASP0001) for the same class of mistake; Crystal gives no equivalent hook, so this runs at startup and an application opts in by calling it. That call is the escape hatch: there is no list of silenced checks, because an application that disagrees simply does not ask.

What it does not check

The relative order of CSRFHandler and PathGuard, which the documented chain separates with the application's own middleware. Both run after authentication, both refuse, and neither depends on the other — so an application that puts its guard earlier has made a choice rather than a mistake, and this is not the place to argue with it.

Nor anything about handlers this shard did not write. It reads the chain to find its own.

Source

Nested types