Yet another JWT library (pac4j-jwt) for Java
pac4j is a security engine for Java which supports authentication/authorization and is available for many frameworks: JEE, Play, Vertx, Spring Security, Shiro and Ratpack to name only a few.
Regarding authentication, one very common use case is to have a user authenticating via a browser (Facebook login for example) and then turn his identity into something usable for calling web services. This could be an opaque string, but it requires checking the value to get the identity user. So the best solution would be some self-sufficient information.
It is here that JWT comes into play: a JSON Web Token is a JSON object which can be signed and/or encrypted and is encoded in base64 format. It’s an industry standard. Signature is used to ensure that the JWT has not been tampered. Encryption is used to hide the information held by the JWT.
A JWT consists of three parts: a header, a payload and a signature. Here is an example taken from the jwt.io website.
is decoded as:
"name": "John Doe",
|To be verified|
For Java, there are several good JWT libraries, but I think the best one is the Nimbus JOSE JWT: it may not be the easiest one, but it really has everything you need for JWT support. You should especially read their algorithm selection guide.
Let’s take an example with HMAC signature:
JWTClaimsSet claimsSet = new JWTClaimsSet(); claimsSet.setSubject("alice"); claimsSet.setIssuer("https://c2id.com"); JWSSigner signer = new MACSigner(KEY1); SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claimsSet); signedJWT.sign(signer); String jwt = signedJWT.serialize(); signedJWT = SignedJWT.parse(jwt); JWSVerifier verifier = new MACVerifier(sharedSecret); assertTrue(signedJWT.verify(verifier)); assertEquals("alice", signedJWT.getJWTClaimsSet().getSubject()); assertEquals("https://c2id.com", signedJWT.getJWTClaimsSet().getIssuer());
It’s really not too complicated and all your use cases can be handled with a similar logic. Even if it provides low-level abstractions, it should be more than sufficient in most situations.
In pac4j security libraries, things are slightly different and authenticated users have profiles (with identifiers, attributes, roles and permissions).
So we must generate JWTs from these profiles (it’s done via the
JwtGenerator) and verify them during the authentication process (thanks to the
We can also verify JWT created in other applications without using the
JwtGenerator to address other use cases.
JwtAuthenticator are available in the
pac4j-jwt module (groupId:
As we want to be able to handle more than just one encryption/signature use case in the
JwtAuthenticator, we offer higher abstractions to configure signature and encryption: the
SignatureConfiguration and the
Inspired by the pac4j JWT documentation:
JwtGenerator<FacebookProfile> generator = new JwtGenerator<>(new SecretSignatureConfiguration(KEY1), new SecretEncryptionConfiguration(KEY1)); String token = generator.generate(facebookProfile); JwtAuthenticator jwtAuthenticator = new JwtAuthenticator(); jwtAuthenticator.addSignatureConfiguration(new SecretSignatureConfiguration(KEY1)); jwtAuthenticator.addSignatureConfiguration(new SecretSignatureConfiguration(KEY2)); jwtAuthenticator.addEncryptionConfiguration(new SecretEncryptionConfiguration(KEY1)); jwtAuthenticator.validate(new TokenCredentials(token, "FacebookClient"));
Finally, after adding the
String generate(Map claims) method to the
JwtGenerator and the
Map validateTokenAndGetClaims(String token) method to the
JwtAuthenticator, we don’t have any dependency left on the pac4j profile and you now have a full library for JWT.