LogoTRUONG PHAM
Home
Projects
Blogs
YouTube
Contact

Newsletter

Stay updated with technical artifacts and engineering insights.

LogoTRUONG PHAM

Building scalable software and sharing insights on technology & life.

Sitemap

  • Home
  • Projects
  • Blogs
  • YouTube
  • Contact

Connect

  • GitHub
  • LinkedIn
  • Email
  • YouTube

© 2024 TRUONG PHAM. © All rights reserved.

Privacy PolicyTerms of Service
Back
Authentication & Authorization - When API Gateway Carries the Team
Microservice Journey: Lessons & Trade-offs

Authentication & Authorization - When API Gateway Carries the Team

Does each service check the token itself or do it in one place for all? How we set up security without overloading the code base.

TP
Truong PhamSoftware Engineer
PublishedMarch 23, 2024
Stack
microservice ·security ·auth

Security in Microservices is like security checks at an airport. Do you want to check once at the entrance, or should guards ask for your passport at every duty-free shop?


The Problem: Who is the User?

In a Monolith application, you have user sessions in memory or a database. Every function easily knows the currentUser. In a Microservice, a User's request might pass through 5 different services. How does service number 5 know this is User A and that User A has permission to perform this action?

1. The Naive Approach: Every Service Auths Itself

We started by implementing JWT authentication logic in every service. Consequences:

  • Code duplication everywhere.
  • Every time the encryption algorithm changes or a new permission type is added, I have to update 10 services.
  • More importantly: Each service has to call the AuthService or Database to check the user—creating a huge and useless amount of internal traffic.

2. API Gateway: The Powerful Gatekeeper

We switched to using an API Gateway (like Kong, Traefik, or a simple Next.js service) as the single point of entry for external requests.

Workflow:

  1. User sends a request with a JWT to the Gateway.
  2. The Gateway validates the JWT and checks if the token is still valid.
  3. The Gateway extracts user information from the token (User ID, Roles).
  4. The Gateway pushes this information into Internal Headers (e.g., X-User-ID, X-User-Roles) and forwards the request to the internal services.

Huge Benefit: Internal services are now extremely "naive." They don't need to know what a JWT is; they just say: "Ah, I have the X-User-ID header, I'll just do my job."

3. But What About Internal Security?

What if someone manages to break into the internal network and sends a request directly to a service (bypassing the Gateway) with a forged header?

Trade-offs for small teams: If you have the resources, use mTLS (Mutual TLS) between services. But for a 2-person team, managing certificates for mTLS is an enormous burden. Our practical solution: Only allow traffic into the services from the API Gateway's IP (Network isolation). Simple, effective, and secure enough for the early stages.


Lessons Learned

  1. JWT is Your Best Friend: Pack as much necessary (but non-sensitive) information into the JWT as possible to minimize database queries.
  2. Stateless is Key: Don't use Sessions. Microservices are built to scale, and Sessions will make scaling a nightmare.
  3. BFF (Backend for Frontend) can also do Auth: If you use Next.js, leverage it to handle Auth before calling down to the business microservices.

Security is not a thick wall, but a reasonable process. For small teams, prioritize centralization for easier management and maintenance.


Conclusion

Don't try to overcomplicate security issues with enterprise solutions from the start. A good Gatekeeper Gateway coordinated with Network Isolation is enough to protect against 99% of common risks for a startup project.

Series • Part 6 of 20

Microservice Journey: Lessons & Trade-offs

NextDocker Compose is Not Enough - The Local Development Story
Distributed Transactions - Why 'Immediate Consistency' is a Luxury
01Trade-offs Under Pressure02Microservices is Not Just About Splitting Services03Monorepo or Microservice? Lessons from a 2-Person Team04REST, gRPC, or NATS? Don't Let Choice Bury Progress05Distributed Transactions - Why 'Immediate Consistency' is a Luxury06Authentication & Authorization - When API Gateway Carries the TeamReading07Docker Compose is Not Enough - The Local Development Story08Database Separation - A Painful but Necessary 'Divorce'09BFF (Backend for Frontend) - The Savior of UX10Idempotency - Why Every API Should Be 'Stubborn'?11Infra as Code (IaC) - Automate or Die in a Mountain of Config
TP

Written by Truong Pham

Software Engineer passionate about building high-performance systems and meaningful experiences.

Read more articles