
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.

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.

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.

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.

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.

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.

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?