JSON Web Token (JWT) with HMAC protection

JSON Web Tokens (JWT) can be integrity protected with a hash-based message authentication code (HMAC). The producer and consumer must posses a shared secret, negotiated through some out-of-band mechanism before the JWS-protected object is communicated (unless the producer secures the JWS object for itself).

The Nimbus JOSE+JWT library supports all standard JWS algorithms for HMAC protection (note the minimum secret length requirement):

  • HS256 - HMAC with SHA-256, requires 256+ bit secret
  • HS384 - HMAC with SHA-384, requires 384+ bit secret
  • HS512 - HMAC with SHA-512, requires 512+ bit secret

The JWT includes a set of claims or assertions, packaged in a JSON object. Note that the SignedJWT.verify method only checks the validity of the HMAC. The claims, which treatment is application specific, must therefore be subsequently checked by your application code.

Example code:

import java.security.SecureRandom;
import java.util.Date;

import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.*;
import com.nimbusds.jwt.*;

// Generate random 256-bit (32-byte) shared secret
SecureRandom random = new SecureRandom();
byte[] sharedSecret = new byte[32];

// Create HMAC signer
JWSSigner signer = new MACSigner(sharedSecret);

// Prepare JWT with claims set
JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
    .expirationTime(new Date(new Date().getTime() + 60 * 1000))

SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claimsSet);

// Apply the HMAC protection

// Serialize to compact form, produces something like
// eyJhbGciOiJIUzI1NiJ9.SGVsbG8sIHdvcmxkIQ.onO9Ihudz3WkiauDO2Uhyuz0Y18UASXlSc1eS0NkWyA
String s = signedJWT.serialize();

// On the consumer side, parse the JWS and verify its HMAC
signedJWT = SignedJWT.parse(s);

JWSVerifier verifier = new MACVerifier(sharedSecret);


// Retrieve / verify the JWT claims according to the app requirements
assertEquals("alice", signedJWT.getJWTClaimsSet().getSubject());
assertEquals("https://c2id.com", signedJWT.getJWTClaimsSet().getIssuer());
assertTrue(new Date().before(signedJWT.getJWTClaimsSet().getExpirationTime()));