PASETO is the latest trend in security token formats. Its primary goal is to reduce the problems the JSON Web Token (JWT) related specifications introduce. In this post, I’ll give you a brief introduction to PASETO tokens and then jump into an example that creates and parses tokens using in Java using JPaseto.
If you’d rather watch a video, I created a screencast too!
What is PASETO?
PASETO stands for Platform-Agnostic SEcurity TOkens. The PASETO RFC defines a format to encode a JSON object so you can securely transfer it between two parties. Sounds a lot like JWT? So much so, the tagline of the PASETO site is:
Paseto is everything you love about JOSE (JWT, JWE, JWS) without any of the many design deficits that plague the JOSE standards.
There has been a rash of vulnerabilities in JWT parsers; this has more to do with the JWT format than the implementations. The PASETO format aims to fix this by simplifying the format and reducing cryptographic options, simplifying implementations, and leaving developers with only the correct options.
The PASETO Format
There are two types (or "purposes") of PASETO tokens: local and public. Local tokens are encrypted with a shared key, whereas public tokens are signed with a public key pair, but NOT encrypted. In other words, anyone can read a public token, and only parties with the secret key can read local tokens.
The PASETO token format has two different versions:
v1is a compatibility mode, which is ideal for legacy systems and uses cryptographic primitives that are wildly available today.
v2is the recommended option, which uses the latest cryptographic primitives.
When you put this all together in a string, the format looks like this:
Or, with the optional footer:
For example, a
v1.local token looks like this:
JPaseto is a Java library modeled after the JJWT project. If you need to use JWTs, I’d strongly recommend JJWT. It’s intuitive and pluggable, and it goes to great lengths to protect you against the types of vulnerabilities JWT is known for.
I’ve put together a simple example to show you how to create and parse PASETO tokens using JPaseto. Grab it on GitHub:
git clone https://github.com/oktadeveloper/okta-jpaseto-example.git cd okta-jpaseto-example
Creating a PASETO Token
To keep things simple, I’m going to use
v1 tokens in this post. Creating and parsing
v2 tokens with JPaseto works the same way, but you would need an additional dependency: a native library "libsodium" See the project readme for more details.
|The requirement on libsodium will be removed from the library in the future when the cryptographic primitives become available as Java implementations.|
Take a look at the
createToken() method in
Instant now = Instant.now(); (1) String token = Pasetos.V1.LOCAL.builder() (2) .setSharedSecret(SHARED_SECRET) (3) .setIssuedAt(now) (4) .setExpiration(now.plus(1, ChronoUnit.HOURS)) (5) .setAudience("blog-post") (6) .setIssuer("https://developer.okta.com/blog/") (7) .claim("1d20", new Random().nextInt(20) +1) (8) .compact(); (9)
|1||Get the current date/time as an
|2||Set the secret key. I used
|3||Create a "builder" for the type of token you are creating (
|6||Set the Audience (
|7||Set the Issuer (
|8||Set a custom claim
|9||Serialize the token into a string|
Parsing a PASETO Token
Parsing tokens is just as easy. Let’s dig into the
PasetoParser parser = Pasetos.parserBuilder() (1) .setSharedSecret(SHARED_SECRET) (2) .build(); (3) Paseto result = parser.parse(token); (4)
|1||Create an instance of
|2||Use the same
|4||Finally, call the
You should reuse the instance of
To access the claims values inside the token, call the
getClaims() method (or
getFooter() to retrieve values stored in the optional token footer).
String audience = result.getClaims().getAudience(); (1) log("Audience: "+ audience); int rolledValue = result.getClaims().get("1d20", Integer.class); (2) log("1d20 rolled: " + rolledValue);
|1||Get the value for the Audience reserved claim|
|2||Get the value for the custom claim
Require Claims in the PASETO Token
JPaseto validates the "expiration" and "not before" attributes (or "claims") automatically for you. You can also validate other claims inside the token; for example, you may need to assert the "aud" (audience) claim has a specific value. See what this looks like in this example:
PasetoParser parser = Pasetos.parserBuilder() .setSharedSecret(SHARED_SECRET) .requireAudience("blog-post") .build();
Attempting to parse a PASETO token that does not meet these requirements will throw a
PasetoException, and you should NOT trust that token.
Learn more about PASETO and Java Security
This post has given you an introduction to the PASETO format and showed you how easy and intuitive the JPaseto library is to use. If you want to learn more about security tokens in Java, check out the posts below!