Weekly Commit #005
This week kicked off Sprint 1 of the Beta phase on a university project, and almost all of it went into one unglamorous-but-critical layer: authentication.
Why auth first
It's tempting to start with the visible stuff, screens, features, the home page. We already had a prototype that we presented for the Alpha Phase where it shows only UI. But auth is the thing everything else leans on. Get it wrong and you're either rebuilding it later or shipping a hole. So Sprint 1 was about laying that foundation across all three layers: backend, mobile, and web.
The backend (the core)
This is where most of the work lived. The shape of it:
- User entity + Role enum, backed by a repository
- Password hashing with bcrypt (never store what you can hash)
- A JWT issuer + verifier, access tokens to prove who you are, refresh tokens to stay logged in
- A clean error/exception hierarchy so failures return sane, consistent responses
- An RBAC mechanism wired into a JWT validation filter, so routes can actually enforce roles
- Register / login / refresh / logout endpoints
- A Datastore-backed revocation list, so a logged-out (or stolen) refresh token can be killed server-side
That last one is the detail people skip. A JWT is valid until it expires, there's no built-in "undo." If you want real logout, you need somewhere to track what's been revoked.
The clients (mobile + web)
The interesting pattern here is the auth interceptor, the same idea implemented twice:
- Mobile: tokens in
flutter_secure_storage, an HTTP wrapper that refreshes-on-401 - Web: tokens in session/localStorage, a fetch wrapper that does the same
The trick on both: when a request comes back 401, don't just fail, try the refresh token, get a new access token, and silently retry the original request. Done right, the user never notices their token expired.
Where it stands
End-to-end register / login / home / logout works across backend, web, and mobile. Foundation's in.
More in #006.
#WeeklyCommit
Follow along here or on LinkedIn where I'll be sharing each new commit.