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 D48B42009D9 for ; Thu, 19 May 2016 17:47:50 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id D327F160A00; Thu, 19 May 2016 15:47:50 +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 07EB21609AE for ; Thu, 19 May 2016 17:47:48 +0200 (CEST) Received: (qmail 55211 invoked by uid 500); 19 May 2016 15: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 55202 invoked by uid 99); 19 May 2016 15:47:47 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd4-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 19 May 2016 15:47:47 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd4-us-west.apache.org (ASF Mail Server at spamd4-us-west.apache.org) with ESMTP id 68D63C006B for ; Thu, 19 May 2016 15:47:47 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd4-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: 1.799 X-Spam-Level: * X-Spam-Status: No, score=1.799 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1, RP_MATCHES_RCVD=-0.001] autolearn=disabled Received: from mx1-lw-us.apache.org ([10.40.0.8]) by localhost (spamd4-us-west.apache.org [10.40.0.11]) (amavisd-new, port 10024) with ESMTP id PikIkZvQY5xI for ; Thu, 19 May 2016 15:47:40 +0000 (UTC) Received: from mailrelay1-us-west.apache.org (mailrelay1-us-west.apache.org [209.188.14.139]) by mx1-lw-us.apache.org (ASF Mail Server at mx1-lw-us.apache.org) with ESMTP id AA4415FB31 for ; Thu, 19 May 2016 15:47:39 +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 48381E0279 for ; Thu, 19 May 2016 15:47:38 +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 5E2CF3A00A5 for ; Thu, 19 May 2016 15:47:37 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r988634 - in /websites/production/cxf/content: cache/docs.pageCache docs/jax-rs-jose.html Date: Thu, 19 May 2016 15:47:36 -0000 To: commits@cxf.apache.org From: buildbot@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20160519154737.5E2CF3A00A5@svn01-us-west.apache.org> archived-at: Thu, 19 May 2016 15:47:51 -0000 Author: buildbot Date: Thu May 19 15:47:36 2016 New Revision: 988634 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 Thu May 19 15:47:36 2016 @@ -119,14 +119,14 @@ Apache CXF -- JAX-RS JOSE

 

 

+/*]]>*/

   

Does it make sense to use JWS JSON if you do not plan to do multiple signatures ? Indeed, if it is only a single signature then using JWS Compact is a good alternative, likely to be used most often.

However, even if you do a single signature, you may still want to try JWS JSON because is is easier to observe the individual JWS JSON structure parts when, example, checking the logs or TCP-tracing HTTP requests/responses. This is especially true when we start talking about a clear payload option, see below.

JWS with Detached Content

JWS with a Detached Content provides a way to integrity-protect some data without actually having these data included in the resulting JWS sequence.

For example, if the producer and consumer can both access the same shared piece of data, then th e producer can sign these data, post the JWS sequence (without the data) to the consumer. The consumer will validate this JWS sequence and assert the data have not been modified by the time it has received and started validating the sequence. You fill find JWS Compact and JWS JSON Producer and Consumer providers accepting an optional 'detached' flag in cases were it is required.      

JWS with Clear Payload

JWE Encryption

JWE (JSON Web Encryption) document describes how a document content, and, when applicable, a content encryption key, can be encrypted. For example, Appendix A1 shows how the content can be encrypted with a secret key using AesGcm with the actual content e ncryption key being encrypted using RSA-OAEP.

CXF ships JWE related classes in this package and offers a support for all of JWA key encryption and content encryption algorithms.

Key and Content Encryption Providers

JWE Encryption process typically involves a content-encryption key being generated with this key being subsequently encrypted/wrapped with a key known to the consumer. Thus CXF offers the providers for supporting the key-encryption algorithms and providers for supporting the content-encryption algorithms . Direct key encryption (where the content-encryption key is established out of band) is also supported.

KeyEncryptionProvider supports encrypting a content-encryption key, KeyDecryptionProvider - decrypting it.

The following table shows the key encryption algorithms and the corresponding providers (org.apache.cxf.rs.security.jose.jwe package):

AlgorithmJWE Header 'alg'KeyEncryptionProviderKeyDecryptionProvider
RSAES-PKCS1-v1_5

