The story of how repetitive authentication development led to building a standalone auth microservice that solves a fundamental engineering problem.
Every backend project I have built starts the same way. New repo. Fresh database. And then before writing a single line of product code, auth. Registration. Email verification. Login. JWT tokens. Password reset. OAuth. Roles. Sessions. The first time I built it, I learned a lot. I understood JWTs, token expiry, password hashing, OAuth flows. It was genuinely valuable. Then I started the next project. And built it again. Then the next one. And built it again. At some point I stopped and looked at what I was doing. Every project needs authentication. The requirements are almost identical across all of them. The security concerns are exactly the same. Yet I was treating it as a fresh problem every single time. That is not engineering. That is repetition.
So I asked myself a simple question: why am I solving the same problem again?
The Real Problem With Copying Auth Code
The obvious solution is to copy it from the previous project. Most engineers do this. I did it too. But copying auth code carries a problem that only shows up later. Auth logic gets tangled with the application it was written for. It references that project's database models, that project's config structure, that project's way of handling errors. You copy it, spend a day untangling it, make adjustments to fit the new project, and ship it. Two months later you find a security issue in the original. You patch it there. The copy still has the old version. You forget. It happens.
The deeper issue is that every time you touch auth code to make it fit a new project, you introduce risk. Security code is not the place for casual modifications. A small change in how tokens are validated, how refresh tokens are stored, or how OAuth state is handled can create a vulnerability that looks completely normal in a code review. Copying is not reusing. It is duplicating - and duplicating security-critical code is one of the quieter ways things go wrong in backend engineering.
The Idea: A Microservice Built Once, Used Everywhere
The question was not how to write better auth code. The question was how to write it once and never write it again. Authentication is infrastructure. It is not a feature of any specific application — it is the layer that makes features possible. And like any infrastructure, it should live in one place, be maintained in one place, and be consumed by everything that needs it.
That is what microservices are for. We separate payment processing into its own service. We separate email sending into its own service. Auth deserves the same treatment, arguably more so, because the consequences of getting it wrong are more severe than a failed payment webhook.
The vision was straightforward: build a standalone auth microservice that any backend project can plug into. Not import as a library. Not copy code from. Actually plug into - send it an HTTP request, get back a JWT, validate that JWT locally, done. The application never touches passwords, tokens, or OAuth flows directly. One service. Any number of consumers. One place to maintain security. One place to patch vulnerabilities. That is AuthShield.
What AuthShield Actually Handles
AuthShield is a deployable FastAPI service backed by PostgreSQL and Redis. Here is what it covers out of the box:
- Authentication - Email and password registration with email verification, login returning JWT access and refresh tokens, Google and GitHub OAuth 2.0 via Authorization Code Flow, and TOTP-based two-factor authentication compatible with Google Authenticator and Authy.
- Authorisation - Role-based access control with three built-in roles: user, moderator, and admin. Roles are embedded in the JWT so downstream services check permissions without a single database call.
- Token security - 15-minute access tokens, 7-day refresh tokens with rotation on every use, Redis-based blacklisting so logout takes effect on the very next request, and refresh token reuse detection that revokes an entire token family the moment theft is suspected.
- Session management - Every login creates a tracked session recording IP address and device info. Users can list all active sessions and revoke any of them individually.
- Rate limiting - Redis sliding-window rate limits on every sensitive endpoint. Not fixed-window — sliding-window, which means there is no clock boundary reset to exploit.
- Production infrastructure - Dockerised with a multi-stage build, Nginx for TLS termination and security headers on every response, structured JSON logging, and 48 integration tests running against real PostgreSQL and Redis.
The integration pattern is the part that makes this actually useful as a reusable service. Any downstream project needs exactly one file and one shared environment variable. The file is 40 lines of Python. It validates the JWT locally - no runtime call to AuthShield on every request - extracts the user ID and roles from the token, and makes them available to every protected route. That is it. The application never thinks about auth again.
Why Not Auth0, Clerk, or Any Existing Solution
This is the question worth answering honestly. Managed auth services are good products. Auth0, Clerk, Supabase Auth - they are mature, well-documented, and genuinely save time. For many teams and many products, they are the right call. But I had two specific reasons for not going that route.
The first is understanding. When you use a managed auth service, you are trusting a black box with the most security-critical layer of your application. That is a reasonable tradeoff for speed. But it means that when something goes wrong - and in auth, something eventually always goes wrong — you are dependent on someone else's documentation, someone else's support, and someone else's timeline to fix it. I wanted to understand every decision in my auth layer. Why the token TTL is what it is. Why refresh tokens are stored hashed rather than plain. Why the OAuth state parameter exists and what happens if it is missing. Why sliding-window rate limiting behaves differently from fixed-window at the boundary. Not because I enjoy complexity, but because understanding your security layer is the difference between debugging a problem and being surprised by one.
The second is control. Security decisions should belong to the engineer shipping the system. What hashing algorithm, what token strategy, what revocation mechanism, what rate limit thresholds - these are decisions that have real consequences. Delegating them entirely to a third-party service means accepting their defaults without always knowing what those defaults are or why they were chosen. AuthShield gives full control over every one of those decisions. Every choice is visible, documented, and mine to change.
Neither of these reasons means managed auth services are wrong. They mean they were wrong for what I was trying to build.
What This Series Covers
This post is the origin story. The next three go into the parts that actually made me think. Next week - OAuth and why it is more than just adding a Google button. Week after - JWTs, logout, and why stateless tokens create a stateful problem. Final week - Rate limiting, testing, and the gap between working locally and running in production.
The GitHub repo is linked below. The README has a full integration guide — how to plug AuthShield into any backend project in under 30 minutes. Contributions and feedback are welcome.
One Last Thought
I built AuthShield because I saw a problem I kept solving repeatedly and decided to solve it once properly. But there is something else that came out of building it that I did not expect. The process of designing a security-focused microservice from scratch - making every decision deliberately, documenting every tradeoff, writing tests that actually run against real infrastructure - changed how I think about backend engineering in general.
Not every project needs a custom auth microservice. But every engineer who has built one has a different relationship with the auth layer in every project they touch after that. That, more than anything, is why I would recommend the experience.
AuthShield on GitHub: https://github.com/ravigupta97/authshield
Always learning, always observing.



Comments
Please log in or register to join the discussion