Skip to content
All articles
Engineering2 min read

Designing Auth Teams Don't Have to Think About

Authentication is the feature every SaaS rebuilds and gets subtly wrong. A look at the architecture decisions behind building it once, correctly.

Every SaaS team rebuilds authentication. Most of them get the happy path right and the edge cases wrong — token rotation, revocation, multi-tenancy, audit. The failures are invisible until they're a breach.

Here's how I think about building auth infrastructure that teams can adopt without becoming security experts.

Speed and revocation are in tension#

Stateless JWTs are fast: verify a signature at the edge and you're done, no round-trip to origin. But they can't be revoked before they expire. That's unacceptable for a compromised session.

The resolution is a hybrid: keep the common path stateless, add a compact, edge-replicated revocation set for the rare case.

async function verifySession(token: string): Promise<Session | null> {
  const claims = await verifyJwt(token, publicKey); // fast path
  if (!claims) return null;
 
  // Only revoked sessions hit this set; it's tiny and edge-cached.
  if (await revocationSet.has(claims.sid)) return null;
 
  return claims;
}

The result: signature-check latency in the common case, seconds-to-revoke when it matters.

Tenancy belongs in the database#

Application code has bugs. A single query that forgets a WHERE org_id = ? is a cross-tenant data leak. So isolation shouldn't live in application code alone.

I enforce it at the database layer with row-level security tied to the authenticated organization:

  • Every tenant-scoped table has an RLS policy.
  • The policy references the current org from the session context.
  • Application bugs fail closed instead of leaking.

The data model is the product#

In B2B auth, organizations, memberships, invitations, and roles aren't add-ons — they're the core. Getting them right early avoids painful migrations when your first enterprise customer asks for SSO and nested teams.

Design the SDK before the API#

We designed the developer experience of the SDK before finalizing the HTTP API. This kept the API honest: if something was awkward to express in the SDK, the API was wrong.

The "5-minute integration" promise is only real if you work backwards from the developer's first five minutes.

Secure defaults win#

Every unsafe option we removed increased adoption. Developers don't want a hundred knobs — they want the right thing to happen when they do nothing special. Make the secure path the easy path, and you've built auth people don't have to think about.

  • Architecture
  • Security
  • Infrastructure
  • TypeScript
Share