Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id BEF6B2009F9 for ; Mon, 23 May 2016 14:47:49 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id BD6DE1609A8; Mon, 23 May 2016 12:47:49 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id EAC951602C5 for ; Mon, 23 May 2016 14:47:47 +0200 (CEST) Received: (qmail 13265 invoked by uid 500); 23 May 2016 12:47:47 -0000 Mailing-List: contact commits-help@cxf.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cxf.apache.org Delivered-To: mailing list commits@cxf.apache.org Received: (qmail 13255 invoked by uid 99); 23 May 2016 12:47:47 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd1-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 23 May 2016 12:47:47 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd1-us-west.apache.org (ASF Mail Server at spamd1-us-west.apache.org) with ESMTP id AA769CB370 for ; Mon, 23 May 2016 12:47:46 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd1-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: 0.374 X-Spam-Level: X-Spam-Status: No, score=0.374 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1, RP_MATCHES_RCVD=-1.426] autolearn=disabled Received: from mx2-lw-us.apache.org ([10.40.0.8]) by localhost (spamd1-us-west.apache.org [10.40.0.7]) (amavisd-new, port 10024) with ESMTP id mGHENKBHVhfw for ; Mon, 23 May 2016 12:47:41 +0000 (UTC) Received: from mailrelay1-us-west.apache.org (mailrelay1-us-west.apache.org [209.188.14.139]) by mx2-lw-us.apache.org (ASF Mail Server at mx2-lw-us.apache.org) with ESMTP id E890B5FB77 for ; Mon, 23 May 2016 12:47:40 +0000 (UTC) Received: from svn01-us-west.apache.org (svn.apache.org [10.41.0.6]) by mailrelay1-us-west.apache.org (ASF Mail Server at mailrelay1-us-west.apache.org) with ESMTP id 36C95E009C for ; Mon, 23 May 2016 12:47:40 +0000 (UTC) Received: from svn01-us-west.apache.org (localhost [127.0.0.1]) by svn01-us-west.apache.org (ASF Mail Server at svn01-us-west.apache.org) with ESMTP id 52A6E3A01A9 for ; Mon, 23 May 2016 12:47:39 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r988946 - in /websites/production/cxf/content: cache/docs.pageCache docs/jax-rs-jose.html Date: Mon, 23 May 2016 12:47:38 -0000 To: commits@cxf.apache.org From: buildbot@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20160523124739.52A6E3A01A9@svn01-us-west.apache.org> archived-at: Mon, 23 May 2016 12:47:49 -0000 Author: buildbot Date: Mon May 23 12:47:38 2016 New Revision: 988946 Log: Production update by buildbot for cxf Modified: websites/production/cxf/content/cache/docs.pageCache websites/production/cxf/content/docs/jax-rs-jose.html Modified: websites/production/cxf/content/cache/docs.pageCache ============================================================================== Binary files - no diff available. Modified: websites/production/cxf/content/docs/jax-rs-jose.html ============================================================================== --- websites/production/cxf/content/docs/jax-rs-jose.html (original) +++ websites/production/cxf/content/docs/jax-rs-jose.html Mon May 23 12:47:38 2016 @@ -119,11 +119,11 @@ Apache CXF -- JAX-RS JOSE

 

 

+/*]]>*/

Introduction

JOSE is a set of high quality specifications that specify how data payloads can be signed/validated and/or encrypted/decrypted with the cryptographic properties set in the JSON-formatted metadata (headers). The data to be secured can be in JSON or other format (plain text, XML, binary data).

JOSE is a key piece of the advanced OAuth2-based applications such as OpenIdConnect but can also be successfully used for securing the regular HTTP web service communications.

CXF 3.1.x and 3.2.0 provides a complete implementation of JOSE.

Maven Dependencies

 

Having the following dependency will let the developers write JOSE code: creating and securing JSON Web Tokens (JWT), and securing the arbitrary data (not only JSON)

