diff --git a/README.md b/README.md
index d138f4f2..1ed0e6e2 100644
--- a/README.md
+++ b/README.md
@@ -7,10 +7,10 @@
JJWT aims to be the easiest to use and understand library for creating and verifying JSON Web Tokens (JWTs) on the JVM
and Android.
-JJWT is a pure Java implementation based
-exclusively on the [JWT](https://tools.ietf.org/html/rfc7519),
-[JWS](https://tools.ietf.org/html/rfc7515), [JWE](https://tools.ietf.org/html/rfc7516),
-[JWK](https://tools.ietf.org/html/rfc7517) and [JWA](https://tools.ietf.org/html/rfc7518) RFC specifications and
+JJWT is a pure Java implementation based
+exclusively on the [JWT](https://tools.ietf.org/html/rfc7519),
+[JWS](https://tools.ietf.org/html/rfc7515), [JWE](https://tools.ietf.org/html/rfc7516),
+[JWK](https://tools.ietf.org/html/rfc7517) and [JWA](https://tools.ietf.org/html/rfc7518) RFC specifications and
open source under the terms of the [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0).
The library was created by [Okta's](http://www.okta.com) Senior Architect, [Les Hazlewood](https://github.com/lhazlewood)
@@ -18,122 +18,126 @@ and is supported and maintained by a [community](https://github.com/jwtk/jjwt/gr
[Okta](https://developer.okta.com/) is a complete authentication and user management API for developers.
-We've also added some convenience extensions that are not part of the specification, such as JWS compression and claim
+We've also added some convenience extensions that are not part of the specification, such as JWS compression and claim
enforcement.
## Table of Contents
-* [Features](#features)
- * [Currently Unsupported Features](#features-unsupported)
-* [Community](#community)
- * [Getting Help](#help)
- * [Questions](#help-questions)
- * [Bugs and Feature Requests](#help-issues)
- * [Contributing](#contributing)
- * [Pull Requests](#contributing-pull-requests)
- * [Help Wanted](#contributing-help-wanted)
-* [What is a JSON Web Token?](#overview)
-* [Installation](#install)
- * [JDK Projects](#install-jdk)
- * [Maven](#install-jdk-maven)
- * [Gradle](#install-jdk-gradle)
- * [Android Projects](#install-android)
- * [Dependencies](#install-android-dependencies)
- * [Proguard Exclusions](#install-android-proguard)
- * [Understanding JJWT Dependencies](#install-understandingdependencies)
-* [Quickstart](#quickstart)
-* [Signed JWTs](#jws)
- * [Signature Algorithm Keys](#jws-key)
- * [HMAC-SHA](#jws-key-hmacsha)
- * [RSA](#jws-key-rsa)
- * [Elliptic Curve](#jws-key-ecdsa)
- * [Creating Safe Keys](#jws-key-create)
- * [Secret Keys](#jws-key-create-secret)
- * [Asymetric Keys](#jws-key-create-asym)
- * [Create a JWS](#jws-create)
- * [Header](#jws-create-header)
- * [Instance](#jws-create-header-instance)
- * [Map](#jws-create-header-map)
- * [Claims](#jws-create-claims)
- * [Standard Claims](#jws-create-claims-standard)
- * [Custom Claims](#jws-create-claims-custom)
- * [Claims Instance](#jws-create-claims-instance)
- * [Claims Map](#jws-create-claims-map)
- * [Signing Key](#jws-create-key)
- * [SecretKey Formats](#jws-create-key-secret)
- * [Signature Algorithm Override](#jws-create-key-algoverride)
- * [Compression](#jws-create-compression)
- * [Read a JWS](#jws-read)
- * [Verification Key](#jws-read-key)
- * [Find the Verification Key at Runtime](#jws-read-key-resolver)
- * [Claims Assertions](#jws-read-claims)
- * [Accounting for Clock Skew](#jws-read-clock)
- * [Custom Clock](#jws-read-clock-custom)
- * [Decompression](#jws-read-decompression)
+- [Features](#features)
+ - [Currently Unsupported Features](#features-unsupported)
+- [Community](#community)
+ - [Getting Help](#help)
+ - [Questions](#help-questions)
+ - [Bugs and Feature Requests](#help-issues)
+ - [Contributing](#contributing)
+ - [Pull Requests](#contributing-pull-requests)
+ - [Help Wanted](#contributing-help-wanted)
+- [What is a JSON Web Token?](#overview)
+- [Installation](#install)
+ - [JDK Projects](#install-jdk)
+ - [Maven](#install-jdk-maven)
+ - [Gradle](#install-jdk-gradle)
+ - [Android Projects](#install-android)
+ - [Dependencies](#install-android-dependencies)
+ - [Proguard Exclusions](#install-android-proguard)
+ - [Understanding JJWT Dependencies](#install-understandingdependencies)
+- [Quickstart](#quickstart)
+- [Signed JWTs](#jws)
+ - [Signature Algorithm Keys](#jws-key)
+ - [HMAC-SHA](#jws-key-hmacsha)
+ - [RSA](#jws-key-rsa)
+ - [Elliptic Curve](#jws-key-ecdsa)
+ - [Creating Safe Keys](#jws-key-create)
+ - [Secret Keys](#jws-key-create-secret)
+ - [Asymetric Keys](#jws-key-create-asym)
+ - [Create a JWS](#jws-create)
+ - [Header](#jws-create-header)
+ - [Instance](#jws-create-header-instance)
+ - [Map](#jws-create-header-map)
+ - [Claims](#jws-create-claims)
+ - [Standard Claims](#jws-create-claims-standard)
+ - [Custom Claims](#jws-create-claims-custom)
+ - [Claims Instance](#jws-create-claims-instance)
+ - [Claims Map](#jws-create-claims-map)
+ - [Signing Key](#jws-create-key)
+ - [SecretKey Formats](#jws-create-key-secret)
+ - [Signature Algorithm Override](#jws-create-key-algoverride)
+ - [Compression](#jws-create-compression)
+ - [Read a JWS](#jws-read)
+ - [Verification Key](#jws-read-key)
+ - [Find the Verification Key at Runtime](#jws-read-key-resolver)
+ - [Claims Assertions](#jws-read-claims)
+ - [Accounting for Clock Skew](#jws-read-clock)
+ - [Custom Clock](#jws-read-clock-custom)
+ - [Decompression](#jws-read-decompression)
-* [Compression](#compression)
- * [Custom Compression Codec](#compression-custom)
-* [JSON Processor](#json)
- * [Custom JSON Processor](#json-custom)
- * [Jackson ObjectMapper](#json-jackson)
- * [Custom Claim Types](#json-jackson-custom-types)
- * [Gson](#json-gson)
-* [Base64 Support](#base64)
- * [Base64 in Security Contexts](#base64-security)
- * [Base64 is not Encryption](#base64-not-encryption)
- * [Changing Base64 Characters](#base64-changing-characters)
- * [Custom Base64 Codec](#base64-custom)
+- [Compression](#compression)
+ - [Custom Compression Codec](#compression-custom)
+- [JSON Processor](#json)
+ - [Custom JSON Processor](#json-custom)
+ - [Jackson ObjectMapper](#json-jackson)
+ - [Custom Claim Types](#json-jackson-custom-types)
+ - [Gson](#json-gson)
+- [Base64 Support](#base64)
+ - [Base64 in Security Contexts](#base64-security)
+ - [Base64 is not Encryption](#base64-not-encryption)
+ - [Changing Base64 Characters](#base64-changing-characters)
+ - [Custom Base64 Codec](#base64-custom)
+
## Features
- * Fully functional on all JDKs and Android
- * Automatic security best practices and assertions
- * Easy to learn and read API
- * Convenient and readable [fluent](http://en.wikipedia.org/wiki/Fluent_interface) interfaces, great for IDE auto-completion to write code quickly
- * Fully RFC specification compliant on all implemented functionality, tested against RFC-specified test vectors
- * Stable implementation with enforced 100% test code coverage. Literally every single method, statement and
- conditional branch variant in the entire codebase is tested and required to pass on every build.
- * Creating, parsing and verifying digitally signed compact JWTs (aka JWSs) with all standard JWS algorithms:
- * HS256: HMAC using SHA-256
- * HS384: HMAC using SHA-384
- * HS512: HMAC using SHA-512
- * ES256: ECDSA using P-256 and SHA-256
- * ES384: ECDSA using P-384 and SHA-384
- * ES512: ECDSA using P-521 and SHA-512
- * RS256: RSASSA-PKCS-v1_5 using SHA-256
- * RS384: RSASSA-PKCS-v1_5 using SHA-384
- * RS512: RSASSA-PKCS-v1_5 using SHA-512
- * PS256: RSASSA-PSS using SHA-256 and MGF1 with SHA-2561
- * PS384: RSASSA-PSS using SHA-384 and MGF1 with SHA-3841
- * PS512: RSASSA-PSS using SHA-512 and MGF1 with SHA-5121
-
- 1. Requires JDK 11 or a compatible JCA Provider (like BouncyCastle) in the runtime classpath.
- * Convenience enhancements beyond the specification such as
- * Body compression for any large JWT, not just JWEs
- * Claims assertions (requiring specific values)
- * Claim POJO marshaling and unmarshaling when using a compatible JSON parser (e.g. Jackson)
- * Secure Key generation based on desired JWA algorithms
- * and more...
-
+- Fully functional on all JDKs and Android
+- Automatic security best practices and assertions
+- Easy to learn and read API
+- Convenient and readable [fluent](http://en.wikipedia.org/wiki/Fluent_interface) interfaces, great for IDE auto-completion to write code quickly
+- Fully RFC specification compliant on all implemented functionality, tested against RFC-specified test vectors
+- Stable implementation with enforced 100% test code coverage. Literally every single method, statement and
+ conditional branch variant in the entire codebase is tested and required to pass on every build.
+- Creating, parsing and verifying digitally signed compact JWTs (aka JWSs) with all standard JWS algorithms:
+ - HS256: HMAC using SHA-256
+ - HS384: HMAC using SHA-384
+ - HS512: HMAC using SHA-512
+ - ES256: ECDSA using P-256 and SHA-256
+ - ES384: ECDSA using P-384 and SHA-384
+ - ES512: ECDSA using P-521 and SHA-512
+ - RS256: RSASSA-PKCS-v1_5 using SHA-256
+ - RS384: RSASSA-PKCS-v1_5 using SHA-384
+ - RS512: RSASSA-PKCS-v1_5 using SHA-512
+ - PS256: RSASSA-PSS using SHA-256 and MGF1 with SHA-2561
+ - PS384: RSASSA-PSS using SHA-384 and MGF1 with SHA-3841
+ - PS512: RSASSA-PSS using SHA-512 and MGF1 with SHA-5121
+ 1. Requires JDK 11 or a compatible JCA Provider (like BouncyCastle) in the runtime classpath.
+- Convenience enhancements beyond the specification such as
+ - Body compression for any large JWT, not just JWEs
+ - Claims assertions (requiring specific values)
+ - Claim POJO marshaling and unmarshaling when using a compatible JSON parser (e.g. Jackson)
+ - Secure Key generation based on desired JWA algorithms
+ - and more...
+
+
### Currently Unsupported Features
-* [Non-compact](https://tools.ietf.org/html/rfc7515#section-7.2) serialization and parsing.
-* JWE (Encryption for JWT)
+- [Non-compact](https://tools.ietf.org/html/rfc7515#section-7.2) serialization and parsing.
+- JWE (Encryption for JWT)
-These features will be implemented in a future release. Community contributions are welcome!
+These features will be implemented in a future release. Community contributions are welcome!
+
## Community
+
### Getting Help
-If you have trouble using JJWT, please first read the documentation on this page before asking questions. We try
+If you have trouble using JJWT, please first read the documentation on this page before asking questions. We try
very hard to ensure JJWT's documentation is robust, categorized with a table of contents, and up to date for each release.
+
#### Questions
If the documentation or the API JavaDoc isn't sufficient, and you either have usability questions or are confused
@@ -141,63 +145,68 @@ about something, please [ask your question here](https://stackoverflow.com/quest
After asking your question, you may wish to join our [Slack](https://jwtk.slack.com/messages/CBNACTN3A) or
[Gittr](https://gitter.im/jwtk/jjwt) chat rooms, but note that they may not always be attended. You will usually
-have a better chance of having your question answered by
+have a better chance of having your question answered by
[asking your question here](https://stackoverflow.com/questions/ask?tags=jjwt&guided=false).
-
-If you believe you have found a bug or would like to suggest a feature enhancement, please create a new GitHub issue,
+
+If you believe you have found a bug or would like to suggest a feature enhancement, please create a new GitHub issue,
however:
-**Please do not create a GitHub issue to ask a question.**
+**Please do not create a GitHub issue to ask a question.**
-We use GitHub Issues to track actionable work that requires changes to JJWT's design and/or codebase. If you have a
-usability question, instead please
-[ask your question here](https://stackoverflow.com/questions/ask?tags=jjwt&guided=false), or try Slack or Gittr as
+We use GitHub Issues to track actionable work that requires changes to JJWT's design and/or codebase. If you have a
+usability question, instead please
+[ask your question here](https://stackoverflow.com/questions/ask?tags=jjwt&guided=false), or try Slack or Gittr as
described above.
**If a GitHub Issue is created that does not represent actionable work for JJWT's codebase, it will be promptly closed.**
+
#### Bugs and Feature Requests
-If you do not have a usability question and believe you have a legitimate bug or feature request,
+If you do not have a usability question and believe you have a legitimate bug or feature request,
please do [create a new JJWT issue](https://github.com/jwtk/jjwt/issues/new).
-If you feel like you'd like to help fix a bug or implement the new feature yourself, please read the Contributing
+If you feel like you'd like to help fix a bug or implement the new feature yourself, please read the Contributing
section next before starting any work.
+
### Contributing
+
#### Pull Requests
-Simple Pull Requests that fix anything other than JJWT core code (documentation, JavaDoc, typos, test cases, etc) are
+Simple Pull Requests that fix anything other than JJWT core code (documentation, JavaDoc, typos, test cases, etc) are
always appreciated and have a high likelihood of being merged quickly. Please send them!
-However, if you want or feel the need to change JJWT's functionality or core code, please do not issue a pull request
-without [creating a new JJWT issue](https://github.com/jwtk/jjwt/issues/new) and discussing your desired
+However, if you want or feel the need to change JJWT's functionality or core code, please do not issue a pull request
+without [creating a new JJWT issue](https://github.com/jwtk/jjwt/issues/new) and discussing your desired
changes **first**, _before you start working on it_.
-It would be a shame to reject your earnest and genuinely appreciated pull request if it might not align with the
-project's goals, design expectations or planned functionality. We've sadly had to reject large PRs in the past because
-they were out of sync with project or design expectations - all because the PR author didn't first check in with
+It would be a shame to reject your earnest and genuinely appreciated pull request if it might not align with the
+project's goals, design expectations or planned functionality. We've sadly had to reject large PRs in the past because
+they were out of sync with project or design expectations - all because the PR author didn't first check in with
the team first before working on a solution.
So, please [create a new JJWT issue](https://github.com/jwtk/jjwt/issues/new) first to discuss, and then we can see if
-(or how) a PR is warranted. Thank you!
+(or how) a PR is warranted. Thank you!
+
#### Help Wanted
-If you would like to help, but don't know where to start, please visit the
-[Help Wanted Issues](https://github.com/jwtk/jjwt/labels/help%20wanted) page and pick any of the
+If you would like to help, but don't know where to start, please visit the
+[Help Wanted Issues](https://github.com/jwtk/jjwt/labels/help%20wanted) page and pick any of the
ones there, and we'll be happy to discuss and answer questions in the issue comments.
-If any of those don't appeal to you, no worries! Any help you would like to offer would be
+If any of those don't appeal to you, no worries! Any help you would like to offer would be
appreciated based on the above caveats concerning [contributing pull reqeuests](#contributing-pull-requests). Feel free
to discuss or ask questions first if you're not sure. :)
+
## What is a JSON Web Token?
Don't know what a JSON Web Token is? Read on. Otherwise, jump on down to the [Installation](#Installation) section.
@@ -205,7 +214,7 @@ Don't know what a JSON Web Token is? Read on. Otherwise, jump on down to the [In
JWT is a means of transmitting information between two parties in a compact, verifiable form.
The bits of information encoded in the body of a JWT are called `claims`. The expanded form of the JWT is in a JSON format, so each `claim` is a key in the JSON object.
-
+
JWTs can be cryptographically signed (making it a [JWS](https://tools.ietf.org/html/rfc7515)) or encrypted (making it a [JWE](https://tools.ietf.org/html/rfc7516)).
This adds a powerful layer of verifiability to the user of JWTs. The receiver has a high degree of confidence that the JWT has not been tampered with by verifying the signature, for instance.
@@ -216,15 +225,16 @@ The compact representation of a signed JWT is a string that has three parts, eac
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.ipevRNuRP6HflG8cFKnmUPtypruRC4fb1DWtoLL62SY
```
-Each part is [Base64URL](https://en.wikipedia.org/wiki/Base64)-encoded. The first part is the header, which at a
-minimum needs to specify the algorithm used to sign the JWT. The second part is the body. This part has all
-the claims of this JWT encoded in it. The final part is the signature. It's computed by passing a combination of
+Each part is [Base64URL](https://en.wikipedia.org/wiki/Base64)-encoded. The first part is the header, which at a
+minimum needs to specify the algorithm used to sign the JWT. The second part is the body. This part has all
+the claims of this JWT encoded in it. The final part is the signature. It's computed by passing a combination of
the header and body through the algorithm specified in the header.
-
-If you pass the first two parts through a base 64 url decoder, you'll get the following (formatting added for
+
+If you pass the first two parts through a base 64 url decoder, you'll get the following (formatting added for
clarity):
`header`
+
```
{
"alg": "HS256"
@@ -232,34 +242,38 @@ clarity):
```
`body`
+
```
{
"sub": "Joe"
}
```
-In this case, the information we have is that the HMAC using SHA-256 algorithm was used to sign the JWT. And, the
+In this case, the information we have is that the HMAC using SHA-256 algorithm was used to sign the JWT. And, the
body has a single claim, `sub` with value `Joe`.
-There are a number of standard claims, called [Registered Claims](https://tools.ietf.org/html/rfc7519#section-4.1),
+There are a number of standard claims, called [Registered Claims](https://tools.ietf.org/html/rfc7519#section-4.1),
in the specification and `sub` (for subject) is one of them.
To compute the signature, you need a secret key to sign it. We'll cover keys and algorithms later.
+
## Installation
Use your favorite Maven-compatible build tool to pull the dependencies from Maven Central.
-The dependencies could differ slightly if you are working with a [JDK project](#install-jdk) or an
+The dependencies could differ slightly if you are working with a [JDK project](#install-jdk) or an
[Android project](#install-android).
+
### JDK Projects
If you're building a (non-Android) JDK project, you will want to define the following dependencies:
+
#### Maven
```xml
@@ -280,7 +294,7 @@ If you're building a (non-Android) JDK project, you will want to define the foll
0.11.2
runtime
-
+
## Compression
**The JWT specification only standardizes this feature for JWEs (Encrypted JWTs) and not JWSs (Signed JWTs), however
-JJWT supports both**. If you are positive that a JWS you create with JJWT will _also_ be parsed with JJWT, you
-can use this feature with JWSs, otherwise it is best to only use it for JWEs.
+JJWT supports both**. If you are positive that a JWS you create with JJWT will _also_ be parsed with JJWT, you
+can use this feature with JWSs, otherwise it is best to only use it for JWEs.
-If a JWT's Claims set is sufficiently large - that is, it contains a lot of name/value pairs, or individual values are
+If a JWT's Claims set is sufficiently large - that is, it contains a lot of name/value pairs, or individual values are
very large or verbose - you can reduce the size of the created JWS by compressing the claims body.
-This might be important to you if the resulting JWS is used in a URL for example, since URLs are best kept under
-4096 characters due to browser, user mail agent, or HTTP gateway compatibility issues. Smaller JWTs also help reduce
+This might be important to you if the resulting JWS is used in a URL for example, since URLs are best kept under
+4096 characters due to browser, user mail agent, or HTTP gateway compatibility issues. Smaller JWTs also help reduce
bandwidth utilization, which may or may not be important depending on your application's volume or needs.
-If you want to compress your JWT, you can use the `JwtBuilder`'s `compressWith(CompressionAlgorithm)` method. For
+If you want to compress your JWT, you can use the `JwtBuilder`'s `compressWith(CompressionAlgorithm)` method. For
example:
```java
Jwts.builder()
-
+
.compressWith(CompressionCodecs.DEFLATE) // or CompressionCodecs.GZIP
-
+
// .. etc ...
```
-If you use the `DEFLATE` or `GZIP` Compression Codecs - that's it, you're done. You don't have to do anything during
+If you use the `DEFLATE` or `GZIP` Compression Codecs - that's it, you're done. You don't have to do anything during
parsing or configure the `JwtParser` for compression - JJWT will automatically decompress the body as expected.
+
### Custom Compression Codec
If however, you used your own custom compression codec when creating the JWT (via `JwtBuilder` `compressWith`), then
-you need to supply the codec to the `JwtParserBuilder` using the `setCompressionCodecResolver` method. For example:
+you need to supply the codec to the `JwtParserBuilder` using the `setCompressionCodecResolver` method. For example:
```java
CompressionCodecResolver ccr = new MyCompressionCodecResolver();
@@ -1225,63 +1281,63 @@ CompressionCodecResolver ccr = new MyCompressionCodecResolver();
Jwts.parserBuilder()
.setCompressionCodecResolver(ccr) // <----
-
+
// .. etc ...
```
Typically a `CompressionCodecResolver` implementation will inspect the `zip` header to find out what algorithm was
-used and then return a codec instance that supports that algorithm. For example:
+used and then return a codec instance that supports that algorithm. For example:
```java
public class MyCompressionCodecResolver implements CompressionCodecResolver {
-
+
@Override
public CompressionCodec resolveCompressionCodec(Header header) throws CompressionException {
-
+
String alg = header.getCompressionAlgorithm();
-
+
CompressionCodec codec = getCompressionCodec(alg); //implement me
-
+
return codec;
}
}
```
+
## JSON Support
-A `JwtBuilder` will serialize the `Header` and `Claims` maps (and potentially any Java objects they
-contain) to JSON with a `Serializer