Using JSON Web Token in Microservice Architecture

JSON Web Token is a simple and powerful way to generate tokens for APIs. These tokens convey a payload that is cryptographically signed. The payload itself is not encrypted, but the signature protects it against tampering. In their base format, a “secret key” is used in the generation and verification of the signature. In this […]

Category

Technologies

Posted

Andrii

Nov 17, 2022

JSON Web Token is a simple and powerful way to generate tokens for APIs. These tokens convey a payload that is cryptographically signed. The payload itself is not encrypted, but the signature protects it against tampering.

In their base format, a “secret key” is used in the generation and verification of the signature. In this blog, I’m going to show you a less-known mechanism to generate JWTs that have signatures that can be verified without having access to the secret key.

Using public key with JWT

The disadvantage of the HS256 signing algorithm is that the secret key must be present both when creating and verifying tokens. For a single application, this is not a problem. But if you have a distributed system consisting of several services that work independently of each other, you will have to choose between two bad options:
● You can create a service to create and validate tokens. Any of your services that receive a token from a client must call the service to validate the token. For highly loaded systems, this creates a bottleneck.
● You can give a secret key to all your services that receive tokens from clients for their subsequent authentication. But this increases the likelihood of compromising the secret key.

As a result, it is better for a distributed application to store the signing key in the authentication service and use it only to generate keys, while all other services can verify these tokens without actually having access to the key.

There are signature algorithms for JWTs where the token is generated with a private key, and then they can be verified by anyone using the server’s public key, which is freely available to anyone who wants to get it. For the following example, I will use Python and the RS256 signature algorithm, which is short for RSA-SHA256.

Example

The pyjwt package does not provide cryptographic signature capability for more advanced public key signature algorithms but instead depends on a cryptography package that provides them. Thus, to use public key signatures, you need to install this package:
>>> pip install cryptography

Next, we create a set of public/private keys for the application to use. There are various ways to generate RSA keys, but I use openssh’s ssh-keygen tool: >>> ssh-keygen -t rsa -b 4096 -m pem

The -t option to ssh-keygen specifies that I’m requesting an RSA key pair, and the -b option specifies a key size of 4096 bits. The -m option means that the key must be generated in PEM format.

After running the command, you will be prompted for the name of this key pair, you can specify jwt-key without specifying the path so that the keys are created in the current directory. The password to protect the key must be left blank.

After executing the command, two files will be returned in the directory: jwt-key and jwt-key.pub. The first is the private key that will be used to create the token, so you put it in a safe place. The .pub file will be used to validate the tokens. This file does not contain confidential information and you can freely use it in any project where token verification is required.

Creating and Verifying Tokens

Let’s create a new token right away:
>>> import jwt
>>> private_key = open(‘jwt-key’).read()
>>> token = jwt.encode({‘user_id’: 777}, private_key, algorithm=’RS256′)
>>> token “***.***.***”

The received token contains a payload that is not encrypted, so for these tokens, you should never put sensitive information in the payload.

Now that we have the token, we can verify it with the public key. Here is an example of token validation:

>>> import jwt >>> public_key = open(‘jwt-key.pub’).read() >>> token = ‘..’
>>> payload = jwt.decode(token, public_key, algorithms=[‘RS256’])
>>> payload
{‘user_id’: 777}

Conclusion

Now you can use this approach to validate JWT tokens without worrying about your private key.

We appreciate our Swan team member taking the time to share. Our team can help your team with a custom application or other IT needs. Schedule a free assessment.