Better Auth Hanami
Hanami adapter for Better Auth Ruby. It mounts the core Rack auth object inside Hanami, uses Hanami's ROM/Sequel database gateway for persistence, renders ROM::SQL migrations, generates Hanami relations/repos for app queries, and provides action helpers plus generator tasks.
Installation
gem "better_auth-hanami"
bundle install
Setup
Load the task file from your app Rakefile if your app does not already load
lib/tasks:
# Rakefile
require "better_auth/hanami"
load Gem.loaded_specs.fetch("better_auth-hanami").full_gem_path + "/lib/tasks/better_auth.rake"
Generate the provider, route wiring, task wrapper, settings, relations/repos, and base migration:
bundle exec rake better_auth:init
Run Hanami migrations:
bin/hanami db migrate
When you add plugins that introduce schema tables or fields, regenerate both the migration and the app query objects before migrating a new app:
bundle exec rake better_auth:generate:migration
bundle exec rake better_auth:generate:relations
Configuration
The install generator creates config/providers/better_auth.rb:
Hanami.app.register_provider(:better_auth) do
prepare do
require "better_auth/hanami"
end
start do
BetterAuth::Hanami.configure do |config|
config.secret = target["settings"].better_auth_secret
config.base_url = target["settings"].better_auth_url
config.base_path = "/api/auth"
config.database = ->() {
BetterAuth::Hanami::SequelAdapter.from_container(target, )
}
config.trusted_origins = [target["settings"].better_auth_url].compact
config.email_and_password = {enabled: true}
config.plugins = []
end
auth = BetterAuth::Hanami.auth
register "better_auth.auth", auth
register "better_auth.rack_app", BetterAuth::Hanami::MountedApp.new(auth, mount_path: BetterAuth::Hanami.configuration.base_path)
end
end
trusted_origins controls Better Auth origin and redirect URL validation. If
your browser client calls the auth endpoints from another origin, configure Rack
CORS middleware in your Hanami app as well so preflight requests and
Access-Control-* response headers match your frontend origin and credentials
policy. For the shared Rack/CORS/CSRF boundary, see
host-app-responsibilities.md.
Do not rely on a Hanami-only empty trusted_origins list as a strict
deny-all-origin policy; set real deployment URLs in app settings. Keep
BetterAuth::Hanami::MountedApp behavior aligned with Hanami's router instead
of copying Rails mount internals without integration tests. Be cautious with
relation or inflector overrides generated for an app, because overwriting
application-specific Hanami relations can be destructive.
Regenerating Migrations
The migration generator skips an existing *_create_better_auth_tables.rb file
by default so user-edited migrations are not overwritten. To intentionally
regenerate the base migration for a new app or after changing plugin schemas,
call the Ruby API with force: true:
BetterAuth::Hanami::Generators::MigrationGenerator.new.run(force: true)
The generated rake task keeps the non-overwriting behavior:
bundle exec rake better_auth:generate:migration
Routes
The generated config/routes.rb includes:
require "better_auth/hanami"
module Bookshelf
class Routes < Hanami::Routes
include BetterAuth::Hanami::Routing
better_auth
end
end
By default this mounts Better Auth at /api/auth. Customize the path:
better_auth at: "/auth"
BetterAuth::Hanami::MountedApp expects PATH_INFO in the shape produced by
Hanami's router; see spec/better_auth/hanami/routing_spec.rb. Custom Rack
stacks with different SCRIPT_NAME conventions may need application-level path
rewriting.
Action Helpers
Include helpers in your base action:
class Action < Hanami::Action
include BetterAuth::Hanami::ActionHelpers
end
Use them from an action:
def handle(request, response)
return unless require_authentication(request, response)
response.body = current_user(request).fetch("email")
end
Relations And Repos
Better Auth uses BetterAuth::Hanami::SequelAdapter for its own reads and
writes. The generated Hanami relations/repos are for your application code when
you want to inspect or query Better Auth tables directly:
users = Hanami.app["relations.users"].to_a
user = Hanami.app["repos.user_repo"].users.by_pk(user_id).one
If you prefer a custom persistence implementation, configure it directly:
BetterAuth::Hanami.configure do |config|
config.database = ->() { MyBetterAuthAdapter.new() }
end
Limitations
- Supports Hanami 2.3+ only. Better Auth core depends on Rack 3, and Hanami 2.3 is the first Hanami line that allows Rack 3.
- Hanami 1.x and Hanami 2.2/Rack 2 apps are out of scope for this adapter.
- The stable command surface is Rake/generator based. A
hanami better_auth ...command is not exposed because the current public guides do not document a stable third-party Hanami CLI extension API. - Apps created with
--skip-dbcan use memory storage for development or tests, but production apps should configure Hanami DB or pass an explicit Better Auth adapter.
Development
cd packages/better_auth-hanami
rbenv exec bundle exec rspec
rbenv exec bundle exec standardrb