Client authentication

mTLS in mobile apps: authenticating the client, not just the server

In ordinary TLS only the server proves who it is. With mTLS the client does too, and that symmetry is what lets you tell your real app apart from anything else that speaks HTTPS.

What mTLS is

Mutual TLS is standard TLS with client authentication switched on. During the handshake the server asks for a certificate, the client presents one and proves it holds the matching private key. If anything fails, the connection is dropped before a single byte of the HTTP request travels.

It is neither new nor proprietary: it has been part of TLS from the start and your web server already knows how to do it. What has historically kept it out of consumer apps is not the protocol but the logistics of issuing, delivering, renewing and revoking one certificate per device.

What it solves in a mobile app

A mobile backend has no reliable way of knowing who is talking to it. User-Agent is trivially forged, an API key baked into the binary is extracted with standard tooling, and a session token only proves somebody authenticated earlier, not which client is using it now.

A per-device certificate changes the question being asked: instead of checking a shared secret that travels with every request, you check possession of a private key that never leaves the device.

The real problem: certificate lifecycle

This is where most home-grown attempts at mobile mTLS come apart. Issuing the first certificate is easy; everything after that is not.

  • Provisioning: how a fresh install gets its certificate without that process becoming an open endpoint of its own.
  • Storage: the private key should be generated in, and stay in, the platform keystore, ideally hardware-backed.
  • Rotation: short-lived certificates limit the damage of a leak, but they demand silent automatic renewal.
  • Revocation: you need a mechanism, typically OCSP, to invalidate one device's certificate without waiting for it to expire.

How it fits your backend

Validation is done by your own edge server. In Nginx it comes down to naming the CA chain you accept and requiring the certificate on the routes that need it; the rest of your architecture is untouched.

Because the check happens at the edge and at the transport layer, rejected traffic never reaches your application: no workers, no database connections, no quota with your SMS provider.

Want to see it on your stack?

Request access to the closed beta and the integration documentation.