mirror of https://github.com/jwtk/jjwt.git
README cleanup based on latest API (#843)
This commit is contained in:
parent
854bb8944c
commit
36a6e1383b
73
README.md
73
README.md
|
@ -126,8 +126,7 @@ JJWT is open source under the terms of the [Apache 2.0 License](http://www.apach
|
||||||
* [JWK Security Considerations](#jwk-security)
|
* [JWK Security Considerations](#jwk-security)
|
||||||
* [JWK `toString()` Safety](#jwk-tostring)
|
* [JWK `toString()` Safety](#jwk-tostring)
|
||||||
* [Compression](#compression)
|
* [Compression](#compression)
|
||||||
* [Custom Compression Codec](#compression-custom)
|
* [Custom Compression Algorithm](#compression-custom)
|
||||||
* [Custom Compression Codec Locator](#compression-custom-locator)
|
|
||||||
* [JSON Processor](#json)
|
* [JSON Processor](#json)
|
||||||
* [Custom JSON Processor](#json-custom)
|
* [Custom JSON Processor](#json-custom)
|
||||||
* [Jackson ObjectMapper](#json-jackson)
|
* [Jackson ObjectMapper](#json-jackson)
|
||||||
|
@ -1425,7 +1424,7 @@ guarantee deterministic behavior.
|
||||||
### JWT Decompression
|
### JWT Decompression
|
||||||
|
|
||||||
If you used JJWT to compress a JWT and you used a custom compression algorithm, you will need to tell the
|
If you used JJWT to compress a JWT and you used a custom compression algorithm, you will need to tell the
|
||||||
`JwtParserBuilder` how to resolve your `CompressionCodec` to decompress the JWT.
|
`JwtParserBuilder` how to resolve your `CompressionAlgorithm` to decompress the JWT.
|
||||||
|
|
||||||
Please see the [Compression](#compression) section below to see how to decompress JWTs during parsing.
|
Please see the [Compression](#compression) section below to see how to decompress JWTs during parsing.
|
||||||
|
|
||||||
|
@ -1471,7 +1470,7 @@ key algorithms:
|
||||||
|
|
||||||
<sup><b>2</b>. Requires Java 15 or a compatible JCA Provider (like BouncyCastle) in the runtime classpath.</sup>
|
<sup><b>2</b>. Requires Java 15 or a compatible JCA Provider (like BouncyCastle) in the runtime classpath.</sup>
|
||||||
|
|
||||||
These are all represented as constants in the `io.jsonwebtoken.Jwts.SIG` convenience class.
|
These are all represented as constants in the `io.jsonwebtoken.Jwts.SIG` registry class.
|
||||||
|
|
||||||
<a name="jws-key"></a>
|
<a name="jws-key"></a>
|
||||||
### Signature Algorithms Keys
|
### Signature Algorithms Keys
|
||||||
|
@ -1600,9 +1599,12 @@ public key (`keyPair.getPublic()`) to parse/verify a JWS.
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
>
|
>
|
||||||
> **The `PS256`, `PS384`, and `PS512` algorithms require JDK 11 or a compatible JCA Provider
|
> * **The `PS256`, `PS384`, and `PS512` algorithms require JDK 11 or a compatible JCA Provider
|
||||||
> (like BouncyCastle) in the runtime classpath.**
|
> (like BouncyCastle) in the runtime classpath.**
|
||||||
> **The `EdDSA` algorithms requires JDK 15 or a compatible JCA Provider (like BouncyCastle) in the runtime classpath.**
|
>
|
||||||
|
>
|
||||||
|
> * **The `EdDSA` algorithms requires JDK 15 or a compatible JCA Provider (like BouncyCastle) in the runtime classpath.**
|
||||||
|
>
|
||||||
> If you want to use either set of algorithms, and you are on an earlier JDK that does not support them,
|
> If you want to use either set of algorithms, and you are on an earlier JDK that does not support them,
|
||||||
> see the [Installation](#Installation) section to see how to enable BouncyCastle. All other algorithms are
|
> see the [Installation](#Installation) section to see how to enable BouncyCastle. All other algorithms are
|
||||||
> natively supported by the JDK.
|
> natively supported by the JDK.
|
||||||
|
@ -1820,7 +1822,7 @@ parsing JWSs or JWEs.
|
||||||
#### JWS Decompression
|
#### JWS Decompression
|
||||||
|
|
||||||
If you used JJWT to compress a JWS and you used a custom compression algorithm, you will need to tell the
|
If you used JJWT to compress a JWS and you used a custom compression algorithm, you will need to tell the
|
||||||
`JwtParserBuilder` how to resolve your `CompressionCodec` to decompress the JWT.
|
`JwtParserBuilder` how to resolve your `CompressionAlgorithm` to decompress the JWT.
|
||||||
|
|
||||||
Please see the [Compression](#compression) section below to see how to decompress JWTs during parsing.
|
Please see the [Compression](#compression) section below to see how to decompress JWTs during parsing.
|
||||||
|
|
||||||
|
@ -1893,29 +1895,19 @@ String jws = Jwts.builder().signWith(testKey) // #1
|
||||||
.compact();
|
.compact();
|
||||||
```
|
```
|
||||||
|
|
||||||
To parse the resulting `jws` string, we need to do three things when creating the `JwtParser`:
|
To parse the resulting `jws` string, we need to do two things when creating the `JwtParser`:
|
||||||
|
|
||||||
1. Specify the signature verification key.
|
1. Specify the signature verification key.
|
||||||
2. Indicate that we want to support Unencoded Payload Option JWSs by enabling the `b64` `crit` header parameter.
|
|
||||||
3. Specify the externally-transmitted unencoded payload bytes, required for signature verification.
|
3. Specify the externally-transmitted unencoded payload bytes, required for signature verification.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Jws<byte[]> parsed = Jwts.parser().verifyWith(testKey) // 1
|
Jws<byte[]> parsed = Jwts.parser().verifyWith(testKey) // 1
|
||||||
.critical("b64") // 2
|
|
||||||
.build()
|
.build()
|
||||||
.parseContentJws(jws, content); // 3
|
.parseContentJws(jws, content); // 2
|
||||||
|
|
||||||
assertArrayEquals(content, parsed.getPayload());
|
assertArrayEquals(content, parsed.getPayload());
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Note**
|
|
||||||
>
|
|
||||||
> **Disabled by Default**: Because of the aforementioned
|
|
||||||
> [security considerations](https://www.rfc-editor.org/rfc/rfc7797.html#section-8), Unencoded Payload Option
|
|
||||||
> JWSs are rejected by the parser by default. Simply enabling the `b64` `crit`ical header as shown above (#2) enables
|
|
||||||
> the feature, with the presumption that the application developer understands the security considerations when doing
|
|
||||||
> so.
|
|
||||||
|
|
||||||
<a name="jws-unencoded-nondetached"></a>
|
<a name="jws-unencoded-nondetached"></a>
|
||||||
#### Non-Detached Payload Example
|
#### Non-Detached Payload Example
|
||||||
|
|
||||||
|
@ -1952,7 +1944,6 @@ See how the `claimsString` is embedded directly as the center `payload` token in
|
||||||
This is why no period (`.`) characters can exist in the payload. If they did, any standard JWT parser would see more
|
This is why no period (`.`) characters can exist in the payload. If they did, any standard JWT parser would see more
|
||||||
than two periods total, which is required for parsing standard JWSs.
|
than two periods total, which is required for parsing standard JWSs.
|
||||||
|
|
||||||
|
|
||||||
To parse the resulting `jws` string, we need to do two things when creating the `JwtParser`:
|
To parse the resulting `jws` string, we need to do two things when creating the `JwtParser`:
|
||||||
|
|
||||||
1. Specify the signature verification key.
|
1. Specify the signature verification key.
|
||||||
|
@ -1960,7 +1951,7 @@ To parse the resulting `jws` string, we need to do two things when creating the
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Jws<Claims> parsed = Jwts.parser().verifyWith(testKey) // 1
|
Jws<Claims> parsed = Jwts.parser().verifyWith(testKey) // 1
|
||||||
.critical("b64") // 2
|
.critical().add("b64").and() // 2
|
||||||
.build()
|
.build()
|
||||||
.parseClaimsJws(jws);
|
.parseClaimsJws(jws);
|
||||||
|
|
||||||
|
@ -1971,11 +1962,16 @@ assert "me".equals(parsed.getPayload().getIssuer());
|
||||||
Did you notice we used the `.parseClaimsJws(String)` method instead of `.parseClaimsJws(String, byte[])`? This is
|
Did you notice we used the `.parseClaimsJws(String)` method instead of `.parseClaimsJws(String, byte[])`? This is
|
||||||
because the non-detached payload is already present and JJWT has what it needs for signature verification.
|
because the non-detached payload is already present and JJWT has what it needs for signature verification.
|
||||||
|
|
||||||
Even so, you could call `.parseClaimsJws(String, byte[])` if you wanted by using the string's UTF-8 bytes:
|
Additionally, we needed to specify the `b64` critical value: because we're not using the two-argument
|
||||||
|
`parseClaimsJws(jws, content)` method, the parser has no way of knowing if you wish to allow or support unencoded
|
||||||
|
payloads. Unencoded payloads have additional security considerations as described above, so they are disabled by
|
||||||
|
the parser by default unless you indicate you want to support them by using `critical().add("b64")`.
|
||||||
|
|
||||||
|
Finally, even if the payload contains a non-detached String, you could still use the two-argument method using the
|
||||||
|
payload String's UTF-8 bytes instead:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
parsed = Jwts.parser().verifyWith(testKey)
|
parsed = Jwts.parser().verifyWith(testKey)
|
||||||
.critical("b64")
|
|
||||||
.build()
|
.build()
|
||||||
.parseClaimsJws(jws, claimsString.getBytes(StandardCharsets.UTF_8)); // <---
|
.parseClaimsJws(jws, claimsString.getBytes(StandardCharsets.UTF_8)); // <---
|
||||||
```
|
```
|
||||||
|
@ -2485,7 +2481,7 @@ You then use the resulting `jwtParserDecryptionKey` (not `pair.getPrivate()`) wi
|
||||||
the return value from a custom [Key Locator](#key-locator) implementation. For example:
|
the return value from a custom [Key Locator](#key-locator) implementation. For example:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
PrivateKey decryptionKey = Keys.wrap(pkcs11PrivateKey, pkcs11PublicKey);
|
PrivateKey decryptionKey = Keys.builder(pkcs11PrivateKey).publicKey(pkcs11PublicKey).build();
|
||||||
|
|
||||||
Jwts.parser()
|
Jwts.parser()
|
||||||
.decryptWith(decryptionKey) // <----
|
.decryptWith(decryptionKey) // <----
|
||||||
|
@ -2850,15 +2846,16 @@ When you call `compressWith`, the JWT `payload` will be compressed with your alg
|
||||||
header will automatically be set to the value returned by your algorithm's `algorithm.getId()` method as
|
header will automatically be set to the value returned by your algorithm's `algorithm.getId()` method as
|
||||||
required by the JWT specification.
|
required by the JWT specification.
|
||||||
|
|
||||||
|
<a name="compression-custom-locator"></a> <!-- legacy link -->
|
||||||
However, the `JwtParser` needs to be aware of this custom algorithm as well, so it can use it while parsing. You do this
|
However, the `JwtParser` needs to be aware of this custom algorithm as well, so it can use it while parsing. You do this
|
||||||
by calling the `JwtParserBuilder`'s `addCompressionAlgorithms` method. For example:
|
by modifying the `JwtParserBuilder`'s `zip()` collection. For example:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
CompressionAlgorithm myAlg = new MyCompressionAlgorithm();
|
CompressionAlgorithm myAlg = new MyCompressionAlgorithm();
|
||||||
|
|
||||||
Jwts.parser()
|
Jwts.parser()
|
||||||
|
|
||||||
.addCompressionAlgorithms(Collections.of(myAlg)) // <----
|
.zip().add(myAlg).and() // <----
|
||||||
|
|
||||||
// .. etc ...
|
// .. etc ...
|
||||||
```
|
```
|
||||||
|
@ -2915,7 +2912,7 @@ Serializer<Map<String,?>> serializer = getMySerializer(); //implement me
|
||||||
|
|
||||||
Jwts.builder()
|
Jwts.builder()
|
||||||
|
|
||||||
.serializer(serializer)
|
.json(serializer)
|
||||||
|
|
||||||
// ... etc ...
|
// ... etc ...
|
||||||
```
|
```
|
||||||
|
@ -2927,7 +2924,7 @@ Deserializer<Map<String,?>> deserializer = getMyDeserializer(); //implement me
|
||||||
|
|
||||||
Jwts.parser()
|
Jwts.parser()
|
||||||
|
|
||||||
.deserializer(deserializer)
|
.json(deserializer)
|
||||||
|
|
||||||
// ... etc ...
|
// ... etc ...
|
||||||
```
|
```
|
||||||
|
@ -2975,7 +2972,7 @@ ObjectMapper objectMapper = getMyObjectMapper(); //implement me
|
||||||
|
|
||||||
String jws = Jwts.builder()
|
String jws = Jwts.builder()
|
||||||
|
|
||||||
.serializer(new JacksonSerializer(objectMapper))
|
.json(new JacksonSerializer(objectMapper))
|
||||||
|
|
||||||
// ... etc ...
|
// ... etc ...
|
||||||
```
|
```
|
||||||
|
@ -2987,7 +2984,7 @@ ObjectMapper objectMapper = getMyObjectMapper(); //implement me
|
||||||
|
|
||||||
Jwts.parser()
|
Jwts.parser()
|
||||||
|
|
||||||
.deserializer(new JacksonDeserializer(objectMapper))
|
.json(new JacksonDeserializer(objectMapper))
|
||||||
|
|
||||||
// ... etc ...
|
// ... etc ...
|
||||||
```
|
```
|
||||||
|
@ -3021,7 +3018,7 @@ The `User` object could be retrieved from the `user` claim with the following co
|
||||||
```java
|
```java
|
||||||
Jwts.parser()
|
Jwts.parser()
|
||||||
|
|
||||||
.deserializer(new JacksonDeserializer(Maps.of("user", User.class).build())) // <-----
|
.json(new JacksonDeserializer(Maps.of("user", User.class).build())) // <-----
|
||||||
|
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
@ -3096,7 +3093,7 @@ Gson gson = new GsonBuilder()
|
||||||
|
|
||||||
String jws = Jwts.builder()
|
String jws = Jwts.builder()
|
||||||
|
|
||||||
.serializer(new GsonSerializer(gson))
|
.json(new GsonSerializer(gson))
|
||||||
|
|
||||||
// ... etc ...
|
// ... etc ...
|
||||||
```
|
```
|
||||||
|
@ -3108,7 +3105,7 @@ Gson gson = getGson(); //implement me
|
||||||
|
|
||||||
Jwts.parser()
|
Jwts.parser()
|
||||||
|
|
||||||
.deserializer(new GsonDeserializer(gson))
|
.json(new GsonDeserializer(gson))
|
||||||
|
|
||||||
// ... etc ...
|
// ... etc ...
|
||||||
```
|
```
|
||||||
|
@ -3250,7 +3247,7 @@ Encoder<byte[], String> encoder = getMyBase64UrlEncoder(); //implement me
|
||||||
|
|
||||||
String jws = Jwts.builder()
|
String jws = Jwts.builder()
|
||||||
|
|
||||||
.encoder(encoder)
|
.b64Url(encoder)
|
||||||
|
|
||||||
// ... etc ...
|
// ... etc ...
|
||||||
```
|
```
|
||||||
|
@ -3262,7 +3259,7 @@ Decoder<String, byte[]> decoder = getMyBase64UrlDecoder(); //implement me
|
||||||
|
|
||||||
Jwts.parser()
|
Jwts.parser()
|
||||||
|
|
||||||
.decoder(decoder)
|
.b64Url(decoder)
|
||||||
|
|
||||||
// ... etc ...
|
// ... etc ...
|
||||||
```
|
```
|
||||||
|
@ -3480,7 +3477,7 @@ KeyAlgorithm<PublicKey, PrivateKey> alg = Jwts.KEY.RSA_OAEP_256; //or RSA_OAEP o
|
||||||
AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc...
|
AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc...
|
||||||
|
|
||||||
// Bob creates the compact JWE with Alice's RSA public key so only she may read it:
|
// Bob creates the compact JWE with Alice's RSA public key so only she may read it:
|
||||||
String jwe = Jwts.builder().audience("Alice")
|
String jwe = Jwts.builder().audience().add("Alice").and()
|
||||||
.encryptWith(pair.getPublic(), alg, enc) // <-- Alice's RSA public key
|
.encryptWith(pair.getPublic(), alg, enc) // <-- Alice's RSA public key
|
||||||
.compact();
|
.compact();
|
||||||
|
|
||||||
|
@ -3543,12 +3540,12 @@ Alice can then decrypt the JWT using her Elliptic Curve private key:
|
||||||
KeyPair pair = Jwts.SIG.ES512.keyPair().build();
|
KeyPair pair = Jwts.SIG.ES512.keyPair().build();
|
||||||
|
|
||||||
// Choose the key algorithm used encrypt the payload key:
|
// Choose the key algorithm used encrypt the payload key:
|
||||||
KeyAlgorithm<PublicKey, PrivateKey> alg = Jwts.KEY.ECDH_ES_A256KW; //ECDH_ES_A192KW, etc.
|
KeyAlgorithm<PublicKey, PrivateKey> alg = Jwts.KEY.ECDH_ES_A256KW; //ECDH_ES_A192KW, etc...
|
||||||
// Choose the Encryption Algorithm to encrypt the payload:
|
// Choose the Encryption Algorithm to encrypt the payload:
|
||||||
AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc...
|
AeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc...
|
||||||
|
|
||||||
// Bob creates the compact JWE with Alice's EC public key so only she may read it:
|
// Bob creates the compact JWE with Alice's EC public key so only she may read it:
|
||||||
String jwe = Jwts.builder().audience("Alice")
|
String jwe = Jwts.builder().audience().add("Alice").and()
|
||||||
.encryptWith(pair.getPublic(), alg, enc) // <-- Alice's EC public key
|
.encryptWith(pair.getPublic(), alg, enc) // <-- Alice's EC public key
|
||||||
.compact();
|
.compact();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue