15

It is my understanding that HMAC is a symmetric signing algorithm (single secret key) whereas RSA is an asymmetric signing algorithm (private/public key pair). I am trying to choose between these 2 methods for signing JSON Web Tokens.

However, I am a little bit confused about the use case of HMAC. If both the clients (users) and the server share a key, what is stopping the client from changing the token's payload fields (perhaps the subject to another user's id) and then resigning the token client-side. Clearly this would be bad. Does HMAC only guarantee that the data was signed by someone with the secret key, and not just a single entity as with RSA? What use case does this actually have, perhaps I am misunderstanding something? Or perhaps the secret key isn't even shared with clients at all?

4Matt
  • 375
  • 1
  • 2
  • 7

2 Answers2

17

HMAC is used to protect against manipulation by someone who has not access to the secret. Typically this means to protect against manipulation by the client if the secret is only known to the server or to protect against manipulation in transit if the secret is known to client and server.

An RSA based signature is used to protect against manipulation and also to allow others to verify the integrity and source of the data without being able to manipulate the data. This can be done because the private key is only known to the provider and signer of the data while the public key is known to everybody who likes to verify the integrity.

What to choose thus depends on your specific use case. If the server just needs to protect the token against manipulation by the client then using HMAC with a server side secret is enough. If instead it needs to be also proven to others that the token was created by a specific (trusted) server then RSA based signatures should be used.

Steffen Ullrich
  • 184,332
  • 29
  • 363
  • 424
  • But doesn't the knowledge of a shared secret have a similar function to a RSA signature? E.g. if I tell Bob's server a shared secret X, and I receive a JWT with a HMAC with key X, then I know Bob created it. Or am I wrong in this assumption? –  Oct 25 '19 at 11:34
  • 2
    @MechMK1: Depends how many have the shared secret. With HMAC everybody having the shared secret can verify the integrity but also modify the data, which means that it cannot really be used as proof of origin of more than 2 parties are involved (which also means that the secret needs to be protected in transit between these two parties). With RSA signature everybody having the public key can verify the signature but only the one having the private key can create it. – Steffen Ullrich Oct 25 '19 at 11:51
  • Yes, that's true. I don't know in which scenarios JWT's would be used in such a manner, but I understand the point behind it. –  Oct 25 '19 at 11:55
3

See the longer answer on recommended algorithm for JWT, the one line answer is to go with RS256 (RSA 2048 bits with SHA 256).

JWT tokens support a few signature schemes, mainly: RSA (RS256), ECDSA (ES256) and HMAC (HS256).

HMAC is a specialized symmetric signature mode that is specific to JWT. It has no practical use cases as far as I am aware, you're better off ignoring it entirely.

In HMAC, the application and the identity provider share ONE secret passphrase. The passphrase is used to both create and verify tokens.

It's odd when one thinks about it, because it allows both the client and the identity server to create authentication tokens. The "normal" mode of operation is only for the identity server (Google, Facebook auth, internal Active Directory, etc...) to authenticate users and create JWT tokens. It makes no sense for clients to manufacture tokens.

In theory, HMAC could be used in some exotic app2app use cases, but those are already covered -and more secure- when using normal signatures (RSA/ECDSA), so there are no practical applications for HS256.

  1. transitive trust: Google and Apple auth could trust one another, sharing one secret passphrase to craft and communicate internal tokens to one another.

Except federated authentication is already supported by regular signatures out-of-the-box and more easily. There is no reason to prefer a secret passphrase, it takes extra work to share the secret passphrase across organizations and both organizations will be compromised if either leaks the secret.

  1. app2app authentication: a service can authenticate to the identify server to obtain a JWT token for itself and communicate with other services (that are protected by authentication).

Except programmatic authentication is already supported out-of-the-box using username/password or certificate authentication. There is no reason to prefer a secret passphrase.

I do authentication for a living, I've implemented all these use cases in some companies. Deep in the abyss of the spec, in the client_credentials grant in service to service authentication (besides client certificate authentication), there are things about clients signing JWT tokens. I'm 99% sure that's the only place where shared secret mode could be used (in a non insane way) and why the mode is supported at all in the spec... and all that's there is better covered by using certificate authentication.

user5994461
  • 1,216
  • 3
  • 12
  • 11
  • [This article](https://www.loginradius.com/blog/async/jwt-signing-algorithms/) comments: "Having a shared secret key can however also be useful in some cases. For example, if the issuer and recipient were both managed by a single party, the two applications would be able to share configurations without having to manage two separate keys. As such, HS256 may be more suitable for situations where data is exchanged within a single party" – conny Jan 11 '21 at 09:51
  • That justification is irrelevant at best. If you want to share a single configuration between services because it's easier to manage, it practically makes no difference whether it is sharing a common password (password authentication), a RSA key (RS256), or a secret key (HS256). However you're gonna need to implement that authentication method in both apps (possibly in different languages/frameworks), HS256 being the least documented and the least widely supported algorithm, you're probably better off with the other methods. – user5994461 Jan 12 '21 at 19:01