KemalIdentity::Application
Everything the shard needs, wired together once at boot.
Built at startup and never mutated afterwards (docs/01-architecture.md): no request can
widen a session window or swap a hasher. Adapters must be safe for concurrent use from
multiple fibers on multiple threads, which since Crystal 1.21 may genuinely mean multiple
threads.
The repositories go in; the services come out. sessions takes a
Sessions::Repository and gives back a Sessions::Service, because an application
configures storage and calls behaviour.
Constructors
Instance methods
The account store. Abstract on purpose — an application with its own users table
implements this and creates no auth_accounts table at all.
The account lifecycle service: password reset and email confirmation.
nil unless the application supplied both an ActionTokenRepository and a Notifier —
neither has a sensible default. A reset flow with nowhere to store its tokens, or with
nobody to send the link, would be a flow that silently never works.
The stores behind the account lifecycle and remember-me services, exposed for the sweeper. Nil when the application configured neither, in which case there is nothing of theirs to sweep.
What decides whether a principal may perform an action, or nil when the application has
not configured authorization at all.
Nil rather than a permissive default, and Authz::DenyAll rather than "allow" when
something is half-configured: an authorizer that permitted everything would turn a wiring
mistake into an open application, and a nil is what makes env.auth.authorize! say so
loudly instead of guessing.
Built by the application rather than assembled from parameters here — Authz::RBAC.new
takes a role catalog, and a catalog is code that belongs next to the routes it guards.
What resolves an Authorization: Bearer header, whichever kind of token it holds.
One authenticator when only one is configured, and an AuthenticatorChain when several
are: the header does not say which kind it carries, so they are tried in turn on shape. Nil
when the application accepts no bearer credential at all.
An application's own authenticators arrive through bearer_authenticators: and are part of
this. That matters beyond the resolution itself: this is also the signal
Kemal::ErrorHandler uses to decide whether to send an RFC 6750 challenge, and
Kemal::CSRFHandler uses to decide whether a token-only request is exempt. An application
whose only bearer credential is its own — a gateway-issued key, a legacy token — used to
get neither, because there was nowhere to put it (blueprints/0025, TOK-04).
CSRF configuration, or nil when the application has not set one up.
Nilable rather than defaulted: a default signing key would be shared by every deployment
that forgot to set one, which is the same as having no protection while appearing to have
some. CSRFHandler raises at construction when this is missing.
JWT validation, or nil — which it is unless an application passed a JWT::Validator.
Off by default on purpose: a JWT cannot be revoked before its exp, and
JWT::RevocationStore sets out what that costs.
Second factors, or nil unless an MFA::Repository, a secret-box key and an issuer were
all supplied. Half of an MFA setup is worse than none: a service with nowhere to store a
factor, or no key to seal it with, would accept an enrolment and lose it.
A policy whose ceiling comes from this application's hasher rather than from a number copied out of a document. v0.1 has no flow that calls it — there is no registration and no password change — so it is built on demand rather than held.
Throttling for the password verification path. NullRateLimiter by default, which
allows everything — see its documentation, and the README.
The cookie remember-me tokens ride in. Separate from the session cookie: different name,
different lifetime, and it carries a max-age because it is meant to outlive the browser
being closed, which is the entire point of it.
The session store, exposed for a sweeper or a "list my devices" screen. The hot path
goes through sessions instead.