0

I am trying to achieve an authentication system that:

  • Has short-lived passwords/tokens (unlike Basic Auth or Api key),
  • Won't expose users credentials if my users table is leaked (unlike HMAC),
  • Every request to the API can be achieved with just one call to the server (unlike schemes with a refresh token).

I understand the OpenID/OAuth flows, where an authorization server generates the JSON Web Token (JWT) that a client can use to authenticate to access a resource.

I am considering a flow where the client generates and signs their own JWT:

  1. The user generates a private-public key pair, and registers the public key in the API server.
  2. The client creates a JWT with a claim with the accountId provided by the API server and an expiry claim (eg 1 minute from now).
  3. The client signs the JWT using one of the asymmetric algorithms and the private key.
  4. The client sends a request to the API server using the JWT.
  5. The server extracts the accountId claim from the JWT, and looks for the registered public key for that accountId in the database.
  6. If the signature of the JWT can be verified against the public key, the authentication succeeds. Otherwise, it fails.

The only trade-off (I think) is that each authentication needs a call to the DB to retrieve the account's public key. This is not an issue for us.

What are the security considerations or trade-offs of a scheme like that?

1

It sounds like you're basically just trying to re-implement mutual TLS ("mTLS", or TLS with Client Authentication). Security-wise, it's a great approach; no passwords / hashes / etc. to leak from the server (incidentally, HMAC by itself is not a suitable password hashing algorithm) but very strong authentication. You can also use a unique key for each client, even if they're owned by the same user, which makes it foolproof to tell, in the event of a compromise, where it occurred. Also, pretty much all standard operating systems and browsers, mobile or desktop, support secure storage and use of private keys, and support mTLS. Finally, while most OSes and such will secure the private keys pretty well and at least recommend putting a password on them (which never leaves the device), you can still add additional server-side security mechanisms to require true multi-factor authentication.

However, it runs into a problem when you try using it in practice: it's a hassle to move the secret key between devices, or set up new key pairs on different devices. Essentially, the user must either export, transfer, and import a key file (losing the advantage of "unique key per client" in the process, unless they then rotate the key on that client alone), or go through what amounts to full re-registration with each new client. This makes it inconvenient for anything with multiple clients (such as web browsers, different PCs, PC + mobile, multiple IoT units, etc.) shared by one user.

You also still need some out-of-band authentication option (email being the usual, or sometimes SMS, but both are less secure) or you have a problem whereby you can't ever restore access to somebody's account if they lose their private key (and also may have a bootstrapping problem; how does the user prove their identity in the first place?) For some systems that's a permissible limitation, but the typical user won't put up with it for the typical app. The out-of-band auth is also useful if you want to make it relatively easy to add unique keys for different users (otherwise, you need to use an already-authenticated client to authorize a new public key for that user).

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.