This is a substantial hardening release. The public helper API
(basic_auth "user", "pass", basic_auth({...})) is unchanged, but the
internals were reorganized around a Verifier strategy interface and the
Credentials timing-equalization algorithm changed. See
Upgrading from 1.x for guidance.
Added
-
Kemal::BasicAuth::Verifierabstract class as a pluggable authentication
strategy. Built-in implementations:Credentials(plaintext, in-memory; existing class, now< Verifier).BcryptVerifierfor bcrypt-hashed passwords (usesCrypto::Bcrypt).ProcVerifierfor dynamic credential lookup (DB, environment, etc.).
-
basic_authblock form for ad-hoc dynamic verification:basic_auth do |user, pass| User.authenticate(user, pass) end
-
Configurable
realmandmessageonHandlerand allbasic_auth
helpers;WWW-Authenticateheader is generated fromrealmand
sanitized against header injection (CR/LF and"). -
Kemal::BasicAuth::RateLimiter: optional in-memory sliding-window rate
limiter for failed authentication attempts. Keys off the request remote
address; emits429 Too Many RequestswithRetry-Afteronce the
threshold is exceeded; resets on successful authentication. -
Automatic
only/excludefiltering: subclasses that use theonlyor
excludemacros no longer need to overridecall. The legacy manual
override pattern keeps working.
Changed
Credentialsnow performs timing-equalized comparison via SHA-256
digests so that response time does not vary with whether the username
exists or how the supplied password compares to the stored one. SHA-256
is used purely for length equalization here; for hashed storage use
BcryptVerifier.Handlerconstructor accepts aVerifierinstead of aCredentials
instance.Credentials < Verifier, so existing callers passing a
Credentialsinstance continue to work without changes.Handlernow acceptsrealm,message, andrate_limiteras
optional keyword arguments on every constructor variant.Authorizationheader parsing is stricter: requires the literal
prefix"Basic "(with the trailing space), tolerates surrounding
whitespace via.strip, and gracefully rejects malformed Base64,
payloads without a:separator, or any other parse failures.shard.yml:kemalmoved fromdevelopment_dependenciesto
dependencies(it is a runtime requirement) and pinned to
>= 1.0.0, < 2.0.0. Minimum Crystal version is now1.12.0.
Fixed
- Passwords containing
:are now supported (parsing uses
String#partitioninstead ofString#split). - Malformed
Authorizationheaders (invalid Base64, missing colon,
unexpected scheme) now produce a clean401response instead of
raisingBase64::Error/IndexError. - Removed dead
headers = HTTP::Headers.newallocation in
Handler#call. - Doc comment typos (
password2->password1,authorized_username
->kemal_authorized_username?). crendentialsparameter name typo (crendentials->credentials).
Removed
src/kemal-basic-auth/version.cr(Kemal::BasicAuth::VERSIONconstant).
The version lives inshard.ymlonly.
Infrastructure
- CI moved from Travis to GitHub Actions, matrix tests against Crystal
latestandnightly, with format check, ameba lint, and full spec
run. .ameba.ymladded with minimal configuration.- Test suite expanded from 3 to 42 specs covering malformed headers,
passwords with:, realm/message customization, header injection
sanitization, all verifiers, the rate limiter (with an injectable
fake clock), andonly/excludebehavior in both auto and legacy
modes.