In today's web world, secure connections are essential. JWT (JSON Web Tokens) is widely used for token-based authentication to verify requests, but it has its own disadvantages. New types of token authentication methods are emerging, and one of them is PASETO (Platform-Agnostic Security Tokens). In this article, we will first explore what JWT is and the issues associated with it. Then, we will introduce PASETO, highlighting its differences from JWT. Additionally, we will discuss the different types of PASETO tokens and provide a step-by-step guide on how to generate and validate them.
JSON Web Token (JWT) is a compact, URL-safe way to transfer information between two parties. It contains three parts: a header, a payload, and a signature. The header includes the token type and signing algorithm, the payload contains details about the user and token like issuer, expiry time, user id, other claims, and the signature verifies the token's authenticity. JWTs are commonly used in authentication systems, where a server generates a token after a user logs in, and the client uses this token to access protected resources. It is a base64 encoded string.
PASETO (Platform-Agnostic Security Tokens) is a modern security token format designed to be safer and more straightforward than JSON Web Tokens (JWT). Developed by Scott Arciszewski, PASETO addresses security issues inherent to JWT while promoting simplicity and robustness.
v1.local.1_5gaMPojdToeX6Kc6CV751PlwowSrvMUYuVAApH5HOdEh3MSCf3fQ6xsf1_zSprLvcDqUxXZIjNbaaQfpz12d9kmoM8p8oVG5wI-n_4Xghh29eJoVm2kuJ9K4seOBRNWugwqVTTSCwHuJyAM-sWD9sCOIYCrUAa0VR4Z5_XIRbCxvN4xU3aplUoRpZUssFYkxdKWgr3DXc6nD1CkrcE40wUhOk-jGVI7-QSp4_JDcceV7RYigr5q4KFKHRfI65Oznh4ucRAQw
The first section of the PASETO is the protocol version (v1). This tells you what version of the PASETO standard is being used. At the time of writing, there are two versions(v1 and v2) of the PASETO standard.
The second section of the PASETO is the purpose (local). PASETO only defines two purposes for tokens: local or public. I’ll expand on these later. For now, just know that the local purpose is the one I’m demonstrating here.
The third section of the PASETO defines the actual token contents, also known as the payload. It contains details about users and the token itself, such as claims, issuer, and other relevant information.
you can use PASETOs for two different purposes: symmetric (aka local) and asymmetric (aka public).
Local PASETOs are created and encrypted using a secret key, which functions like a long password. If anyone obtains the local PASETO token, they cannot extract any useful information from it without the secret key. As long as the secret key remains secure, the PASETO is safe even if shared publicly.
Use Case: You can use local PASETOs to verify one web service with another. For instance, a microservice architecture where an internal service needs to authenticate requests to another internal service can benefit from using local PASETOs. By encrypting the token with a shared secret key, only the intended service can decrypt and validate the token, ensuring secure communication between services.
Public PASETOs use a pair of public and private keys for encryption. The private key is used to sign the token, and the public key is used to verify its authenticity. This method ensures that the token can be verified by anyone with the public key but only signed by the private key.
Use Case: Public PASETOs are ideal for scenarios where you need to ensure that a token's authenticity can be verified by multiple parties without exposing the private key. For example, in a distributed system where different clients need to validate the token's authenticity, public PASETOs provide a secure solution. Only the server with the private key can sign the token, but any client with the public key can verify it, maintaining the token's integrity and trustworthiness.
To create and use PASETO in a Quarkus project, follow these steps. This example uses Gradle as the build tool, but you can also use Maven if you prefer.
First, create a new Quarkus project. You can do this using the Quarkus CLI or through the Quarkus website.
Add the following dependencies to your build.gradle file. For Maven users, search for the corresponding dependencies in the Maven repository and add them to your pom.xml.
implementation 'dev.paseto:jpaseto-api:0.7.0'
implementation 'dev.paseto:jpaseto-impl:0.7.0'
implementation 'dev.paseto:jpaseto-jackson:0.7.0'
implementation 'dev.paseto:jpaseto-bouncy-castle:0.7.0'
package com.grootan;
import dev.paseto.jpaseto.Pasetos;
import dev.paseto.jpaseto.lang.Keys;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import javax.crypto.SecretKey;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Random;
@Path("/token/create")
public class CreateTokenService {
public static final SecretKey SHARED_SECRET = Keys.secretKey();
@GET
@Produces(MediaType.TEXT_PLAIN)
public String createToken() {
Instant now = Instant.now();
String token = Pasetos.V1.LOCAL.builder()
.setSharedSecret(SHARED_SECRET)
.setIssuedAt(now)
.setExpiration(now.plus(1, ChronoUnit.HOURS))
.setAudience("blog")
.setIssuer("https://ezto.io/")
.claim("1d20", new Random().nextInt(20) + 1)
.compact();
return token;
}
}
A PASETO token is then created using the Pasetos.V1.LOCAL.builder(). The following claims and properties are set on the token:
The compact() method finalizes the token creation process, returning the token as a string.
You can make get request to this API to get your PASETO.
package com.grootan;
import dev.paseto.jpaseto.Paseto;
import dev.paseto.jpaseto.PasetoParser;
import dev.paseto.jpaseto.Pasetos;
import dev.paseto.jpaseto.Version;
import dev.paseto.jpaseto.lang.Keys;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import java.security.KeyPair;
import static com.grootan.CreateTokenService.SHARED_SECRET;
@Path("/token/verify")
public class VerifyTokenService {
private static final KeyPair KEY_PAIR = Keys.keyPairFor(Version.V1);
@POST
@Produces(MediaType.TEXT_PLAIN)
public String verifyToken(String token) {
PasetoParser parser = Pasetos.parserBuilder()
.setSharedSecret(SHARED_SECRET)
.setPublicKey(KEY_PAIR.getPublic())
.requireAudience("blog")
.requireIssuer("https://ezto.io/")
.build();
Paseto result = parser.parse(token);
return result.getClaims().getIssuer();
}
}
PasetoParser is built using the Pasetos.parserBuilder() method. The parser is configured with:
You can make a post request with the token to this API to verify your PASETO.
While PASETO (Platform-Agnostic Security Tokens) offers several improvements over JWT (JSON Web Tokens), it also has its own set of limitations. Here are some key limitations to consider:
Both JWT and PASETO have their own advantages and disadvantages. As new authentication methods continue to emerge, developers will have more alternatives to explore. It is important for us to stay informed about these options and carefully evaluate which method best suits our application's needs. By understanding the strengths and weaknesses of JWT and PASETO, we can make more informed decisions to enhance the security and efficiency of our applications.