Nowadays, token-based authentication has become more and more popular in the development of web and mobile applications.
There are many different types of tokens, but among them, JSON web token (or JWT) is one of the most widely used.
However, in the past few years, we’ve also discovered several security issues regarding JSON web token, mainly because of its poorly designed standard.
So recently people have started migrating to other types of tokens such as PASETO, which promises to bring better security to the application.
In this lecture, we will learn everything about the security issues of JWT and how PASETO is designed to solve all of those problems.
First, let’s talk a bit about token-based authentication.
Basically, in this authentication mechanism, the client will make the first request to log in user, where it provides the username and password to the server.
The server will check if the username and password are correct or not. If they are, the server will create and sign a token with its secret or private key, then sends back a
200 OK response to the client together with the signed access token.
The reason it’s called access token is that later the client will use this token to get access to other resources on the server.
For example, let’s say the client wants to get the list of bank accounts that belong to the logged-in user. Then it will make a
GET /accounts request to the server, where it embeds the user’s access token in the header of the request.
Upon receiving this request, the server will verify if the provided token is valid or not. If it is valid, the request will be authorized, and a
200 OK response will be sent back to the client with the list of user’s bank accounts.
Note that an access token normally has a lifetime duration before it gets expired. And during this time, the client can use the same token to send multiple requests to the server.
So that’s how the token-based authentication works.
Now let’s talk about JSON Web Token! Here’s an example of a JSON Web Token:
It is a base64 encoded string, composed of 3 main parts, separated by a dot.
The first part (with the color red) is the header of the token. When we decode this part, we will get a JSON object that contains the token type
JWT, and the algorithm used to sign the token:
HS256 in this case.
The second part (in purple) of the token is the payload data. This part is where we store information about the logged-in user, such as username, and also the timestamp at which this token will be expired.
You can customize this JSON payload to store any other information you want. In this case, we also have an ID field to uniquely identify the token. It will be useful in case we want to revoke access of the token in case it is leaked.
Keep in mind that all data stored in the JWT is only base64-encoded, not encrypted. So you don’t need the secret/private key of the server in order to decode its content.
It also means that we can easily encode the header and payload data without the key. So how can the server verify the authenticity of the access token?
Well, that’s the purpose of the third part of the token: the digital signature (in blue color). If you don’t know how the digital signature algorithm works, then I recommend you to read my post about SSL/TLS before continuing.
The idea is simple, only the server has the secret/private key to sign the token. So if a hacker attempts to create a fake token without the correct key, it will be easily detected by the server in the verification process.
The JWT standards provide many different types of digital signature algorithms, but they can be classified into 2 main categories.
The first one is symmetric-key algorithm, where the same secret key is used to both sign and verify the tokens.
And since there’s only 1 key, it should be kept secret. So this algorithm is suitable for local use only, or in other words, for internal services, where the secret key can be shared.
Some specific algorithms which belong to this symmetric-key category are:
Symmetric-key algorithm is very efficient and suitable for most applications.
However, we cannot use it in case there’s an external third-party service that wants to verify the token, because it would mean we must give them our secret key.
In that case, we must use the second category: asymmetric-key algorithm.
In this type of algorithm, there’s a pair of keys instead of just 1 single secret key.
The private key is used to sign the token, while the public key is used only to verify it.
Therefore, we can easily share our public key with any external third-party services without worrying about leaking our private key.
Within this asymmetric-key category, there are several groups of algorithms, such as
PS group, or
RS256 is basically
RSA algorithm with
PS256 is also
RSA algorithm but with Probabilistic Signature Scheme and
SHA256. It was designed to be more secured than
And the last one
ES256 is simply Elliptic Curve Digital Signature Algorithm with
OK, so far it sounds like JWT is a good standard, and it gives us a lot of flexibility to choose whatever signing algorithms we want. So what exactly are its problems?
Well, the first problem is weak signing algorithms. JWT gives developers too many algorithms to choose from, including the algorithms that are already known to be vulnerable, such as:
PKCSv1.5is susceptible to a padding oracle attack.
ECDSAcan face an invalid-curve attack.
For developers without deep experience in security, it would be hard for them to know which algorithm is the best to use.
So the fact that JWT gives developers too much flexibility to choose the algorithm is like giving them a gun to shoot themselves in the foot.
But it’s not the worst. JSON web token makes token forgery so trivial, that if you are not careful in your implementation or if you choose a poorly implemented library for your project, your system will easily become a vulnerable target.
One bad thing about JWT is that it includes the signing algorithm in the token header.
Because of this, we have seen in the past, an attacker can just set the
alg header to
none to bypass the signature verification process.
Of course, this issue has been identified and fixed in many libraries, but it’s something you should carefully check when choosing the community-developed library for your project.
Another more dangerous potential attack is to purposely set the algorithm header to a symmetric-key one, such as
HS256 while knowing that the server actually uses an asymmetric-key algorithm, such as
RSA to sign and verify the token.
Let me explain how!
Basically, the server’s RSA public key is clearly known to the public because it’s a public key.
So the hacker can just create a fake token of the admin user, where he purposely set the algorithm header to
HS256, which is a symmetric-key algorithm.
Then, he just signs this token with the server’s public key and uses it to access resources on the server.
Now, keep in mind that, the server normally uses an
RSA algorithm, such as
RS256 to sign & verify the token, so it will use the
RSA public key as the key to verify the token signature.
However, since the token’s algorithm header is saying
HS256, the server will verify the signature with this symmetric algorithm
HS256 instead of
And because the same key is used by the hacker to sign the token payload, this signature verification process will be successful, and the request of the hacker will be authorized.
This kind of attack is very simple, but still so powerful and dangerous, and it has actually happened in the past because the developers didn’t check the algorithm header before verify the token signature.
So, in order to prevent this attack, it’s crucial that in your server code, you must check the token’s algorithm header to make sure that it matches with the one your server uses to sign and verify tokens.
OK, so now you know why JSON web token is not a very well-designed standard. It opens the door to many potential threats.
Therefore, many people are trying to stay away from it, and migrate to something more robust.
PASETO, or Platform Agnostic Security Token is one of the most successful designs that is being widely accepted by the community as the best-secured alternative to JWT.
It solves all issues of JSON web token by first, provide strong signing algorithms out of the box.
Developers don’t have to choose the algorithm anymore. Instead, they only need to select the version of
PASETO they want to use.
PASETO version has already been implemented with 1 strong cipher suite. And at any time, there will be only at most 2 latest versions of
PASETO are active.
Right now, 2 active
PASETO versions are version 1 and version 2.
Version 1 is older, and should only be used for legacy systems that cannot use modern cryptography.
PASETO also has 2 algorithm categories for 2 main use cases.
For local or internal services, we use a symmetric-key algorithm.
But unlike JWT, which only does base64-encode the payload, and sign the token,
PASETO actually encrypts and authenticates all data in the token with a secret key, using a strong Authenticated Encryption with Associated Data (or
AEAD) algorithm. If you don’t know what AEAD is, you can watch my video about SSL/TLS.
AEAD algorithm used in
PASETO version 1 is
AES256 CTR with
For public cases, where there are external services that need to verify the token, we have to use an asymmetric-key algorithm.
In that case,
PASETO uses the same approach as
JWT, which means, it doesn’t encrypt the token data, but only base64-encode it, and uses the private key to sign the content with a digital signature.
The chosen asymmetric-key algorithm in
PASETO version 1 is
RSA PSS with
In the latest version of
PASETO (version 2), 2 more secured and modern algorithms are being used.
For local symmetric-key scenario, it uses
And for a public asymmetric-key scenario, Edward-curve digital signature algorithm with curve
25519 is used.
This choice reminds me of how
TLS 1.3 was designed to improve the security of its older version
TLS 1.2, and also simplify & reduce the number of TLS cipher suites at the same time.
Now with the design of PASETO, token forgery is no longer trivial.
Because the algorithm header doesn’t exist anymore, so the attacker cannot set it to
none, or force the server to use the algorithm it chose in this header.
Everything in the token is also authenticated with
AEAD, so it’s not possible to tamper with it.
Moreover, if you use a local symmetric-key algorithm, the payload is now encrypted, not just encoded, so it’s impossible for hackers to read or change the data stored in the token without knowing the server’s secret key.
Sounds amazing, right?
In the next lecture, I’m gonna show you how to implement both
PASETO using Golang.
You will see
PASETO not only makes it safer but also easier and so much simpler to implement, compared to
For now, let’s take a look at the structure of a
This is a
PASETO version 2 token for local usage purposes. There are 4 main parts of the token, separated by a dot.
The first part is
PASETO version (with red color), which is
The second part is the purpose of the token, is it used for
public scenarios? In this case, it is
local, which means using a symmetric-key authenticated encryption algorithm.
The third part (with green color) is the main content or the payload data of the token. Note that it is encrypted, so if we decrypt it using the secret key, we will get 3 smaller parts:
- First, the payload body. In this case, we just store a simple message and the expiration time of the token.
- Second, the nonce value that is used in both encryption and message authentication process.
- And finally the message authentication tag to authenticate the encrypted message and its associated unencrypted data.
In this case, the unencrypted data is the version, the purpose, and the footer of the token (with purple color).
You can store any public information in the footer because it won’t be encrypted like the payload body, but only
base64 encoded. So anyone who has the token can decode it to read the footer data.
In this case, it is Paragon Initiative Enterprises, the one who invented
Note that the footer is optional, so you can have a PASETO token without a footer. For example, this is another PASETO token for the public usage scenario:
It only has 3 parts, with no footer. The first part is
PASETO version, which is
The second part is its purpose:
public in this case, which means an asymmetric-key digital signature algorithm is used to sign the token, and its payload data will not be encrypted, but only
As you can see here, the green part of the payload is actually the encoded body, which we can easily decode to get this JSON object.
While the blue part of the payload is the signature of the token, created by the digital signature algorithm using the private key.
The server will use its paired public key to verify the authenticity of this signature.
And that’s it for today’s lecture about token-based authentication.
We have learned about the design flaws of
JSON Web Token that causes many security issues in the past, and how
PASETO was invented to fix all of those problems, and thus, make our developers’ life much easier.
I hope you like this article, and see you in the next one, where we will write codes to create and verify
PASETO tokens in Golang.
If you want to join me on my current amazing team at Voodoo, check out our job openings here. Remote or onsite in Paris/Amsterdam/London/Berlin/Barcelona with visa sponsorship.