JWS with unencoded payload (RFC 7797)

Nimbus JOSE+JWT v8.15 introduced clean support for applying a JSON Web Signature (JWS) to an unencoded and optionally detached payload, according to the RFC 7797 specification. This can be useful when signing data which original encoding or presentation must be preserved, such as human readable text or a data in some web API or protocol (regular JWS requires the payload to be Base64URL-encoded). Keeping the payload unencoded can also save bandwidth and memory when dealing with large pieces of data.

Example Java code for a unencoded detached JWS payload:

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

// Some HMAC key for JWS with HS256
OctetSequenceKey hmacJWK = OctetSequenceKey.parse("{"+
    "\"kty\":\"oct\"," +
    "\"k\":\"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow\"" +
    "}");

// The payload which will not be encoded and must be passed to
// the JWS consumer in a detached manner
Payload detachedPayload = new Payload("Hello, world!");

// Create and sign JWS
JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.HS256)
    .base64URLEncodePayload(false)
    .criticalParams(Collections.singleton("b64"))
    .build();

JWSObject jwsObject = new JWSObject(header, detachedPayload);
jwsObject.sign(new MACSigner(hmacJWK));

boolean isDetached = true;
String jws = jwsObject.serialize(isDetached);

// The resulting JWS, note the payload is not encoded (empty second part)
// eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJIUzI1NiJ9..
// 5rPBT_XW-x7mjc1ubf4WwW1iV2YJyc4CCFxORIEaAEk

// Parse JWS with detached payload
JWSObject parsedJWSObject = JWSObject.parse(jws, detachedPayload);

// Verify the HMAC
if (parsedJWSObject.verify(new MACVerifier(hmacJWK))) {
    System.out.println("Valid HMAC");
} else {
    System.out.println("Invalid HMAC");
}

To not detach the unencoded payload, i.e. keep it within the serialised JWS:

boolean isDetached = false;
String jws = jwsObject.serialize(isDetached);

// The resulting JWS (with line breaks for clarity)
// eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJIUzI1NiJ9.
// Hello, world!.
// 5rPBT_XW-x7mjc1ubf4WwW1iV2YJyc4CCFxORIEaAEk

Note that to parse this JWS the payload must be presented as detached, otherwise the parse method will throw a ParseException. In future we may add support for parsing inlined unencoded payloads.

JWSObject.parse(
    "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJIUzI1NiJ9..5rPBT_XW-x7mjc1ubf4WwW1iV2YJyc4CCFxORIEaAEk",
    new Payload("Hello, world!")
);

The unencoded JWS payload option also works with RSA, EC and EdDSA signatures.