
How I Built Google OAuth for a Real SaaS (Next.js + Auth.js) — CreatorCopilot Part 2
Learn how to implement production-ready Google OAuth in Next.js using Auth.js (NextAuth v5) with App...

Most posts say: “Always put an API Gateway in front.”
That’s not advice. That’s a meme.
Reality: the right choice depends on your stage, your clients, and what you’re willing to operationally own. I’ve built microservice setups where direct calls were the only reason we shipped fast — and setups where skipping a gateway created a mess.
Here’s the decision, without fluff.
Direct calls: Service A calls Service B directly.
API Gateway: Clients call the gateway; the gateway routes to services and handles cross-cutting concerns.
Direct calls are attractive because they remove ceremony:
no routing config
no extra deployment to maintain
fewer failure points
lower latency today
# orders_service -> calls payments_service directly
import httpx
async def charge_customer(order_id: str, amount: int):
async with httpx.AsyncClient(timeout=5) as client:
r = await client.post(
"http://payments:8000/charge",
json={"order_id": order_id, "amount": amount},
headers={"X-Internal-Token": "..."}
)
r.raise_for_status()
return r.json()This is fast to build. You ship. You feel productive.
Then scale hits.
Every service begins implementing its own auth rules. They won’t stay consistent.
Service A rate limits one way, Service B another. Attackers love this.
Your frontend starts doing orchestration:
call auth
call users
call orders
call payments
merge responses
That’s not “microservices.” That’s clients doing backend work.
Without centralized entry + tracing, debugging becomes:
“Where did this request die?”
And you waste hours.
A gateway is basically a policy + routing layer.
Typical wins:
single place for JWT validation / RBAC
consistent rate limiting
request shaping (BFF-style
centralized logging + tracing headers
simpler clients (one API surface)
# Nginx as a simple gateway (illustrative)
location /api/orders/ {
proxy_pass http://orders:8000/;
}
location /api/payments/ {
proxy_pass http://payments:8000/;
}// Middleware at gateway (Next.js / Node / edge)
export function requireAuth(req) {
const token = req.headers.get("authorization")?.replace("Bearer ", "");
if (!token) throw new Error("Unauthorized");
// verify JWT once here
const user = verifyJwt(token);
req.user = user;
}Now services can focus on business logic — not “security plumbing” 20 times.
Here’s what tutorials conveniently skip:
extra hop (latency)
single chokepoint (bad config can break everything)
ops burden (deploy, scale, monitor)
risk of becoming a “gateway monolith” if you stuff business logic there
If you don’t have discipline, the gateway becomes the new monolith — just with better marketing.
you have 1 client (your own web app)
you have few services (2–5)
you’re still validating product/market fit
speed > polish
internal-only APIs
you have multiple clients (web + mobile + partners)
you need consistent auth + rate limiting + audit logs
you expose public APIs
observability is hurting (you can’t trace requests)
the team grows (more owners → more inconsistency)
Most sane setups end up here:
Gateway for external traffic (clients → gateway → services)
Direct calls internally (service → service)
If internal communication gets complex, then you graduate to:
async messaging (queues)
service mesh (only when you can afford it)
A gateway is not a default requirement.
Direct calls are not “wrong.”
The real question is: where do you want complexity to live — in every service, or in one place?
If you’re early-stage, start simple.
If you’re scaling clients/security/traffic, centralize policy.
That’s the trade-off.
🔥 Found this blog post helpful? 🔥
If you enjoyed this article and found it valuable, please show your support by clapping 👏 and subscribing to my blog for more in-depth insights on web development and Next.js!
Subscribe here: click me
🚀 Follow me on:
🌐 Website: sagarsangwan.dev
🐦 Twitter/X: @sagar sangwan
🔗 LinkedIn: Sagar Sangwan
📸 Instagram: @codingbysagar
▶️YouTube: @codingbysagar
Your encouragement helps me continue creating high-quality content that can assist you on your development journey. 🚀

Code. Write. Build. Explore. 💻✍️ Software developer by day, mechanical tinkerer by night. When I’m not shipping code or writing blogs, you’ll find me trekking up a mountain, whipping up a feast, or hitting the open road on two wheels. Life is better in high gear.
View more blogs by me CLICK HERE

Learn how to implement production-ready Google OAuth in Next.js using Auth.js (NextAuth v5) with App...

A practical guide to implementing a production-ready SEO stack in a Next.js blog. Learn how to add J...

If you’re a creator, engineer, or indie builder, you’ve probably learned this the hard way: Algorith...
Subscribe to get the latest posts delivered to your inbox