RSA Signature Overview for JWT

I am implementing a login system using the JWT (JSON Web Token) scheme. Typically, after a user logs in / logs in, the server signs the JWT and passes it to the client.

The client then returns a token with each request, and the server checks the token before sending a response.

This is pretty much as you expect, but I have some problems with the process logic. Of all the mathematical articles I read, it seems that asymmetric keys are used to sign the RSA. Since the public key, as its name implies, is provided to the client, and the private key is stored on the server, it makes sense to sign the JWT with the public key that is sent to the client and verify it on the server side using the private key.

However, in every example and library, I see that the opposite is true. Any idea why this is? If the JWT is signed with a private key and verified with a public key, what's the point?

+21
source share
3 answers

First of all, apologies, this answer turned out to be rather long.

If you use RSA to sign your tokens, and the connecting client is a web browser, the client will never see RSA keys (public or private). This is because the client apparently does not need to check the validity of the JWT, only the server should do this. The client simply holds the JWT and shows it to the server when requested. Then the server checks its validity when viewing the token.

So why do you need a combined public / private key for JWT? Well, firstly, you do not need to use the public / private key algorithm.

You can sign a JWT with several different algorithms, RSA is one of them. Other popular signature options for your JWT are ECDSA or HMAC (the JWT standard also supports others ). HMAC, in particular, is not a public / private key scheme. There is only one key, a key that is used to sign and verify tokens. You can think of it as using the private key to sign and verify the JWT. I am by no means an expert in this matter, but here are the conclusions that I came to after my recent research:

Using HMAC is nice because it is the fastest option. However, in order to test JWT, you need to give someone one key that does everything. Sharing this key with someone else means that this person can now also sign tokens and pretend to be you. If you are creating several server-side applications that everyone should be able to test your JWTs, you may not want each application to be able to sign tokens as well (different programmers may support different applications, sharing the possibility of signing with more people is a security risk and etc.). In this case, it is better to have one strictly controlled private key (and one application that performs the signature), and then share the public key with other people to enable them to check tokens. Here, the private key is used to sign tokens, and the public key is used to verify them. In this case, you will want to choose RSA or ECDSA.

For example, you may have an ecosystem of applications that all connect to the same database. To enter the system, each application sends people to one, dedicated application "login". This application has a private key. Another application may verify that the person is logged in using the public key (but they cannot log in).

My research indicates that RSA is the best option for most JWT applications in this scenario. This is because, theoretically, your application will often check tokens. RSA is much faster than ECDSA when tested. ECDSA is primarily good because the keys are smaller. This makes it better for HTTPS certificates, because you need to send the public key to the client’s browser. However, in the JWT script, the keys remain on the server, so the storage size is not specified, and the verification speed is more important.

Bottom line: if you are creating a small application without a few small “micro-service applications” / you are the only developer, perhaps choose HMAC to encrypt your keys. Otherwise, probably choose RSA. Again, I'm not an expert, just someone who recently googled this topic, so grab this with a little salt.

+39
source

Your suggestion:

it makes sense to sign a JWT with a public key that is sent to the client and verify it on the server side using the private key.

wrong. Signing is performed using the server’s private key; encryption is performed using the client’s public key. This is how PKI as a whole works.

+11
source

There is a difference between signing / verifying and encrypting / decrypting data, but the semantics may be similar.

You sign the data with a private key, which is only in controlled sources, so anyone who receives information can use your public key to verify that this information was really sent by you and is the same information that you intended to send.

You encrypt data with a public key and decrypt with a private key. It sounds the opposite, but actually follows the same logical concept as signing. If you want to send data between person A and person B, both people have a pair of public / private keys, and they share their public keys with each other when they meet (handshake). A creates a message for B, encrypts it using the public key of B and sends it to B. Now no one without the private key of B can decrypt this message, including A, even if they originally sent it.

From a JWT perspective, the JWT payload itself is just Base64 encoded JSON with some standardized fields. The signature allows a person with a public key to verify that the information has not been changed by someone in the middle. Sounds like a checksum, but with some extra protective warm fuzzy feelings. The content of a signed JWT is easily visible (base64 encodes as Unicode or UTF-8, but not encrypted) to the end user and any intermediary, therefore they usually do not approve of sending confidential data in passwords like JWT or PII .

As already mentioned, most JWTs contain information intended not for clients, but to facilitate some stateless RESTful services. Typically, the JWT will contain accounts, user IDs, and often permissions as “claims”. The API endpoint can verify the signature and intelligently trust claims that will not be modified by the client. When a client sends a JWT for each request, the endpoint is forced to do many database operations back and forth, just to find its place, simply by checking the public key signature.

In addition, signed JWTs can be encrypted. According to the JWE specification , the payload is encrypted after signing, and then decrypted before verification. The trade-off here is that all endpoints must also have a private key to decrypt the JWT, but end users will not be able to see the contents of the JWT. I'm talking about exchanges because, in general, private keys are designed to be secure, and the widespread private key is simply less secure. Security, risk assessment and the cost / benefit of encryption is a completely different beast :)

+2
source

All Articles