Auth Workspace: A Hexagonal Auth/authz Library For Axum + Postgres (v0.1.0, Feedback Welcome)
Hi everyone! I just released my first open-source project: a hexagonal
auth/authz library and standalone service in Rust.
What it does
- users, global and scoped roles (the scope is an opaque string like
project:42, the consuming service decides what it means), permissions - sessions with refresh-token rotation; rotation runs in one transaction
with SELECT ... FOR UPDATE, and replaying a revoked refresh token
revokes all of the user's sessions - Argon2id password hashing, JWT access tokens (HS256)
- runtime settings stored in the DB (e.g. toggling self-registration
without a redeploy) - Axum router, Postgres via sqlx, tracing exported to Jaeger over OTLP
- a lightweight JWT verifier for third-party services that only need to
check a token without touching the auth database - unit tests on in-memory ports plus integration tests with testcontainers
You can embed it as a library in your own Axum service, or run
auth-server as a standalone HTTP service.
Why I built it
I wrote the auth part for a project with a friend, then started my own
wiki project and realized I was about to write almost the same logic
again. So I turned it into a reusable library. I chose a hexagonal
design (auth-core has no sqlx/axum/argon2, adapters implement its
ports), so I can swap the database or the token implementation later,
for example SQLite instead of Postgres, without touching the core.
Status
v0.1.0, early, and not security-audited, so please don't treat it as
production-ready yet. Licensed under MIT OR Apache-2.0.
Plans
- an audit log for important events (for analytics and security review)
- an admin UI in Leptos (I'm new to it)
A question I'd love advice on
Every operation in my Postgres adapter runs in its own sqlx
transaction, but use cases in the core that call several ports in a row
don't share one. For example, change_own_password first updates the
password hash through one port and then revokes sessions through
another. If the second call fails, the password is changed but old
sessions stay valid. I can fix this one by merging both steps into a
single port method backed by one transaction, but I'm wondering if
there's a cleaner, more general pattern (Unit of Work, a
transaction-scoped repository factory) that doesn't leak sqlx into the
core. How would you do it in idiomatic Rust?
Any feedback on the architecture, API design or the crate layout is very
welcome. Thanks for reading!
1 post - 1 participant
Popular Products
-
Brightening & Hydrating Rose Facial C...$154.99$107.78 -
Pheromone Long Lasting Attraction Per...$88.99$61.78 -
Crystal Glass Rose Table Decoration w...$137.99$95.78 -
Mini Facial Hair Trimmer with Replace...$15.99$9.78 -
Whitening & Spot Removal Skincare Set...$201.99$140.78