None

API authentication is rarely the part of the system people worry about.

It usually works. It's well documented. And once it's in place, it tends to stay untouched for years.

That's precisely why small misunderstandings here scale into large problems later.

None

API keys, OAuth, JWTs, and mTLS all solve different trust problems. They're often compared side by side, but they weren't designed to replace one another.

Understanding the context each one assumes is more useful than memorizing their mechanics.

None

API keys: identifying the caller, nothing more

Real-world examples: Stripe secret keys Twilio API keys SendGrid and Mailgun integrations

An API key is a shared secret between a client and a service.

If the request includes the key, the service assumes:

"This request belongs to that account."

That's the entire model.

For Stripe, this works well:

  • The key lives on your backend
  • It represents your Stripe account
  • Each request is scoped to that account's data

There's no user context involved, and none is expected.

Where API keys work best

  • Server-to-server integrations
  • Single-tenant access
  • Clear ownership of the key

They're simple, predictable, and easy to rotate.

Their natural limitations

API keys don't describe:

  • Who initiated the action
  • Why the request is being made
  • What subset of actions should be allowed

They identify the caller, but they don't express intent or permissions beyond that identity. Anything more complex has to be enforced separately.

None

OAuth: controlled access on someone else's behalf

Real-world examples: "Sign in with Google" GitHub OAuth apps Slack and Notion integrations

OAuth exists to solve a delegation problem.

Instead of sharing credentials, a user authorizes an application to act within defined boundaries.

When you connect a Slack app:

  • You choose what it can access
  • Slack issues a token with scopes
  • Slack remains in control of revocation

The application never gains full ownership of the account.

What OAuth is good at

OAuth clearly answers:

  • Who approved this access?
  • What permissions were granted?
  • Can this access be revoked independently?

That makes it ideal for third-party integrations.

What OAuth does not guarantee

OAuth does not automatically enforce:

  • Correct authorization logic
  • Resource ownership
  • Business rules

It defines permission to request, not permission to succeed. Those checks still belong to the API.

None

JWTs: portable identity with embedded context

Real-world examples: Auth0 access tokens Firebase Authentication Supabase JWT-based APIs

JWTs package identity and metadata into a signed token.

Instead of calling an auth server for every request:

  • The token carries user ID, roles, and expiration
  • Services verify the signature locally
  • Trust is derived from cryptographic integrity

This is why JWTs fit well in distributed systems.

Where JWTs shine

  • SPAs and mobile apps
  • Microservices
  • Systems that need stateless verification

They reduce coupling between services while maintaining a shared identity model.

Trade-offs to be aware of

JWTs are issued at a moment in time.

If permissions change later:

  • Existing tokens may remain valid
  • Revocation requires additional infrastructure
  • Authorization must still be checked per request

JWTs communicate identity efficiently, but they don't replace authorization logic.

None

mTLS: explicit identity between services

Real-world examples: Kubernetes service meshes (Istio, Linkerd) Google internal service communication Financial and payment networks

mTLS shifts authentication to the transport layer.

Both client and server present certificates. Both verify each other's identity. The connection itself becomes the proof.

This is particularly useful when no human is involved.

Why teams adopt mTLS

mTLS answers:

"Which service is making this request?"

Not via headers or tokens, but through cryptographic identity bound to infrastructure.

That's valuable in large internal systems where:

  • Many services communicate
  • Network boundaries are porous
  • Explicit trust is preferred over implied trust

Practical boundaries

mTLS is typically used:

  • Internally, not in browsers
  • Between known services
  • Alongside authorization policies

It secures the channel and the caller identity, but application-level permissions still apply.

None

Why these models are often confused

Most systems use more than one of these at the same time.

A typical SaaS might have:

  • OAuth for user integrations
  • JWTs for frontend access
  • API keys for internal tooling
  • mTLS between backend services

Confusion happens when assumptions from one model are applied to another.

Authentication establishes who is calling. Authorization decides what should happen next.

Each mechanism handles the first part differently, but none solve the second automatically.

It's usually more helpful to ask:

"What relationship am I modeling here?"

  • API keys model account-level trust
  • OAuth models delegated user consent
  • JWTs model portable identity
  • mTLS models service identity

Choosing the right one is less about trends and more about matching the trust boundary to the problem.

Thanks for readingg. Any thoughts?