RSA1_5

RSAKeyEncryptionAlgorithm

RSAKeyDecryptionAlgorithm

RSAES OAEP

RSA-OAEP, RSA-OAEP-256

RSAKeyEncryptionAlgorithmRSAKeyDecryptionAlgorithm
AES Key Wrap

A128KW, A192KW, A256KW

AesKeyWrapEncryptionAlgorithmAesKeyWrapDecryptionAlgorithm
DirectdirDirectKeyEncryptionAlgorithmDirectKeyDecryptionAlgorithm
ECDH-ES Wrap

ECDH-ES+A128KW (+A192KW, +256KW)

EcdhAesWrapKeyEncryptionAlgorithmEcdhAesWrapKeyDecryptionAlgorithm
ECDH-ES Direct

ECDH-ES

EcdhDirectKeyJweEncryptionEcdhDirectKeyJweDecryption
AES-GCM

A128GCMKW, A192GCMKW, A256GCMKW

AesGcmWrapKeyEncryptionAlgorithmAesGcmWrapKeyDecryptionAlgorithm
PBES2

PBES2-HS256+A128KW

PBES2-HS384+A192KW

PBES2-HS512+A256KW

PbesHmacAesWrapKeyEncryptionAlgorithmPbesHmacAesWrapKeyDecryptionAlgorithm

 

RSA-OAEP algo rithms are likely to be used most often at the moment due to existing JKS stores being available everywhere and a relatively easy way of making the public validation keys available.

ContentEncryptionProvider supports encrypting a generated content-encryption key, ContentDecryptionProvider - decrypting it.

The following table shows the content encryption algorithms and the corresponding providers:

AlgorithmJWE Header 'enc'ContentEncryptionProviderContentDecryptionProvider
AES_CBC_HMAC_SHA2

A128CBC-HS256(-HS384, -HS512)

AesCbcHmacJweEncryption,

AesCbcHmacJweDecryption

AES-GCM

A128GCM, A92GCM, A256GCM

AesGcmContentEncryptionAlgorithmAesGcmContentDecryptionAlgorithm

All of the above providers can be initialized with the keys loaded from JWK or Java JKS stores or from the in-memory representations.

JWE Compact

JweEncryptionProvider supports encrypting the content, JweDecrypti onProvider - decrypting the content. Encryptors and Decryptors for all of JWE algorithms are shipped.

Here is the example of doing AES CBC HMAC and AES Key Wrap in CXF:

CXF Jwe AesWrapAesCbcHMac
+

The above code produces a JWS JSON sequence containing two signatures, similarly to this example. If the sequence contains a single signature only then the JWS JSON 'signatures' array will contain a single 'signature' element, or the whole sequence can be flattened with the actual 'signatures' array dropped. JwsJsonProducer  does not produce the flattened sequence when only a single signature is used by default because 3rd party JWS JSON consumers may only be able to process the sequences with the 'signatures' array, so pass a 'supportFlattened' flag to JwsJsonProducer if needed. 

Does it make sense to use JWS JSON if you do not plan to do multiple signatures ? Indeed, if it is only a single signature then using JWS Compa ct is a good alternative, likely to be used most often.

However, even if you do a single signature, you may still want to try JWS JSON because is is easier to observe the individual JWS JSON structure parts when, example, checking the logs or TCP-tracing HTTP requests/responses. This is especially true when we start talking about an unencoded payload option, see below.

JWS with Detached Content

JWS with a Detached Content provides a way to integrity-protect some data without actually having these data included in the resulting JWS sequence.

For example, if the producer and consumer can both access the same shared piece of data, then the producer can sign these data, post the JWS sequence (without the data) to the consumer. The consumer will validate this JWS sequence and assert the data have not been modified by the time it has received and started validating the sequence. JWS Compact and JWS JSON Producer and Consumer provider constructors accept an optional 'detached' flag in cases were it is required.      

JWS with Unencoded Payload

By default, JWS Compact and JWS JSON sequences have the data first Base64Url encoded and then inlined in the resulting sequence. This is useful especially for JWS Compact which is used in OAuth2/OIDC  flows to represent the signed access or id tokens. 

One concern around the data being inlined is that it takes an extra time to Base64Url encode them which may become noticeable with large payloads, and another one is that one can not see the data while looking at JWS sequences in the logs or trace screens.

Thus a JWS with Unencoded Payload option (JWS header 'b64' prope rty set to false) has been introduced to let users configure JWS Signature providers not to encode the actual data payload. As it happens it appears to be most useful when JWS JSON sequences are produced, see this example.

Note that JWS Compact also supports 'b64' property but only with the detached payloads. It is easier to appreciate the value of disabling Base64Url encoding with JWS JSON as seen in the example.

In CXF you can apply this option to both JWS Compact and JWS JSON sequences, here is a JWS JSON code fragment:

 

JWS JSON Unencoded
+
JwsJsonProducer producer = new JwsJsonProducer(UNSIGNED_PLAIN_JSON_DOCUMENT, true);
+JwsHeaders headers = new JwsHeaders(SignatureAlgorithm.HS256);
+headers.setPayloadEncodingStatus(false);
+producer.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY_1, SignatureAlgorithm.HS256),
+                  headers);
+

 

JWE Encryption

JWE (JSON Web Encryption) document describes how a document content, and, when applicable, a content encryption key, can be encrypted. For example, Appendix A1 shows how the content can be encrypted with a secret key using AesGcm with the actual content encryption key being encrypted using RSA-OAEP.

CXF ships JWE related classes in this package and offers a support for all of JWA key encryption a nd content encryption algorithms.

Key and Content Encryption Providers

JWE Encryption process typically involves a content-encryption key being generated with this key being subsequently encrypted/wrapped with a key known to the consumer. Thus CXF offers the providers for supporting the key-encryption algorithms and providers for supporting the content-encryption algorithms. Direct key encryption (where the content-encryption key is established out of band) is also supported.

KeyEncryptionProvider supports encrypting a content-encryption key, KeyDecryptionProvider - decrypting it.

The following table shows the key encryption algorithms and the corresponding providers (org.apache.cxf.rs.security.jose.jwe package):

AlgorithmJWE Header 'alg'KeyEncryptionProviderKeyDecryptionProvider
RSAES-PKCS1-v1_5

RSA1_5

RSAKeyEncryptionAlgorithm

RSAKeyDecryptionAlgorithm

RSAES OAEP

RSA-OAEP, RSA-OAEP-256

RSAKeyEncryptionAlgorithmRSAKeyDecryptionAlgorithm
AES Key Wrap

A128KW, A192KW, A256KW

AesKeyWrapEncryptionAlgorithmAesKeyWrapDecryptionAlgorithm
DirectdirDirectKeyEncryptionAlgorithmDirectKeyDecryptionAlgorithm
ECDH-ES Wrap

ECDH-ES+A128KW (+A192KW, +256KW)

EcdhAesWrapKeyEncryptionAlgorithmEcdhAesWrapKeyDecryptionAlgorith m
ECDH-ES Direct

ECDH-ES

EcdhDirectKeyJweEncryptionEcdhDirectKeyJweDecryption
AES-GCM

A128GCMKW, A192GCMKW, A256GCMKW

AesGcmWrapKeyEncryptionAlgorithmAesGcmWrapKeyDecryptionAlgorithm
PBES2

PBES2-HS256+A128KW

PBES2-HS384+A192KW

PBES2-HS512+A256KW

PbesHmacAesWrapKeyEncryptionAlgorithmPbesHmacAesWrapKeyDecryptionAlgorithm

 

RSA-OAEP algorithms are likely to be used most often at the moment due to existing JKS stores being available everywhere and a relatively easy way of making the public validation keys available.

ContentEncryptionProvider supports encryp ting a generated content-encryption key, ContentDecryptionProvider - decrypting it.

The following table shows the content encryption algorithms and the corresponding providers:

AlgorithmJWE Header 'enc'ContentEncryptionProviderContentDecryptionProvider
A ES_CBC_HMAC_SHA2

A128CBC-HS256(-HS384, -HS512)

AesCbcHmacJweEncryption,

AesCbcHmacJweDecryption