<dependency>
@@ -354,7 +352,30 @@ JweJsonConsumer c = new JweJsonConsumer(
 String content = consumer.decryptWith(jweDecrypt).getContent();
 
 
-

If the sequence contains a single recipient entry only then the JWE JSON 'recipients' array will contain a single entry, or the whole sequence can be flattened instead with the actual 'recipients' array dropped. JweJsonProducer  does not produce the flattened sequence when only a single encryption is done by default because 3rd party JWE JSON consumers may only be able to process the sequences with the 'recipients' array, so pass a 'canBeFlat' flag to JwEJsonProducer if needed

Does it make sense to use JWE JSON if you do not plan to do multiple encryptions ? Most likely you will prefer JWE Compact if only a single recipient is targeted.

JSON Web Token

JWT (JSON Web Token) is a collection of claims in JSON format. It is simply a regular JSON document where each top elevel property is called a 'claim'.

JWT can be JWS signed and/or JWE encrypted like any other data structure.

JWT is mainly used in OAuth2 and OIDC applications to represent self-contained OAuth2 access tokens, OIDC IdToken, UserInfo, but can also be used in other contexts. For example, see the section below on linking JWT authentication tokens to JWS or JWE secured payloads.

CXF offers a JWT support in this package. Typically one would create a set of claims and submit them to JWS/JWE JWT processors, for example, see a JWS section above.

JWS and JWE Combined

If you have a requirement to sign the data and then encrypt the signed payload then it can be easily achieved by sel ecting a required JWS Producer and creating a JWS Compact sequence, and next submitting this sequence to a JWE producer, and processing it all in the reverse sequence

JOSE JAX-RS Filters

JWS

JWE

Linking JWT authentications to JWS or JWE content

 

Configuration

CXF JOSE configuration provides for loading JWS and JWE keys and supporting various processing options. Configuration properties can be shared between JWS and JWE processors or in/out only JWS and or JWE properties can be set.

Typically a secure JAX-RS endpoint or client is initialized with JWS and or JWE properties.

For example, this endpoint is configured with a single JWS properties file which will apply to both input (signature verification) and output (signature creation) JWS operations. This endpoint depends on two JWS properties files, one - for input JWS, another one - for output JWS. Similarly, this endpoint uses a single JWE properties file for encrypting/decrypting the data, while this endpoint uses two JWE properties files. This endpoint support both JWS and JSON with in/out specific properties. If either JWS or JWE private key needs to be loaded from the password-protected storage (JKS, encryped JWK)  then a password provider needs be registered as well, it can be shared between JWS or JWS or be in/out specific for either JWS or JWE.

These configuration propertie are of major help when JAX-RS JOSE filters process the in/out payload without the application service code being aware of it. While filters can be injected with JWS or JWE providers directly, one would usually set the relevant properties as part of the endpoint or client set-up and expect the filters load the required JWS or JWE providers as needed. 

If you need to do JWS or JWE processing directly in your service or interceptor code then having the properties may also be helpful, for example, the following code works because it is indirectly supported by the properties indicating which signature or encryption algorithm is used, where to get the key if needed, etc:

Loading JWS and JWE Providers
+

If the sequence contains a single recipient entry only then the JWE JSON 'recipients' array will contain a single entry, or the whole sequence can be flattened instead with the actual 'recipients' array dropped. JweJsonProducer  does not produce the flattened sequence when only a single encryption is done by default because 3rd party JWE JSON consumers may only be able to process the sequences with the 'recipients' array, so pass a 'canBeFlat' flag to JwEJsonProducer if needed

Does it make sense to use JWE JSON if you do not plan to do multiple encryptions ? Most likely you will prefer JWE Compact if only a single recipient is targeted.

JSON Web Token

JWT (JSON Web Token) is a collection of claims in JSON format. It is simply a regular JSON document where each top elevel property is called a 'claim'.

JWT can be JWS signed and/or JWE encrypted like any other data structure.

JWT is mainly used in OAuth2 and OIDC applications to represent self-contained OAuth2 access tokens, OIDC IdToken, UserInfo, but can also be used in other contexts. For example, see the section below on linking JWT authentication tokens to JWS or JWE secured payloads.

CXF offers a JWT support in this package. Typically one would create a set of claims and submit them to JWS/JWE JWT processors, for example, see a JWS section above.

JWS and JWE Combined

If you have a requirement to sign the data and then encrypt the signed payload then it can be easily achieved by sel ecting a required JWS Producer and creating a JWS Compact sequence, and next submitting this sequence to a JWE producer, and processing it all in the reverse sequence

JOSE JAX-RS Filters

 

While working directly with JWS and JWE providers may be needed in the application code, JAX-RS users writing the code like this:

Typical JAX-RS code
+
@Path("/bookstore")
+public class BookStore {
+    
+    public BookStore() {
+    }
+    
+    @POST
+    @Path("/books")
+    @Produces("text/plain")
+    @Consumes("text/plain")
+    public String echoText(String text) {
+        return text;
+    }
+    
+    @POST
+    @Path("/books")
+    @Produces("application/json")
+    @Consumes("application/json")
+    public Book echoBook(Book book) {
+        return book;
+    }
+}
+

would expect JWS and/or JWE processing done before the resource method is invoked or after this method returned some response.

This is what CXF JOSE JAX-RS filters do, they help the client or server code get the application data JWS- or JWE-secured. The filters do it by loadng the configuration properties as described below in the Configuration section, and produce or consume JWS or JWE sequences.

Note, JWS Compact and JSON, as well as JWE Compact client and server output filters do the best effort at keeping the streaming process going while they are signing or encrypting the payload. JWE JSON client/server output filter and JWS Compact client/server input filters will be enhanced in due time to support the streaming too. Most of CXF JOSE system tests enable the streaming capable filters to stream by default, however this can be disabled.  

JWS and JWE JSON input filters are expected to process JSON containers with the properti es set in a random order hence by default they wil not stream the data in.  

Register both JWS and JWE out filters if the data need to be signed and encrypted (the filters are ordered such that the data are signed first and encrypted next) and JWS and JWE in filters if the signed data need to be decrypted first and then verified.

JWS Compact

JwsWriterInterceptor creates compact JWS sequences on the client or server out directions. For example, if you have the client code posting a Book or the server code returning a Book, with this Book representation expected to be signed, then add JwsWriterInterceptor and set the signature properties on the JAX-RS client or server.

JwsClientResponseFilter and JwsContainerRequestFilter process the incoming client or server Compact JWS sequences.

 

J wsJsonWriterInterceptor creates JWS JSON sequences on the client or server out directions. 

JwsJsonClientResponseFilter and JwsJsonContainerRequestFilter process the incoming client or server Compact JWS sequences.

JWE

JweWriterInterceptor creates Compact JWE sequen ces on the client or server out directions. For example, if you have the client code posting a Book or the server code returning a Book, with this Book representation expected to be encrypted, then add JweWriterInterceptor and set the encryption properties on the JAX-RS client or server.

JweClientResponseFilter and JweContainerRequestFilter process the incoming client or server Compact JWE sequences.

 

JweJsonWriterInterceptor creates JWE JSON sequences on the client or server out directions. 

JweJsonClientResponseFilter and JweContainerRequestFilter process the incoming client or server JWE JSON sequences.

 

Linking JWT authentications to JWS or JWE content

CXF introduced a "JWT" HTTP authentication scheme, with a Base64Url encoded JWT token representing a user authentication against an IDP capable of issuing JWT assertions (or simply JWT tokens). JWT assertion is like SAML assertion except that it is in a JSON format. If you'd like to cryptographically bind this JWT token to a data secured by JWS and/or JWE processors then simply add JwtAuthenticationClientFilteron the client side and JwtAuthenticationFilter on the server side. These filters link the authentication token with a randomly generated secure value which is added to both the token and the body JWS/JWE protected headers.

This approach is more effective compared to the ones where the body hash is calculated before it is submitted to a signature creation function, with the signature added as HTTP header.

 

 

Configuration

CXF JOSE configuration provides for loading JWS and JWE keys and supporting various processing options. Configuration properties can be shared between JWS and JWE processors or in/out only JWS and or JWE properties can be set.

Typically a secure JAX-RS endpoint or client is initialized with JWS and or JWE properties.

For example, this endpoint is configured with a single JWS properties file which will apply to both input (signature verification) and output (signature creation) JWS operations. This endpoint depends on two JWS properties files, one - for input JWS, another one - for output JWS. Similarly, this endpoint uses a single JWE properties file for encrypting/decrypting the data, while this endpoint uses two JWE properties files. This endpoint support both JWS and JSON with in/out specific properties. If either JWS or JWE private key needs to be loaded from the password-protected storage (JKS, encryped JWK)  then a password provider needs be registered as well, it can be shared between JWS or JWS or be in/out specific for either JWS or JWE.

These configuration propertie are of major help when JAX-RS JOSE filters process the in/out payload without the application service code being aware of it. While filters can be injected with JWS or JWE providers directly, one would usually set the relevant properties as part of the endpoint or client set-up and expect the filters load the required JWS or JWE providers as needed. 

If you need to do JWS or JWE processing directly in your service or interceptor code then having the properties may also be helpful, for example, the following code works because it is indirectly supported by the properties indicating which signature or encryption algorithm is used, where to get the key if needed, etc:

Loading JWS and JWE Providers
JwsSignatureProvider jwsOut = JwsUtils.loadSignatureProvider(true);
 JwsSignatureVerifier jwsIn = JwsUtils.loadSignatureVerifier(true);
 
@@ -363,7 +384,7 @@ JweDecryptionProvider jweIn = JweUtils.l
 

The providers may be initialized from a single properties file or each of them may have specific properties allocated to it.

Sometimes it can be useful to load the properties only and check the signature or encryption algorithm and load a JWS or JWE provider directly as shown in JWS and JWE sections above.

Loading JWS and JWE properties
Properties jwsProps = JweUtils.loadEncryptionProperties("jws.properties", true);
 Properties jweProps = JweUtils.loadEncryptionProperties("jwe.properties", true);
-

After loading the properties one can check various property values (signature algorithm, etc) and use it to create a required provider.

The above code needs to be executed in the context of the current request (in server or client in/out interceptors or server service code) as it expects the current CXF Message be available in order to deduce where to load the configuration properties from. However JwsUtils and JweUtils provide a number of utility methods for loading the providers without loading the properties first which can be used when setting up the c lient code or when no properties are available in the current request context.

 

When the code needs to load the configuration properties it first looks for the property 'container' file which contains the specific properties instructing which keys and algorithms need to be used. Singature or encryption properties for in/out operations can be provided.  

Configuration Property Containers

Signature

rs.security.signature.out.properties

The signature properties file for Compact or JSON signature creation. If not specified then it falls back to "rs.security.signature.properties".

rs.security.signature.in.properties

The signature properties file for Compact or JSON signature verification. If not specified then it falls back to "rs.security.signature.properties".

rs.security.signature.propertiesThe signature properties file for Compact or JSON signature creation/verification.

Encryption

rs.security.encryption.out.properties

The encryption properties file for Compact or JSON encryption creation. If not specified then it falls back to "rs.security.encryption.properties".

rs.security.encryption.in.properties

The encryption properties file for Compact or JSON decryption. If not specified then it falls back to "rs.security.encryption.properties".

rs.security.encryption.propertiesThe signature properties file for encryption/decryption.

 

Once the properties are loaded the runtime proceeds with initializing JWS/JWE providers accordingly. The following section lists the properties, some oif them being common and some - unique to the signature/verification and encryption/decryption processes.

Note that one can override some of the properties, for example, 'rs.security.store' can be set as a dynamic request property pointing to a preloaded Java KeyStore object.

Configuration that applies to both encryption and signature

rs.security.keystoreThe Java KeyStore Object to use. This configuration tag is used if you want to pass the KeyStore Object through dynamically.

rs.security.keystore.type

The keystore type. Suitable values are "jks" or "jwk".

rs.security.keystore.passwordThe password required to access the keystore.
rs.security.keystore.alias The keystore alias corresponding to the key to use. You can append one of the following to this tag to get the alias for more specific operations:
     - jwe.out
     - jwe.in
     - jws.out
     - jws.in
rs.security.keystore.aliasesThe keystore aliases corresponding to the keys to use, when using the JSON serialization form. You can append one of the following to this tag to get the alias for more specific operations:
     - jws.out
     - jws.in
rs.security.keystore.fileThe path to the keystore file.
rs.security.key.passwordThe password required to access the private key (in the keystore).
rs.security.key.password.providerA reference to a PrivateKeyPasswordProvider instance used to retrieve passwords to access keys.
rs.security.accept.public.key

Whether to allow using a JWK received in the header for signature validation. The default is "false".

Configuration that applies to signature only

rs.security.signature.key.password.provider

A reference to a PrivateKeyPasswordProvider instance used to retrieve passwords to access keys for signature. If this is not specified it falls back to use "rs.security.key.password.provider".

rs.security.signature.algorithmThe signature algorithm to use. The default algorithm if not specified is 'RS256'.
rs.security.signature.include.public.keyInclude the JWK public key for signature in the "jwk" header.
rs.security.signature.include.certInclude the X.509 certificate for signature in the "x5c" header.
rs.security.signature.include.key.idInclude the JWK key id for signature in the "kid" header.
rs.security.signature.include.cert.sha1Include the X.509 certificate SHA-1 digest for signature in the "x5t" header.

Configuration that applies to encryption only

rs.security.decryption.key.password.provider

A reference to a PrivateKeyPasswordProvider instance used to retrieve passwords to access keys for decryption. If this is not specified it falls back to use "rs.security.key.password.provider".

rs.security.encryption.content.algorithmThe encryption content algorithm to use. The default algorithm if not specified is 'A128GCM'.
rs.security.encryption.key.algorithm

The encryption key algorithm to use. The default algorithm if not specified is 'RSA-OAEP' if the key is an RSA key, and 'A128GCMKW' if it is an octet sequence.

rs.security.encryption.zip.algorithmThe encryption zip algorithm to use.
rs.security.encryption.include.public.keyInclude the JWK public key for encryption in the "jwk" header.
rs.security.encryption.include.certInclude the X.509 certificate for encryption in the "x5c" header.
rs.security.encryption.include.key.idInclude the JWK key id for encryption in the "kid" header.
rs.security.encryption.include.cert.sha1Include the X.509 certificate SHA-1 digest for encryption in the "x5t" header.

Configuration that applies to JWT tokens only

rs.security.enable.unsigned-jwt.principal

Whether to allow unsigned JWT tokens as SecurityContext Principals. The default is false.

Interoperability

 

Third-Party Libraries

Jose4J

Nimbus JOSE

 

 

 

+

After loading the properties one can check various property values (signature algorithm, etc) and use it to create a required provider.

The above code needs to be executed in the context of the current request (in server or client in/out interceptors or server service code) as it expects the current CXF Message be available in order to deduce where to load the configuration properties from. However JwsUtils and JweUtils provide a number of utility methods for loading the providers without loading the properties first which can be used when setting up the c lient code or when no properties are available in the current request context.

 

When the code needs to load the configuration properties it first looks for the property 'container' file which contains the specific properties instructing which keys and algorithms need to be used. Singature or encryption properties for in/out operations can be provided.  

Configuration Property Containers

Signature

rs.security.signature.out.properties

The signature properties file for Compact or JSON signature creation. If not specified then it falls back to "rs.security.signature.properties".

rs.security.signature.in.properties

The signature properties file for Compact or JSON signature verification. If not specified then it falls back to "rs.security.signature.properties".

rs.security.signature.propertiesThe signature properties file for Compact or JSON signature creation/verification.

Encryption

rs.security.encryption.out.properties

The encryption properties file for Compact or JSON encryption creation. If not specified then it falls back to "rs.security.encryption.properties".

rs.security.encryption.in.properties

The encryption properties file for Compact or JSON decryption. If not specified then it falls back to "rs.security.encryption.properties".

rs.security.encryption.propertiesThe signature properties file for encryption/decryption.

Note that these property containers can be used for creating/processing JWS and JWE Compact and JSON sequences. If it is either JWS JSON or JWE JSON and you wish to have more than one signature or encryption be created then let the property value be a commas separated list of locations, with each location pointing to a unique signature or encryption operation property file.

Once the properties are loaded the runtime proceeds with initializing JWS/JWE providers accordingly. The following section lists the properties, some oif them being common and some - unique to the signature/verification a nd encryption/decryption processes.

Note that one can override some of the properties, for example, 'rs.security.store' can be set as a dynamic request property pointing to a preloaded Java KeyStore object.

Configuration that applies to both encryption and signature

rs.security.keystoreThe Java KeyStore Object to use. This configuration tag is used if you want to pass the KeyStore Object through dynamically.

rs.security.keystore.type

The keystore type. Suitable values are "jks" or "jwk".

rs.security.keystore.passwordThe password required to access the keystore.
rs.security.keystore.alias The keystore alias corresponding to the key to use. You can append one of the following to this tag to get the alias for more specific operations:
     - jwe.out
     - jwe.in
     - jws.out
     - jws.in
rs.security.keystore.aliasesThe keystore aliases corresponding to the keys to use, when using the JSON serialization form. You can append one of the following to this tag to get the alias for more specific operations:
     - jws.out
     - j ws.in
rs.security.keystore.fileThe path to the keystore file.
rs.security.key.passwordThe password required to access the private key (in the keystore).
rs.security.key.password.providerA reference to a PrivateKeyPasswordProvider instance used to retrieve passwords to access keys.
rs.security.accept.public.key

Whether to allow using a JWK received in the header for signature validation. The default is "false".

Configuration that app lies to signature only

Include the X.509 certificate for signature in the "x5c" header.

rs.security.signature.key.password.provider

A reference to a PrivateKeyPasswordProvider instance used to retrieve passwords to access keys for signature. If this is not specified it falls back to use "rs.security.key.password.provider".

rs.security.signature.algorithmThe signature algorithm to use. The default algorithm if not specified is 'RS256'.
rs.security.signature.include.public.keyInclude the JWK public key for signature in the "jwk" header.
rs.security.signature.include.cert
rs.security.signature.include.key.idInclude the JWK key id for signature in the "kid" header.
rs.security.signature.include.cert.sha1Include the X.509 certificate SHA-1 digest for signature in the "x5t" header.

Configuration that applies to encryption only

rs.security.decryption.key.password.provider

A reference to a PrivateKeyPasswordProvider instance used to retrieve passwor ds to access keys for decryption. If this is not specified it falls back to use "rs.security.key.password.provider".

rs.security.encryption.content.algorithmThe encryption content algorithm to use. The default algorithm if not specified is 'A128GCM'.
rs.security.encryption.key.algorithm

The encryption key algorithm to use. The default algorithm if not specified is 'RSA-OAEP' if the key is an RSA key, and 'A128GCMKW' if it is an octet sequence.

rs.security.encryption.zip.algorithmThe encryption zip algorithm to use.
rs.security.encryption.include.public.keyInclude the JWK public key for encryption in the "jwk" header.
rs.security.encryption.include.certInclude the X.509 certificate for encryption in the "x5c" header.
rs.security.encryption.include.key.idInclude the JWK key id for encryption in the "kid" header.
rs.security.encryption.include.cert.sha1Include the X.509 certificate SHA-1 digest for encryption in the "x5t" header.

Configuration that applies to JWT tokens only

rs.security.enable.unsigned-jwt.principal

Whether to allow unsigned JWT tokens as SecurityContext Principals. The default is false.

Interoperability

 

JOSE is already widely supported in OAuth2 and OIDC applications. Besides that CXF JOSE client or server will interoperate with a 3rd party client/server able to produce or consume JWS/JWE sequences.  For example, see the following WebCrypto API use case, the following demo demonstrates how a JWS sequence produced b y a browser-hosted script can be validated by a server application capable of processing JWS, with the demo browser client being tested against a CXF JWS server too. 

 

Third-Party Libraries

Jose4J

Nimbus JOSE