Identitas: Why We Built Our Own Auth Service
47 source files, 146 routes, 15 tables, 35 rate-limit rules, 3 auth providers. Every SaaS needs auth. Not every SaaS should build its own.
Why build auth in-house?
At 47 source files, Identitas is our smallest codebase. But it's the most critical — every request to every product goes through it. We chose to build because:
- Three apps, one identity. The same user logs into nexum.app, the admin panel, and the business portal. Shared session, per-app JWT secrets.
- Internal service auth. Machine-to-machine calls between Nexum and Identitas use
X-Internal-Keyheaders. No user session needed. - OIDC compliance. Third-party apps can authenticate through Identitas. We're the identity provider, not Auth0.
- Full control. When auth breaks, nothing works. We can debug, patch, and deploy at 2 AM without waiting for a vendor.
The architecture
Identitas has two layers of endpoints, separated by network boundary:
- External (auth routes): login, signup, password reset, OIDC authorize/callback, change password. These are proxied through Nexum backend — never exposed directly to the internet.
- Internal (admin routes): validate token, get user, sync user, create app credential. Called by other backend services with
X-Internal-Key. No user auth, just service auth.
// The validate endpoint — Identitas's most-hit route
POST /internal/validate
X-Internal-Key: ****
X-App-Id: nexum-backend
→ {
valid: true,
user: { id, email, name, avatar },
session: { id, expiresAt, createdAt },
orgs: [{ id, slug, role }]
}Auth providers
Identitas currently supports three authentication methods, each independently configurable per app:
- Email + password. bcrypt hashing (cost 10), constant-time comparison. Password reset via email verification. No plaintext passwords ever touch the database.
- Google OAuth. Standard OIDC flow. Identitas wraps Google's tokens — apps never see them.
- Apple Sign-In. Full OIDC compliance. Handles Apple's authorization state expiry (we learned this the hard way).
The cost of owning auth
Identitas has 83 commits across its history (older than the split — it was the first service we built). The ongoing maintenance cost is real:
- Security reviews. Every PR touching sessions, passwords, or tokens gets extra eyes. No exceptions.
- Rate limiting. 35 rules across Identitas, 240+ across Nexum. Per-IP, per-appId, per-endpoint. One misconfiguration and you're in credential-stuffing territory.
- Session invalidation. "Log out everywhere" requires Redis-backed session blacklists. We had to build that from scratch.
- OIDC compliance maintenance. Providers change their APIs. Apple's authorization state expiry broke our flow in July — we shipped a fix the same day.
Would we build it again?
Yes — but the threshold matters. Below three apps sharing one identity, use Auth0 or Clerk. The vendor cost is lower than the maintenance tax. Above three, the integration surface area starts to hurt — every vendor has its own API shape, its own session model, its own quirks.
We have three apps (admin, business, client) plus future products. Identitas was the right call. If you're at that threshold, building might be your answer too.
Identitas is not open source (yet). But we're considering it. If that interests you, let us know.