AES-GCM

A128GCM, A92GCM, A256GCM

AesGcmContentEncryptionAlgorithmAesGcmContentDecryptionAlgorithm

All of the above providers can be initialized with the keys loaded from JWK or Java JKS stores or from the in-memory representations.

JWE Compact

JweEncryptionProvider supports encrypting the content, JweDecryptionProvider - decrypting the content. Encryptors and Decryptors for all of JWE algorithms are shipped.

Here is the example of doing AES CBC HMAC and AES Key Wrap in CXF:

CXF Jwe AesWrapAesCbcHMac
final String specPlainText = "Live long and prosper.";
         
 byte[] cekEncryptionKey = Base64UrlUtility.decode(KEY_ENCRYPTION_KEY_A3);
@@ -272,7 +278,7 @@ AesWrapKeyDecryptionAlgorithm keyDecrypt
 JweDecryptionProvider decryption = new AesCbcHmacJweDecryption(keyDecryption);
 String decryptedText = decryption.decrypt(jweContent).getContentText();
 assertEquals(specPlainText, decryptedText);
-

 

JWE JSON

JSON Web Token

JWT (JSON Web Token) is a collection of claims in JSON format. It offers a standard JSON container for representing various properties or claims.

JWT can be signed and or encrypted, i.e, serve as a JOSE signature or encryption input like any other data structure.

JWT has been primarily used in OAuth2 applications to represent self-contained access tokens but can also be used in other contexts.

CXF offers an initial JWT support in this package.

JOSE JAX-RS Filters

JWS

J WE

Linking JWT authentications to JWS or JWE content

 

Configuration

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.passwordTh e 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.out.properties

The signature properties file for compact 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 signature verification. If not specified then it falls back to "rs.security.signature.properties".

rs.security.signature.propertiesThe signature properties file for compact signature creation/verification.
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.ke y.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.out.properties

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

rs.security.encryption.in.properties

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

rs.security.encryption.propertiesThe signature properties file for encryption/decryption.
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.

 

OAuth2 and Jose

CXF OAuth2 module depends on its JOSE module. This will be used to support OAuth 2 POP tokens. Authorization code JOSE requests can already be processed. Utility support for validating JWT-based access tokens is provided.

Add more...

OIDC and Jose

OIDC heavily depends on JOSE. CXF OIDC module utilizes a JOSE module to support OIDC RP and IDP code. Add more...

Future Work

OAuth2, WebCrypto, OIDC, etc

Third-Party Alternatives

Jose4J is a top project from Brian Campbell.  CXF users are encouraged to experiment with Jose4J (or indeed with other 3rd party implementations) if they prefer.

TODO: describe how Jose4J can be integrated with CXF filters if preferred.

 

+

 

JWE JSON

JSON Web Token

JWT (JSON Web Token) is a collection of claims in JSON format. It offers a standard JSON container for representing various properties or claims.

JWT can be signed and or encrypted, i.e, serve as a JOSE signature or encryption input like any other data structure.

JWT has been primarily used in OAuth2 applications to represent self-contained access tokens but can also be used in other contexts.

CXF offers an initial JWT support in this package.

JOSE JAX-RS Filters

JWS

J WE

Linking JWT authentications to JWS or JWE content

 

Configuration

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.passwordTh e 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.out.properties

The signature properties file for compact 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 signature verification. If not specified then it falls back to "rs.security.signature.properties".

rs.security.signature.propertiesThe signature properties file for compact signature creation/verification.
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.ke y.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.out.properties

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

rs.security.encryption.in.properties

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

rs.security.encryption.propertiesThe signature properties file for encryption/decryption.
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.

 

OAuth2 and Jose

CXF OAuth2 module depends on its JOSE module. This will be used to support OAuth 2 POP tokens. Authorization code JOSE requests can already be processed. Utility support for validating JWT-based access tokens is provided.

Add more...

OIDC and Jose

OIDC heavily depends on JOSE. CXF OIDC module utilizes a JOSE module to support OIDC RP and IDP code. Add more...

Future Work

OAuth2, WebCrypto, OIDC, etc

Third-Party Alternatives

Jose4J

Nimbus JOSE