mirror of https://github.com/jwtk/jjwt.git
update readme.md: installation in gradle 7+
This commit is contained in:
parent
1118726d04
commit
915a3753c4
365
README.md
365
README.md
|
@ -23,117 +23,121 @@ enforcement.
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
* [Features](#features)
|
- [Features](#features)
|
||||||
* [Currently Unsupported Features](#features-unsupported)
|
- [Currently Unsupported Features](#features-unsupported)
|
||||||
* [Community](#community)
|
- [Community](#community)
|
||||||
* [Getting Help](#help)
|
- [Getting Help](#help)
|
||||||
* [Questions](#help-questions)
|
- [Questions](#help-questions)
|
||||||
* [Bugs and Feature Requests](#help-issues)
|
- [Bugs and Feature Requests](#help-issues)
|
||||||
* [Contributing](#contributing)
|
- [Contributing](#contributing)
|
||||||
* [Pull Requests](#contributing-pull-requests)
|
- [Pull Requests](#contributing-pull-requests)
|
||||||
* [Help Wanted](#contributing-help-wanted)
|
- [Help Wanted](#contributing-help-wanted)
|
||||||
* [What is a JSON Web Token?](#overview)
|
- [What is a JSON Web Token?](#overview)
|
||||||
* [Installation](#install)
|
- [Installation](#install)
|
||||||
* [JDK Projects](#install-jdk)
|
- [JDK Projects](#install-jdk)
|
||||||
* [Maven](#install-jdk-maven)
|
- [Maven](#install-jdk-maven)
|
||||||
* [Gradle](#install-jdk-gradle)
|
- [Gradle](#install-jdk-gradle)
|
||||||
* [Android Projects](#install-android)
|
- [Android Projects](#install-android)
|
||||||
* [Dependencies](#install-android-dependencies)
|
- [Dependencies](#install-android-dependencies)
|
||||||
* [Proguard Exclusions](#install-android-proguard)
|
- [Proguard Exclusions](#install-android-proguard)
|
||||||
* [Understanding JJWT Dependencies](#install-understandingdependencies)
|
- [Understanding JJWT Dependencies](#install-understandingdependencies)
|
||||||
* [Quickstart](#quickstart)
|
- [Quickstart](#quickstart)
|
||||||
* [Signed JWTs](#jws)
|
- [Signed JWTs](#jws)
|
||||||
* [Signature Algorithm Keys](#jws-key)
|
- [Signature Algorithm Keys](#jws-key)
|
||||||
* [HMAC-SHA](#jws-key-hmacsha)
|
- [HMAC-SHA](#jws-key-hmacsha)
|
||||||
* [RSA](#jws-key-rsa)
|
- [RSA](#jws-key-rsa)
|
||||||
* [Elliptic Curve](#jws-key-ecdsa)
|
- [Elliptic Curve](#jws-key-ecdsa)
|
||||||
* [Creating Safe Keys](#jws-key-create)
|
- [Creating Safe Keys](#jws-key-create)
|
||||||
* [Secret Keys](#jws-key-create-secret)
|
- [Secret Keys](#jws-key-create-secret)
|
||||||
* [Asymetric Keys](#jws-key-create-asym)
|
- [Asymetric Keys](#jws-key-create-asym)
|
||||||
* [Create a JWS](#jws-create)
|
- [Create a JWS](#jws-create)
|
||||||
* [Header](#jws-create-header)
|
- [Header](#jws-create-header)
|
||||||
* [Instance](#jws-create-header-instance)
|
- [Instance](#jws-create-header-instance)
|
||||||
* [Map](#jws-create-header-map)
|
- [Map](#jws-create-header-map)
|
||||||
* [Claims](#jws-create-claims)
|
- [Claims](#jws-create-claims)
|
||||||
* [Standard Claims](#jws-create-claims-standard)
|
- [Standard Claims](#jws-create-claims-standard)
|
||||||
* [Custom Claims](#jws-create-claims-custom)
|
- [Custom Claims](#jws-create-claims-custom)
|
||||||
* [Claims Instance](#jws-create-claims-instance)
|
- [Claims Instance](#jws-create-claims-instance)
|
||||||
* [Claims Map](#jws-create-claims-map)
|
- [Claims Map](#jws-create-claims-map)
|
||||||
* [Signing Key](#jws-create-key)
|
- [Signing Key](#jws-create-key)
|
||||||
* [SecretKey Formats](#jws-create-key-secret)
|
- [SecretKey Formats](#jws-create-key-secret)
|
||||||
* [Signature Algorithm Override](#jws-create-key-algoverride)
|
- [Signature Algorithm Override](#jws-create-key-algoverride)
|
||||||
* [Compression](#jws-create-compression)
|
- [Compression](#jws-create-compression)
|
||||||
* [Read a JWS](#jws-read)
|
- [Read a JWS](#jws-read)
|
||||||
* [Verification Key](#jws-read-key)
|
- [Verification Key](#jws-read-key)
|
||||||
* [Find the Verification Key at Runtime](#jws-read-key-resolver)
|
- [Find the Verification Key at Runtime](#jws-read-key-resolver)
|
||||||
* [Claims Assertions](#jws-read-claims)
|
- [Claims Assertions](#jws-read-claims)
|
||||||
* [Accounting for Clock Skew](#jws-read-clock)
|
- [Accounting for Clock Skew](#jws-read-clock)
|
||||||
* [Custom Clock](#jws-read-clock-custom)
|
- [Custom Clock](#jws-read-clock-custom)
|
||||||
* [Decompression](#jws-read-decompression)
|
- [Decompression](#jws-read-decompression)
|
||||||
<!-- * [Error Handling](#jws-read-errors) -->
|
<!-- * [Error Handling](#jws-read-errors) -->
|
||||||
* [Compression](#compression)
|
- [Compression](#compression)
|
||||||
* [Custom Compression Codec](#compression-custom)
|
- [Custom Compression Codec](#compression-custom)
|
||||||
* [JSON Processor](#json)
|
- [JSON Processor](#json)
|
||||||
* [Custom JSON Processor](#json-custom)
|
- [Custom JSON Processor](#json-custom)
|
||||||
* [Jackson ObjectMapper](#json-jackson)
|
- [Jackson ObjectMapper](#json-jackson)
|
||||||
* [Custom Claim Types](#json-jackson-custom-types)
|
- [Custom Claim Types](#json-jackson-custom-types)
|
||||||
* [Gson](#json-gson)
|
- [Gson](#json-gson)
|
||||||
* [Base64 Support](#base64)
|
- [Base64 Support](#base64)
|
||||||
* [Base64 in Security Contexts](#base64-security)
|
- [Base64 in Security Contexts](#base64-security)
|
||||||
* [Base64 is not Encryption](#base64-not-encryption)
|
- [Base64 is not Encryption](#base64-not-encryption)
|
||||||
* [Changing Base64 Characters](#base64-changing-characters)
|
- [Changing Base64 Characters](#base64-changing-characters)
|
||||||
* [Custom Base64 Codec](#base64-custom)
|
- [Custom Base64 Codec](#base64-custom)
|
||||||
|
|
||||||
<a name="features"></a>
|
<a name="features"></a>
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* Fully functional on all JDKs and Android
|
- Fully functional on all JDKs and Android
|
||||||
* Automatic security best practices and assertions
|
- Automatic security best practices and assertions
|
||||||
* Easy to learn and read API
|
- 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
|
- 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
|
- 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
|
- 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.
|
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:
|
- Creating, parsing and verifying digitally signed compact JWTs (aka JWSs) with all standard JWS algorithms:
|
||||||
* HS256: HMAC using SHA-256
|
- HS256: HMAC using SHA-256
|
||||||
* HS384: HMAC using SHA-384
|
- HS384: HMAC using SHA-384
|
||||||
* HS512: HMAC using SHA-512
|
- HS512: HMAC using SHA-512
|
||||||
* ES256: ECDSA using P-256 and SHA-256
|
- ES256: ECDSA using P-256 and SHA-256
|
||||||
* ES384: ECDSA using P-384 and SHA-384
|
- ES384: ECDSA using P-384 and SHA-384
|
||||||
* ES512: ECDSA using P-521 and SHA-512
|
- ES512: ECDSA using P-521 and SHA-512
|
||||||
* RS256: RSASSA-PKCS-v1_5 using SHA-256
|
- RS256: RSASSA-PKCS-v1_5 using SHA-256
|
||||||
* RS384: RSASSA-PKCS-v1_5 using SHA-384
|
- RS384: RSASSA-PKCS-v1_5 using SHA-384
|
||||||
* RS512: RSASSA-PKCS-v1_5 using SHA-512
|
- RS512: RSASSA-PKCS-v1_5 using SHA-512
|
||||||
* PS256: RSASSA-PSS using SHA-256 and MGF1 with SHA-256<sup>1</sup>
|
- PS256: RSASSA-PSS using SHA-256 and MGF1 with SHA-256<sup>1</sup>
|
||||||
* PS384: RSASSA-PSS using SHA-384 and MGF1 with SHA-384<sup>1</sup>
|
- PS384: RSASSA-PSS using SHA-384 and MGF1 with SHA-384<sup>1</sup>
|
||||||
* PS512: RSASSA-PSS using SHA-512 and MGF1 with SHA-512<sup>1</sup>
|
- PS512: RSASSA-PSS using SHA-512 and MGF1 with SHA-512<sup>1</sup>
|
||||||
|
|
||||||
<sup>1. Requires JDK 11 or a compatible JCA Provider (like BouncyCastle) in the runtime classpath.</sup>
|
<sup>1. Requires JDK 11 or a compatible JCA Provider (like BouncyCastle) in the runtime classpath.</sup>
|
||||||
* Convenience enhancements beyond the specification such as
|
- Convenience enhancements beyond the specification such as
|
||||||
* Body compression for any large JWT, not just JWEs
|
- Body compression for any large JWT, not just JWEs
|
||||||
* Claims assertions (requiring specific values)
|
- Claims assertions (requiring specific values)
|
||||||
* Claim POJO marshaling and unmarshaling when using a compatible JSON parser (e.g. Jackson)
|
- Claim POJO marshaling and unmarshaling when using a compatible JSON parser (e.g. Jackson)
|
||||||
* Secure Key generation based on desired JWA algorithms
|
- Secure Key generation based on desired JWA algorithms
|
||||||
* and more...
|
- and more...
|
||||||
|
|
||||||
<a name="features-unsupported"></a>
|
<a name="features-unsupported"></a>
|
||||||
|
|
||||||
### Currently Unsupported Features
|
### Currently Unsupported Features
|
||||||
|
|
||||||
* [Non-compact](https://tools.ietf.org/html/rfc7515#section-7.2) serialization and parsing.
|
- [Non-compact](https://tools.ietf.org/html/rfc7515#section-7.2) serialization and parsing.
|
||||||
* JWE (Encryption for JWT)
|
- 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!
|
||||||
|
|
||||||
<a name="community"></a>
|
<a name="community"></a>
|
||||||
|
|
||||||
## Community
|
## Community
|
||||||
|
|
||||||
<a name="help"></a>
|
<a name="help"></a>
|
||||||
|
|
||||||
### Getting Help
|
### 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.
|
very hard to ensure JJWT's documentation is robust, categorized with a table of contents, and up to date for each release.
|
||||||
|
|
||||||
<a name="help-questions"></a>
|
<a name="help-questions"></a>
|
||||||
|
|
||||||
#### Questions
|
#### Questions
|
||||||
|
|
||||||
If the documentation or the API JavaDoc isn't sufficient, and you either have usability questions or are confused
|
If the documentation or the API JavaDoc isn't sufficient, and you either have usability questions or are confused
|
||||||
|
@ -157,6 +161,7 @@ described above.
|
||||||
**If a GitHub Issue is created that does not represent actionable work for JJWT's codebase, it will be promptly closed.**
|
**If a GitHub Issue is created that does not represent actionable work for JJWT's codebase, it will be promptly closed.**
|
||||||
|
|
||||||
<a name="help-issues"></a>
|
<a name="help-issues"></a>
|
||||||
|
|
||||||
#### Bugs and Feature Requests
|
#### 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,
|
||||||
|
@ -166,9 +171,11 @@ If you feel like you'd like to help fix a bug or implement the new feature yours
|
||||||
section next before starting any work.
|
section next before starting any work.
|
||||||
|
|
||||||
<a name="contributing"></a>
|
<a name="contributing"></a>
|
||||||
|
|
||||||
### Contributing
|
### Contributing
|
||||||
|
|
||||||
<a name="contributing-pull-requests"></a>
|
<a name="contributing-pull-requests"></a>
|
||||||
|
|
||||||
#### Pull Requests
|
#### 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
|
||||||
|
@ -187,6 +194,7 @@ So, please [create a new JJWT issue](https://github.com/jwtk/jjwt/issues/new) fi
|
||||||
(or how) a PR is warranted. Thank you!
|
(or how) a PR is warranted. Thank you!
|
||||||
|
|
||||||
<a name="contributing-help-wanted"></a>
|
<a name="contributing-help-wanted"></a>
|
||||||
|
|
||||||
#### Help Wanted
|
#### Help Wanted
|
||||||
|
|
||||||
If you would like to help, but don't know where to start, please visit the
|
If you would like to help, but don't know where to start, please visit the
|
||||||
|
@ -198,6 +206,7 @@ appreciated based on the above caveats concerning [contributing pull reqeuests](
|
||||||
to discuss or ask questions first if you're not sure. :)
|
to discuss or ask questions first if you're not sure. :)
|
||||||
|
|
||||||
<a name="overview"></a>
|
<a name="overview"></a>
|
||||||
|
|
||||||
## What is a JSON Web Token?
|
## 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.
|
Don't know what a JSON Web Token is? Read on. Otherwise, jump on down to the [Installation](#Installation) section.
|
||||||
|
@ -225,6 +234,7 @@ If you pass the first two parts through a base 64 url decoder, you'll get the fo
|
||||||
clarity):
|
clarity):
|
||||||
|
|
||||||
`header`
|
`header`
|
||||||
|
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"alg": "HS256"
|
"alg": "HS256"
|
||||||
|
@ -232,6 +242,7 @@ clarity):
|
||||||
```
|
```
|
||||||
|
|
||||||
`body`
|
`body`
|
||||||
|
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"sub": "Joe"
|
"sub": "Joe"
|
||||||
|
@ -247,6 +258,7 @@ 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.
|
To compute the signature, you need a secret key to sign it. We'll cover keys and algorithms later.
|
||||||
|
|
||||||
<a name="install"></a>
|
<a name="install"></a>
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Use your favorite Maven-compatible build tool to pull the dependencies from Maven Central.
|
Use your favorite Maven-compatible build tool to pull the dependencies from Maven Central.
|
||||||
|
@ -255,11 +267,13 @@ The dependencies could differ slightly if you are working with a [JDK project](#
|
||||||
[Android project](#install-android).
|
[Android project](#install-android).
|
||||||
|
|
||||||
<a name="install-jdk"></a>
|
<a name="install-jdk"></a>
|
||||||
|
|
||||||
### JDK Projects
|
### JDK Projects
|
||||||
|
|
||||||
If you're building a (non-Android) JDK project, you will want to define the following dependencies:
|
If you're building a (non-Android) JDK project, you will want to define the following dependencies:
|
||||||
|
|
||||||
<a name="install-jdk-maven"></a>
|
<a name="install-jdk-maven"></a>
|
||||||
|
|
||||||
#### Maven
|
#### Maven
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
|
@ -293,6 +307,7 @@ If you're building a (non-Android) JDK project, you will want to define the foll
|
||||||
```
|
```
|
||||||
|
|
||||||
<a name="install-jdk-gradle"></a>
|
<a name="install-jdk-gradle"></a>
|
||||||
|
|
||||||
#### Gradle
|
#### Gradle
|
||||||
|
|
||||||
```groovy
|
```groovy
|
||||||
|
@ -302,15 +317,20 @@ dependencies {
|
||||||
// Uncomment the next line if you want to use RSASSA-PSS (PS256, PS384, PS512) algorithms:
|
// Uncomment the next line if you want to use RSASSA-PSS (PS256, PS384, PS512) algorithms:
|
||||||
//'org.bouncycastle:bcprov-jdk15on:1.60',
|
//'org.bouncycastle:bcprov-jdk15on:1.60',
|
||||||
'io.jsonwebtoken:jjwt-jackson:0.11.2' // or 'io.jsonwebtoken:jjwt-gson:0.11.2' for gson
|
'io.jsonwebtoken:jjwt-jackson:0.11.2' // or 'io.jsonwebtoken:jjwt-gson:0.11.2' for gson
|
||||||
|
// Gradle 7+ doesn't support the compile and runtime configuration anymore. Please use implementation and runtimeOnly instead.
|
||||||
|
implementation 'io.jsonwebtoken:jjwt-api:0.11.2'
|
||||||
|
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<a name="install-android"></a>
|
<a name="install-android"></a>
|
||||||
|
|
||||||
### Android Projects
|
### Android Projects
|
||||||
|
|
||||||
Android projects will want to define the following dependencies and Proguard exclusions:
|
Android projects will want to define the following dependencies and Proguard exclusions:
|
||||||
|
|
||||||
<a name="install-android-dependencies"></a>
|
<a name="install-android-dependencies"></a>
|
||||||
|
|
||||||
#### Dependencies
|
#### Dependencies
|
||||||
|
|
||||||
Add the dependencies to your project:
|
Add the dependencies to your project:
|
||||||
|
@ -328,6 +348,7 @@ dependencies {
|
||||||
```
|
```
|
||||||
|
|
||||||
<a name="install-android-proguard"></a>
|
<a name="install-android-proguard"></a>
|
||||||
|
|
||||||
#### Proguard
|
#### Proguard
|
||||||
|
|
||||||
You can use the following [Android Proguard](https://developer.android.com/studio/build/shrink-code) exclusion rules:
|
You can use the following [Android Proguard](https://developer.android.com/studio/build/shrink-code) exclusion rules:
|
||||||
|
@ -345,6 +366,7 @@ You can use the following [Android Proguard](https://developer.android.com/studi
|
||||||
```
|
```
|
||||||
|
|
||||||
<a name="install-understandingdependencies"></a>
|
<a name="install-understandingdependencies"></a>
|
||||||
|
|
||||||
### Understanding JJWT Dependencies
|
### Understanding JJWT Dependencies
|
||||||
|
|
||||||
Notice the above dependency declarations all have only one compile-time dependency and the rest are declared as
|
Notice the above dependency declarations all have only one compile-time dependency and the rest are declared as
|
||||||
|
@ -366,6 +388,7 @@ implementations whenever and however necessary. This helps us implement feature
|
||||||
you more quickly and efficiently.
|
you more quickly and efficiently.
|
||||||
|
|
||||||
<a name="quickstart"></a>
|
<a name="quickstart"></a>
|
||||||
|
|
||||||
## Quickstart
|
## Quickstart
|
||||||
|
|
||||||
Most complexity is hidden behind a convenient and readable builder-based [fluent interface](http://en.wikipedia.org/wiki/Fluent_interface), great for relying on IDE auto-completion to write code quickly. Here's an example:
|
Most complexity is hidden behind a convenient and readable builder-based [fluent interface](http://en.wikipedia.org/wiki/Fluent_interface), great for relying on IDE auto-completion to write code quickly. Here's an example:
|
||||||
|
@ -387,10 +410,10 @@ How easy was that!?
|
||||||
|
|
||||||
In this case, we are:
|
In this case, we are:
|
||||||
|
|
||||||
1. *building* a JWT that will have the
|
1. _building_ a JWT that will have the
|
||||||
[registered claim](https://tools.ietf.org/html/rfc7519#section-4.1) `sub` (subject) set to `Joe`. We are then
|
[registered claim](https://tools.ietf.org/html/rfc7519#section-4.1) `sub` (subject) set to `Joe`. We are then
|
||||||
2. *signing* the JWT using a key suitable for the HMAC-SHA-256 algorithm. Finally, we are
|
2. _signing_ the JWT using a key suitable for the HMAC-SHA-256 algorithm. Finally, we are
|
||||||
3. *compacting* it into its final `String` form. A signed JWT is called a 'JWS'.
|
3. _compacting_ it into its final `String` form. A signed JWT is called a 'JWS'.
|
||||||
|
|
||||||
The resultant `jws` String looks like this:
|
The resultant `jws` String looks like this:
|
||||||
|
|
||||||
|
@ -428,6 +451,7 @@ try {
|
||||||
```
|
```
|
||||||
|
|
||||||
<a name="jws"></a>
|
<a name="jws"></a>
|
||||||
|
|
||||||
## Signed JWTs
|
## Signed JWTs
|
||||||
|
|
||||||
The JWT specification provides for the ability to
|
The JWT specification provides for the ability to
|
||||||
|
@ -444,6 +468,7 @@ So how is a JWT signed? Let's walk through it with some easy-to-read pseudocode
|
||||||
1. Assume we have a JWT with a JSON header and body (aka 'Claims') as follows:
|
1. Assume we have a JWT with a JSON header and body (aka 'Claims') as follows:
|
||||||
|
|
||||||
**header**
|
**header**
|
||||||
|
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"alg": "HS256"
|
"alg": "HS256"
|
||||||
|
@ -451,6 +476,7 @@ So how is a JWT signed? Let's walk through it with some easy-to-read pseudocode
|
||||||
```
|
```
|
||||||
|
|
||||||
**body**
|
**body**
|
||||||
|
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"sub": "Joe"
|
"sub": "Joe"
|
||||||
|
@ -492,7 +518,6 @@ So how is a JWT signed? Let's walk through it with some easy-to-read pseudocode
|
||||||
String jws = concatenated + '.' + base64URLEncode( signature )
|
String jws = concatenated + '.' + base64URLEncode( signature )
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
And there you have it, the final `jws` String looks like this:
|
And there you have it, the final `jws` String looks like this:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -510,23 +535,24 @@ Keys, specifically as they relate to the JWT specifications. Understanding them
|
||||||
JWS properly.
|
JWS properly.
|
||||||
|
|
||||||
<a name="jws-key"></a>
|
<a name="jws-key"></a>
|
||||||
|
|
||||||
### Signature Algorithms Keys
|
### Signature Algorithms Keys
|
||||||
|
|
||||||
The JWT specification identifies 12 standard signature algorithms - 3 secret key algorithms and 9 asymmetric
|
The JWT specification identifies 12 standard signature algorithms - 3 secret key algorithms and 9 asymmetric
|
||||||
key algorithms - identified by the following names:
|
key algorithms - identified by the following names:
|
||||||
|
|
||||||
* `HS256`: HMAC using SHA-256
|
- `HS256`: HMAC using SHA-256
|
||||||
* `HS384`: HMAC using SHA-384
|
- `HS384`: HMAC using SHA-384
|
||||||
* `HS512`: HMAC using SHA-512
|
- `HS512`: HMAC using SHA-512
|
||||||
* `ES256`: ECDSA using P-256 and SHA-256
|
- `ES256`: ECDSA using P-256 and SHA-256
|
||||||
* `ES384`: ECDSA using P-384 and SHA-384
|
- `ES384`: ECDSA using P-384 and SHA-384
|
||||||
* `ES512`: ECDSA using P-521 and SHA-512
|
- `ES512`: ECDSA using P-521 and SHA-512
|
||||||
* `RS256`: RSASSA-PKCS-v1_5 using SHA-256
|
- `RS256`: RSASSA-PKCS-v1_5 using SHA-256
|
||||||
* `RS384`: RSASSA-PKCS-v1_5 using SHA-384
|
- `RS384`: RSASSA-PKCS-v1_5 using SHA-384
|
||||||
* `RS512`: RSASSA-PKCS-v1_5 using SHA-512
|
- `RS512`: RSASSA-PKCS-v1_5 using SHA-512
|
||||||
* `PS256`: RSASSA-PSS using SHA-256 and MGF1 with SHA-256
|
- `PS256`: RSASSA-PSS using SHA-256 and MGF1 with SHA-256
|
||||||
* `PS384`: RSASSA-PSS using SHA-384 and MGF1 with SHA-384
|
- `PS384`: RSASSA-PSS using SHA-384 and MGF1 with SHA-384
|
||||||
* `PS512`: RSASSA-PSS using SHA-512 and MGF1 with SHA-512
|
- `PS512`: RSASSA-PSS using SHA-512 and MGF1 with SHA-512
|
||||||
|
|
||||||
These are all represented in the `io.jsonwebtoken.SignatureAlgorithm` enum.
|
These are all represented in the `io.jsonwebtoken.SignatureAlgorithm` enum.
|
||||||
|
|
||||||
|
@ -546,22 +572,23 @@ one wants completely insecure JWTs, right? Neither would we.
|
||||||
So what are the requirements?
|
So what are the requirements?
|
||||||
|
|
||||||
<a name="jws-key-hmacsha"></a>
|
<a name="jws-key-hmacsha"></a>
|
||||||
|
|
||||||
#### HMAC-SHA
|
#### HMAC-SHA
|
||||||
|
|
||||||
JWT HMAC-SHA signature algorithms `HS256`, `HS384`, and `HS512` require a secret key that is _at least_ as many bits as
|
JWT HMAC-SHA signature algorithms `HS256`, `HS384`, and `HS512` require a secret key that is _at least_ as many bits as
|
||||||
the algorithm's signature (digest) length per [RFC 7512 Section 3.2](https://tools.ietf.org/html/rfc7518#section-3.2).
|
the algorithm's signature (digest) length per [RFC 7512 Section 3.2](https://tools.ietf.org/html/rfc7518#section-3.2).
|
||||||
This means:
|
This means:
|
||||||
|
|
||||||
* `HS256` is HMAC-SHA-256, and that produces digests that are 256 bits (32 bytes) long, so `HS256` _requires_ that you
|
- `HS256` is HMAC-SHA-256, and that produces digests that are 256 bits (32 bytes) long, so `HS256` _requires_ that you
|
||||||
use a secret key that is at least 32 bytes long.
|
use a secret key that is at least 32 bytes long.
|
||||||
|
- `HS384` is HMAC-SHA-384, and that produces digests that are 384 bits (48 bytes) long, so `HS384` _requires_ that you
|
||||||
* `HS384` is HMAC-SHA-384, and that produces digests that are 384 bits (48 bytes) long, so `HS384` _requires_ that you
|
|
||||||
use a secret key that is at least 48 bytes long.
|
use a secret key that is at least 48 bytes long.
|
||||||
|
|
||||||
* `HS512` is HMAC-SHA-512, and that produces digests that are 512 bits (64 bytes) long, so `HS512` _requires_ that you
|
- `HS512` is HMAC-SHA-512, and that produces digests that are 512 bits (64 bytes) long, so `HS512` _requires_ that you
|
||||||
use a secret key that is at least 64 bytes long.
|
use a secret key that is at least 64 bytes long.
|
||||||
|
|
||||||
<a name="jws-key-rsa"></a>
|
<a name="jws-key-rsa"></a>
|
||||||
|
|
||||||
#### RSA
|
#### RSA
|
||||||
|
|
||||||
JWT RSA signature algorithms `RS256`, `RS384`, `RS512`, `PS256`, `PS384` and `PS512` all require a minimum key length
|
JWT RSA signature algorithms `RS256`, `RS384`, `RS512`, `PS256`, `PS384` and `PS512` all require a minimum key length
|
||||||
|
@ -572,27 +599,28 @@ Anything smaller than this (such as 1024 bits) will be rejected with an `Invalid
|
||||||
That said, in keeping with best practices and increasing key lengths for security longevity, JJWT
|
That said, in keeping with best practices and increasing key lengths for security longevity, JJWT
|
||||||
recoommends that you use:
|
recoommends that you use:
|
||||||
|
|
||||||
* at least 2048 bit keys with `RS256` and `PS256`
|
- at least 2048 bit keys with `RS256` and `PS256`
|
||||||
* at least 3072 bit keys with `RS384` and `PS384`
|
- at least 3072 bit keys with `RS384` and `PS384`
|
||||||
* at least 4096 bit keys with `RS512` and `PS512`
|
- at least 4096 bit keys with `RS512` and `PS512`
|
||||||
|
|
||||||
These are only JJWT suggestions and not requirements. JJWT only enforces JWT specification requirements and
|
These are only JJWT suggestions and not requirements. JJWT only enforces JWT specification requirements and
|
||||||
for any RSA key, the requirement is the RSA key (modulus) length in bits MUST be >= 2048 bits.
|
for any RSA key, the requirement is the RSA key (modulus) length in bits MUST be >= 2048 bits.
|
||||||
|
|
||||||
<a name="jws-key-ecdsa"></a>
|
<a name="jws-key-ecdsa"></a>
|
||||||
|
|
||||||
#### Elliptic Curve
|
#### Elliptic Curve
|
||||||
|
|
||||||
JWT Elliptic Curve signature algorithms `ES256`, `ES384`, and `ES512` all require a minimum key length
|
JWT Elliptic Curve signature algorithms `ES256`, `ES384`, and `ES512` all require a minimum key length
|
||||||
(aka an Elliptic Curve order bit length) that is _at least_ as many bits as the algorithm signature's individual
|
(aka an Elliptic Curve order bit length) that is _at least_ as many bits as the algorithm signature's individual
|
||||||
`R` and `S` components per [RFC 7512 Section 3.4](https://tools.ietf.org/html/rfc7518#section-3.4). This means:
|
`R` and `S` components per [RFC 7512 Section 3.4](https://tools.ietf.org/html/rfc7518#section-3.4). This means:
|
||||||
|
|
||||||
* `ES256` requires that you use a private key that is at least 256 bits (32 bytes) long.
|
- `ES256` requires that you use a private key that is at least 256 bits (32 bytes) long.
|
||||||
|
- `ES384` requires that you use a private key that is at least 384 bits (48 bytes) long.
|
||||||
|
|
||||||
* `ES384` requires that you use a private key that is at least 384 bits (48 bytes) long.
|
- `ES512` requires that you use a private key that is at least 512 bits (64 bytes) long.
|
||||||
|
|
||||||
* `ES512` requires that you use a private key that is at least 512 bits (64 bytes) long.
|
|
||||||
|
|
||||||
<a name="jws-key-create"></a>
|
<a name="jws-key-create"></a>
|
||||||
|
|
||||||
#### Creating Safe Keys
|
#### Creating Safe Keys
|
||||||
|
|
||||||
If you don't want to think about bit length requirements or just want to make your life easier, JJWT has
|
If you don't want to think about bit length requirements or just want to make your life easier, JJWT has
|
||||||
|
@ -600,6 +628,7 @@ provided the `io.jsonwebtoken.security.Keys` utility class that can generate suf
|
||||||
JWT signature algorithm you might want to use.
|
JWT signature algorithm you might want to use.
|
||||||
|
|
||||||
<a name="jws-key-create-secret"></a>
|
<a name="jws-key-create-secret"></a>
|
||||||
|
|
||||||
##### Secret Keys
|
##### Secret Keys
|
||||||
|
|
||||||
If you want to generate a sufficiently strong `SecretKey` for use with the JWT HMAC-SHA algorithms, use the
|
If you want to generate a sufficiently strong `SecretKey` for use with the JWT HMAC-SHA algorithms, use the
|
||||||
|
@ -623,6 +652,7 @@ Ensure you save the resulting `secretString` somewhere safe -
|
||||||
further encrypt it, etc, before saving to disk (for example).
|
further encrypt it, etc, before saving to disk (for example).
|
||||||
|
|
||||||
<a name="jws-key-create-asym"></a>
|
<a name="jws-key-create-asym"></a>
|
||||||
|
|
||||||
##### Asymmetric Keys
|
##### Asymmetric Keys
|
||||||
|
|
||||||
If you want to generate sufficiently strong Elliptic Curve or RSA asymmetric key pairs for use with JWT ECDSA or RSA
|
If you want to generate sufficiently strong Elliptic Curve or RSA asymmetric key pairs for use with JWT ECDSA or RSA
|
||||||
|
@ -641,6 +671,7 @@ the [Installation](#Installation) section to see how to enable BouncyCastle. Al
|
||||||
supported by the JDK.
|
supported by the JDK.
|
||||||
|
|
||||||
<a name="jws-create"></a>
|
<a name="jws-create"></a>
|
||||||
|
|
||||||
### Creating a JWS
|
### Creating a JWS
|
||||||
|
|
||||||
You create a JWS as follows:
|
You create a JWS as follows:
|
||||||
|
@ -663,6 +694,7 @@ String jws = Jwts.builder() // (1)
|
||||||
```
|
```
|
||||||
|
|
||||||
<a name="jws-create-header"></a>
|
<a name="jws-create-header"></a>
|
||||||
|
|
||||||
#### Header Parameters
|
#### Header Parameters
|
||||||
|
|
||||||
A JWT Header provides metadata about the contents, format and cryptographic operations relevant to the JWT's Claims.
|
A JWT Header provides metadata about the contents, format and cryptographic operations relevant to the JWT's Claims.
|
||||||
|
@ -687,6 +719,7 @@ potentially overwriting any existing identically-named key/value pair.
|
||||||
depending on the signature algorithm or compression algorithm used.
|
depending on the signature algorithm or compression algorithm used.
|
||||||
|
|
||||||
<a name="jws-create-header-instance"></a>
|
<a name="jws-create-header-instance"></a>
|
||||||
|
|
||||||
##### Header Instance
|
##### Header Instance
|
||||||
|
|
||||||
If you want to specify the entire header at once, you can use the `Jwts.header()` method and build up the header
|
If you want to specify the entire header at once, you can use the `Jwts.header()` method and build up the header
|
||||||
|
@ -711,6 +744,7 @@ already been set. In all cases however, JJWT will still set (and overwrite) any
|
||||||
if those are in the specified `header` object or not.
|
if those are in the specified `header` object or not.
|
||||||
|
|
||||||
<a name="jws-create-header-map"></a>
|
<a name="jws-create-header-map"></a>
|
||||||
|
|
||||||
##### Header Map
|
##### Header Map
|
||||||
|
|
||||||
If you want to specify the entire header at once and you don't want to use `Jwts.header()`, you can use `JwtBuilder`
|
If you want to specify the entire header at once and you don't want to use `Jwts.header()`, you can use `JwtBuilder`
|
||||||
|
@ -728,29 +762,30 @@ String jws = Jwts.builder()
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
**NOTE**: Calling `setHeader` will overwrite any existing header name/value pairs with the same names that might have
|
**NOTE**: Calling `setHeader` will overwrite any existing header name/value pairs with the same names that might have
|
||||||
already been set. In all cases however, JJWT will still set (and overwrite) any `alg` and `zip` headers regardless
|
already been set. In all cases however, JJWT will still set (and overwrite) any `alg` and `zip` headers regardless
|
||||||
if those are in the specified `header` object or not.
|
if those are in the specified `header` object or not.
|
||||||
|
|
||||||
<a name="jws-create-claims"></a>
|
<a name="jws-create-claims"></a>
|
||||||
|
|
||||||
#### Claims
|
#### Claims
|
||||||
|
|
||||||
Claims are a JWT's 'body' and contain the information that the JWT creator wishes to present to the JWT recipient(s).
|
Claims are a JWT's 'body' and contain the information that the JWT creator wishes to present to the JWT recipient(s).
|
||||||
|
|
||||||
<a name="jws-create-claims-standard"></a>
|
<a name="jws-create-claims-standard"></a>
|
||||||
|
|
||||||
##### Standard Claims
|
##### Standard Claims
|
||||||
|
|
||||||
The `JwtBuilder` provides convenient setter methods for standard registered Claim names defined in the JWT
|
The `JwtBuilder` provides convenient setter methods for standard registered Claim names defined in the JWT
|
||||||
specification. They are:
|
specification. They are:
|
||||||
|
|
||||||
* `setIssuer`: sets the [`iss` (Issuer) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.1)
|
- `setIssuer`: sets the [`iss` (Issuer) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.1)
|
||||||
* `setSubject`: sets the [`sub` (Subject) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.2)
|
- `setSubject`: sets the [`sub` (Subject) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.2)
|
||||||
* `setAudience`: sets the [`aud` (Audience) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.3)
|
- `setAudience`: sets the [`aud` (Audience) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.3)
|
||||||
* `setExpiration`: sets the [`exp` (Expiration Time) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.4)
|
- `setExpiration`: sets the [`exp` (Expiration Time) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.4)
|
||||||
* `setNotBefore`: sets the [`nbf` (Not Before) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.5)
|
- `setNotBefore`: sets the [`nbf` (Not Before) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.5)
|
||||||
* `setIssuedAt`: sets the [`iat` (Issued At) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.6)
|
- `setIssuedAt`: sets the [`iat` (Issued At) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.6)
|
||||||
* `setId`: sets the [`jti` (JWT ID) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.7)
|
- `setId`: sets the [`jti` (JWT ID) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.7)
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
|
@ -770,6 +805,7 @@ String jws = Jwts.builder()
|
||||||
```
|
```
|
||||||
|
|
||||||
<a name="jws-create-claims-custom"></a>
|
<a name="jws-create-claims-custom"></a>
|
||||||
|
|
||||||
##### Custom Claims
|
##### Custom Claims
|
||||||
|
|
||||||
If you need to set one or more custom claims that don't match the standard setter method claims shown above, you
|
If you need to set one or more custom claims that don't match the standard setter method claims shown above, you
|
||||||
|
@ -791,6 +827,7 @@ Obviously, you do not need to call `claim` for any [standard claim name](#jws-cr
|
||||||
recommended instead to call the standard respective setter method as this enhances readability.
|
recommended instead to call the standard respective setter method as this enhances readability.
|
||||||
|
|
||||||
<a name="jws-create-claims-instance"></a>
|
<a name="jws-create-claims-instance"></a>
|
||||||
|
|
||||||
###### Claims Instance
|
###### Claims Instance
|
||||||
|
|
||||||
If you want to specify all claims at once, you can use the `Jwts.claims()` method and build up the claims
|
If you want to specify all claims at once, you can use the `Jwts.claims()` method and build up the claims
|
||||||
|
@ -814,6 +851,7 @@ String jws = Jwts.builder()
|
||||||
already been set.
|
already been set.
|
||||||
|
|
||||||
<a name="jws-create-claims-map"></a>
|
<a name="jws-create-claims-map"></a>
|
||||||
|
|
||||||
###### Claims Map
|
###### Claims Map
|
||||||
|
|
||||||
If you want to specify all claims at once and you don't want to use `Jwts.claims()`, you can use `JwtBuilder`
|
If you want to specify all claims at once and you don't want to use `Jwts.claims()`, you can use `JwtBuilder`
|
||||||
|
@ -835,6 +873,7 @@ String jws = Jwts.builder()
|
||||||
already been set.
|
already been set.
|
||||||
|
|
||||||
<a name="jws-create-key"></a>
|
<a name="jws-create-key"></a>
|
||||||
|
|
||||||
#### Signing Key
|
#### Signing Key
|
||||||
|
|
||||||
It is recommended that you specify the signing key by calling call the `JwtBuilder`'s `signWith` method and let JJWT
|
It is recommended that you specify the signing key by calling call the `JwtBuilder`'s `signWith` method and let JJWT
|
||||||
|
@ -865,6 +904,7 @@ The same selection logic applies for Elliptic Curve `PrivateKey`s.
|
||||||
`PublicKey` for signing with an `InvalidKeyException`.
|
`PublicKey` for signing with an `InvalidKeyException`.
|
||||||
|
|
||||||
<a name="jws-create-key-secret"></a>
|
<a name="jws-create-key-secret"></a>
|
||||||
|
|
||||||
##### SecretKey Formats
|
##### SecretKey Formats
|
||||||
|
|
||||||
If you want to sign a JWS using HMAC-SHA algorithms and you have a secret key `String` or
|
If you want to sign a JWS using HMAC-SHA algorithms and you have a secret key `String` or
|
||||||
|
@ -873,22 +913,24 @@ to convert it into a `SecretKey` instance to use as the `signWith` method argume
|
||||||
|
|
||||||
If your secret key is:
|
If your secret key is:
|
||||||
|
|
||||||
* An [encoded byte array](https://docs.oracle.com/javase/8/docs/api/java/security/Key.html#getEncoded--):
|
- An [encoded byte array](https://docs.oracle.com/javase/8/docs/api/java/security/Key.html#getEncoded--):
|
||||||
```java
|
```java
|
||||||
SecretKey key = Keys.hmacShaKeyFor(encodedKeyBytes);
|
SecretKey key = Keys.hmacShaKeyFor(encodedKeyBytes);
|
||||||
```
|
```
|
||||||
* A Base64-encoded string:
|
- A Base64-encoded string:
|
||||||
```java
|
```java
|
||||||
SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretString));
|
SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretString));
|
||||||
```
|
```
|
||||||
* A Base64URL-encoded string:
|
- A Base64URL-encoded string:
|
||||||
```java
|
```java
|
||||||
SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64URL.decode(secretString));
|
SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64URL.decode(secretString));
|
||||||
```
|
```
|
||||||
* A raw (non-encoded) string (e.g. a password String):
|
- A raw (non-encoded) string (e.g. a password String):
|
||||||
|
|
||||||
```java
|
```java
|
||||||
SecretKey key = Keys.hmacShaKeyFor(secretString.getBytes(StandardCharsets.UTF_8));
|
SecretKey key = Keys.hmacShaKeyFor(secretString.getBytes(StandardCharsets.UTF_8));
|
||||||
```
|
```
|
||||||
|
|
||||||
It is always incorrect to call `secretString.getBytes()` (without providing a charset).
|
It is always incorrect to call `secretString.getBytes()` (without providing a charset).
|
||||||
|
|
||||||
However, raw password strings like this, e.g. `correcthorsebatterystaple` should be avoided whenever possible
|
However, raw password strings like this, e.g. `correcthorsebatterystaple` should be avoided whenever possible
|
||||||
|
@ -896,6 +938,7 @@ If your secret key is:
|
||||||
If you are able, prefer creating a [new secure-random secret key](#jws-key-create-secret) instead.
|
If you are able, prefer creating a [new secure-random secret key](#jws-key-create-secret) instead.
|
||||||
|
|
||||||
<a name="jws-create-key-algoverride"></a>
|
<a name="jws-create-key-algoverride"></a>
|
||||||
|
|
||||||
##### SignatureAlgorithm Override
|
##### SignatureAlgorithm Override
|
||||||
|
|
||||||
In some specific cases, you might want to override JJWT's default selected algorithm for a given key.
|
In some specific cases, you might want to override JJWT's default selected algorithm for a given key.
|
||||||
|
@ -920,15 +963,17 @@ bits.
|
||||||
used for that algorithm according to the JWT specification requirements.**
|
used for that algorithm according to the JWT specification requirements.**
|
||||||
|
|
||||||
<a name="jws-create-compression"></a>
|
<a name="jws-create-compression"></a>
|
||||||
|
|
||||||
#### JWS Compression
|
#### JWS Compression
|
||||||
|
|
||||||
If your JWT claims set is large (contains a lot of data), and you are certain that JJWT will also be the same library
|
If your JWT claims set is large (contains a lot of data), and you are certain that JJWT will also be the same library
|
||||||
that reads/parses your JWS, you might want to compress the JWS to reduce its size. Note that this is
|
that reads/parses your JWS, you might want to compress the JWS to reduce its size. Note that this is
|
||||||
*not* a standard feature for JWS and is not likely to be supported by other JWT libraries.
|
_not_ a standard feature for JWS and is not likely to be supported by other JWT libraries.
|
||||||
|
|
||||||
Please see the main [Compression](#compression) section to see how to compress and decompress JWTs.
|
Please see the main [Compression](#compression) section to see how to compress and decompress JWTs.
|
||||||
|
|
||||||
<a name="jws-read"></a>
|
<a name="jws-read"></a>
|
||||||
|
|
||||||
### Reading a JWS
|
### Reading a JWS
|
||||||
|
|
||||||
You read (parse) a JWS as follows:
|
You read (parse) a JWS as follows:
|
||||||
|
@ -966,6 +1011,7 @@ catch (JwtException ex) { // (5)
|
||||||
available) as this guarantees the correct security model for parsing signed JWTs.
|
available) as this guarantees the correct security model for parsing signed JWTs.
|
||||||
|
|
||||||
<a name="jws-read-key"></a>
|
<a name="jws-read-key"></a>
|
||||||
|
|
||||||
#### Verification Key
|
#### Verification Key
|
||||||
|
|
||||||
The most important thing to do when reading a JWS is to specify the key to use to verify the JWS's
|
The most important thing to do when reading a JWS is to specify the key to use to verify the JWS's
|
||||||
|
@ -974,7 +1020,7 @@ discarded.
|
||||||
|
|
||||||
So which key do we use for verification?
|
So which key do we use for verification?
|
||||||
|
|
||||||
* If the jws was signed with a `SecretKey`, the same `SecretKey` should be specified on the `JwtParserBuilder`. For example:
|
- If the jws was signed with a `SecretKey`, the same `SecretKey` should be specified on the `JwtParserBuilder`. For example:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Jwts.parserBuilder()
|
Jwts.parserBuilder()
|
||||||
|
@ -984,7 +1030,8 @@ So which key do we use for verification?
|
||||||
.build()
|
.build()
|
||||||
.parseClaimsJws(jwsString);
|
.parseClaimsJws(jwsString);
|
||||||
```
|
```
|
||||||
* If the jws was signed with a `PrivateKey`, that key's corresponding `PublicKey` (not the `PrivateKey`) should be
|
|
||||||
|
- If the jws was signed with a `PrivateKey`, that key's corresponding `PublicKey` (not the `PrivateKey`) should be
|
||||||
specified on the `JwtParserBuilder`. For example:
|
specified on the `JwtParserBuilder`. For example:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
|
@ -1004,6 +1051,7 @@ In these cases, you can't call the `JwtParserBuilder`'s `setSigningKey` method w
|
||||||
to use a `SigningKeyResolver`, covered next.
|
to use a `SigningKeyResolver`, covered next.
|
||||||
|
|
||||||
<a name="jws-read-key-resolver"></a>
|
<a name="jws-read-key-resolver"></a>
|
||||||
|
|
||||||
##### Signing Key Resolver
|
##### Signing Key Resolver
|
||||||
|
|
||||||
If your application expects JWSs that can be signed with different keys, you won't call the `setSigningKey` method.
|
If your application expects JWSs that can be signed with different keys, you won't call the `setSigningKey` method.
|
||||||
|
@ -1088,13 +1136,14 @@ Finally remember that for HMAC algorithms, the returned verification key should
|
||||||
algorithms, the key returned should be a `PublicKey` (not a `PrivateKey`).
|
algorithms, the key returned should be a `PublicKey` (not a `PrivateKey`).
|
||||||
|
|
||||||
<a name="jws-read-claims"></a>
|
<a name="jws-read-claims"></a>
|
||||||
|
|
||||||
#### Claim Assertions
|
#### Claim Assertions
|
||||||
|
|
||||||
You can enforce that the JWS you are parsing conforms to expectations that you require and are important for your
|
You can enforce that the JWS you are parsing conforms to expectations that you require and are important for your
|
||||||
application.
|
application.
|
||||||
|
|
||||||
For example, let's say that you require that the JWS you are parsing has a specific `sub` (subject) value,
|
For example, let's say that you require that the JWS you are parsing has a specific `sub` (subject) value,
|
||||||
otherwise you may not trust the token. You can do that by using one of the various `require`* methods on the
|
otherwise you may not trust the token. You can do that by using one of the various `require`\* methods on the
|
||||||
`JwtParserBuilder`:
|
`JwtParserBuilder`:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
|
@ -1127,12 +1176,14 @@ try {
|
||||||
// the 'myfield' field was missing or did not have a 'myRequiredValue' value
|
// the 'myfield' field was missing or did not have a 'myRequiredValue' value
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
(or, again, you could catch either `MissingClaimException` or `IncorrectClaimException` instead).
|
(or, again, you could catch either `MissingClaimException` or `IncorrectClaimException` instead).
|
||||||
|
|
||||||
Please see the `JwtParserBuilder` class and/or JavaDoc for a full list of the various `require`* methods you may use for claims
|
Please see the `JwtParserBuilder` class and/or JavaDoc for a full list of the various `require`\* methods you may use for claims
|
||||||
assertions.
|
assertions.
|
||||||
|
|
||||||
<a name="jws-read-clock"></a>
|
<a name="jws-read-clock"></a>
|
||||||
|
|
||||||
#### Accounting for Clock Skew
|
#### Accounting for Clock Skew
|
||||||
|
|
||||||
When parsing a JWT, you might find that `exp` or `nbf` claim assertions fail (throw exceptions) because the clock on
|
When parsing a JWT, you might find that `exp` or `nbf` claim assertions fail (throw exceptions) because the clock on
|
||||||
|
@ -1141,7 +1192,7 @@ obvious problems since `exp` and `nbf` are time-based assertions, and clock time
|
||||||
assertions.
|
assertions.
|
||||||
|
|
||||||
You can account for these differences (usually no more than a few minutes) when parsing using the `JwtParserBuilder`'s
|
You can account for these differences (usually no more than a few minutes) when parsing using the `JwtParserBuilder`'s
|
||||||
`setAllowedClockSkewSeconds`. For example:
|
`setAllowedClockSkewSeconds`. For example:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
long seconds = 3 * 60; //3 minutes
|
long seconds = 3 * 60; //3 minutes
|
||||||
|
@ -1154,18 +1205,20 @@ Jwts.parserBuilder()
|
||||||
.build()
|
.build()
|
||||||
.parseClaimsJws(jwt);
|
.parseClaimsJws(jwt);
|
||||||
```
|
```
|
||||||
|
|
||||||
This ensures that clock differences between the machines can be ignored. Two or three minutes should be more than
|
This ensures that clock differences between the machines can be ignored. Two or three minutes should be more than
|
||||||
enough; it would be fairly strange if a production machine's clock was more than 5 minutes difference from most
|
enough; it would be fairly strange if a production machine's clock was more than 5 minutes difference from most
|
||||||
atomic clocks around the world.
|
atomic clocks around the world.
|
||||||
|
|
||||||
<a name="jws-read-clock-custom"></a>
|
<a name="jws-read-clock-custom"></a>
|
||||||
|
|
||||||
##### Custom Clock Support
|
##### Custom Clock Support
|
||||||
|
|
||||||
If the above `setAllowedClockSkewSeconds` isn't sufficient for your needs, the timestamps created
|
If the above `setAllowedClockSkewSeconds` isn't sufficient for your needs, the timestamps created
|
||||||
during parsing for timestamp comparisons can be obtained via a custom time source. Call the `JwtParserBuilder`'s `setClock`
|
during parsing for timestamp comparisons can be obtained via a custom time source. Call the `JwtParserBuilder`'s `setClock`
|
||||||
method with an implementation of the `io.jsonwebtoken.Clock` interface. For example:
|
method with an implementation of the `io.jsonwebtoken.Clock` interface. For example:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Clock clock = new MyClock();
|
Clock clock = new MyClock();
|
||||||
|
|
||||||
Jwts.parserBuilder().setClock(myClock) //... etc ...
|
Jwts.parserBuilder().setClock(myClock) //... etc ...
|
||||||
|
@ -1176,6 +1229,7 @@ as most would expect. However, supplying your own clock could be useful, especi
|
||||||
guarantee deterministic behavior.
|
guarantee deterministic behavior.
|
||||||
|
|
||||||
<a name="jws-read-decompression"></a>
|
<a name="jws-read-decompression"></a>
|
||||||
|
|
||||||
#### 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 `JwtParserBuilder`
|
If you used JJWT to compress a JWS and you used a custom compression algorithm, you will need to tell the `JwtParserBuilder`
|
||||||
|
@ -1186,6 +1240,7 @@ Please see the [Compression](#compression) section below to see how to decompres
|
||||||
<!-- TODO: ## Encrypted JWTs -->
|
<!-- TODO: ## Encrypted JWTs -->
|
||||||
|
|
||||||
<a name="compression"></a>
|
<a name="compression"></a>
|
||||||
|
|
||||||
## Compression
|
## Compression
|
||||||
|
|
||||||
**The JWT specification only standardizes this feature for JWEs (Encrypted JWTs) and not JWSs (Signed JWTs), however
|
**The JWT specification only standardizes this feature for JWEs (Encrypted JWTs) and not JWSs (Signed JWTs), however
|
||||||
|
@ -1214,6 +1269,7 @@ If you use the `DEFLATE` or `GZIP` Compression Codecs - that's it, you're done.
|
||||||
parsing or configure the `JwtParser` for compression - JJWT will automatically decompress the body as expected.
|
parsing or configure the `JwtParser` for compression - JJWT will automatically decompress the body as expected.
|
||||||
|
|
||||||
<a name="compression-custom"></a>
|
<a name="compression-custom"></a>
|
||||||
|
|
||||||
### Custom Compression Codec
|
### Custom Compression Codec
|
||||||
|
|
||||||
If however, you used your own custom compression codec when creating the JWT (via `JwtBuilder` `compressWith`), then
|
If however, you used your own custom compression codec when creating the JWT (via `JwtBuilder` `compressWith`), then
|
||||||
|
@ -1248,6 +1304,7 @@ public class MyCompressionCodecResolver implements CompressionCodecResolver {
|
||||||
```
|
```
|
||||||
|
|
||||||
<a name="json"></a>
|
<a name="json"></a>
|
||||||
|
|
||||||
## JSON Support
|
## JSON Support
|
||||||
|
|
||||||
A `JwtBuilder` will serialize the `Header` and `Claims` maps (and potentially any Java objects they
|
A `JwtBuilder` will serialize the `Header` and `Claims` maps (and potentially any Java objects they
|
||||||
|
@ -1260,16 +1317,14 @@ They are checked in order, and the first one found is used:
|
||||||
|
|
||||||
1. Jackson: This will automatically be used if you specify `io.jsonwebtoken:jjwt-jackson` as a project runtime
|
1. Jackson: This will automatically be used if you specify `io.jsonwebtoken:jjwt-jackson` as a project runtime
|
||||||
dependency. Jackson supports POJOs as claims with full marshaling/unmarshaling as necessary.
|
dependency. Jackson supports POJOs as claims with full marshaling/unmarshaling as necessary.
|
||||||
|
|
||||||
2. Gson: This will automatically be used if you specify `io.jsonwebtoken:jjwt-gson` as a project runtime dependency.
|
2. Gson: This will automatically be used if you specify `io.jsonwebtoken:jjwt-gson` as a project runtime dependency.
|
||||||
Gson also supports POJOs as claims with full marshaling/unmarshaling as necessary.
|
Gson also supports POJOs as claims with full marshaling/unmarshaling as necessary.
|
||||||
|
|
||||||
3. JSON-Java (`org.json`): This will be used automatically if you specify `io.jsonwebtoken:jjwt-orgjson` as a
|
3. JSON-Java (`org.json`): This will be used automatically if you specify `io.jsonwebtoken:jjwt-orgjson` as a
|
||||||
project runtime dependency.
|
project runtime dependency.
|
||||||
|
|
||||||
**NOTE:** `org.json` APIs are natively enabled in Android environments so this is the recommended JSON processor for
|
**NOTE:** `org.json` APIs are natively enabled in Android environments so this is the recommended JSON processor for
|
||||||
Android applications _unless_ you want to use POJOs as claims. The `org.json` library supports simple
|
Android applications _unless_ you want to use POJOs as claims. The `org.json` library supports simple
|
||||||
Object-to-JSON marshaling, but it *does not* support JSON-to-Object unmarshalling.
|
Object-to-JSON marshaling, but it _does not_ support JSON-to-Object unmarshalling.
|
||||||
|
|
||||||
**If you want to use POJOs as claim values, use either the `io.jsonwebtoken:jjwt-jackson` or
|
**If you want to use POJOs as claim values, use either the `io.jsonwebtoken:jjwt-jackson` or
|
||||||
`io.jsonwebtoken:jjwt-gson` dependency** (or implement your own Serializer and Deserializer if desired). **But beware**,
|
`io.jsonwebtoken:jjwt-gson` dependency** (or implement your own Serializer and Deserializer if desired). **But beware**,
|
||||||
|
@ -1277,6 +1332,7 @@ Jackson will force a sizable (> 1 MB) dependency to an Android application thus
|
||||||
mobile users.
|
mobile users.
|
||||||
|
|
||||||
<a name="json-custom"></a>
|
<a name="json-custom"></a>
|
||||||
|
|
||||||
### Custom JSON Processor
|
### Custom JSON Processor
|
||||||
|
|
||||||
If you don't want to use JJWT's runtime dependency approach, or just want to customize how JSON serialization and
|
If you don't want to use JJWT's runtime dependency approach, or just want to customize how JSON serialization and
|
||||||
|
@ -1308,6 +1364,7 @@ Jwts.parserBuilder()
|
||||||
```
|
```
|
||||||
|
|
||||||
<a name="json-jackson"></a>
|
<a name="json-jackson"></a>
|
||||||
|
|
||||||
### Jackson JSON Processor
|
### Jackson JSON Processor
|
||||||
|
|
||||||
If you want to use Jackson for JSON processing, just including the `io.jsonwebtoken:jjwt-jackson` dependency as a
|
If you want to use Jackson for JSON processing, just including the `io.jsonwebtoken:jjwt-jackson` dependency as a
|
||||||
|
@ -1340,6 +1397,8 @@ scope which is the typical JJWT default). That is:
|
||||||
```groovy
|
```groovy
|
||||||
dependencies {
|
dependencies {
|
||||||
compile 'io.jsonwebtoken:jjwt-jackson:0.11.2'
|
compile 'io.jsonwebtoken:jjwt-jackson:0.11.2'
|
||||||
|
// if you are using gradle 7+, you need to use the implemetation dependency instead.
|
||||||
|
implementation 'io.jsonwebtoken:jjwt-jackson:0.11.2'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1368,6 +1427,7 @@ Jwts.parserBuilder()
|
||||||
```
|
```
|
||||||
|
|
||||||
<a name="json-jackson-custom-types"></a>
|
<a name="json-jackson-custom-types"></a>
|
||||||
|
|
||||||
#### Parsing of Custom Claim Types
|
#### Parsing of Custom Claim Types
|
||||||
|
|
||||||
By default JJWT will only convert simple claim types: String, Date, Long, Integer, Short and Byte. If you need to deserialize other types you can configure the `JacksonDeserializer` by passing a `Map` of claim names to types in through a constructor. For example:
|
By default JJWT will only convert simple claim types: String, Date, Long, Integer, Short and Byte. If you need to deserialize other types you can configure the `JacksonDeserializer` by passing a `Map` of claim names to types in through a constructor. For example:
|
||||||
|
@ -1410,6 +1470,7 @@ consequences for a shared `ObjectMapper` instance. This should work for most app
|
||||||
parsing options, [configure the mapper directly](#json-jackson).
|
parsing options, [configure the mapper directly](#json-jackson).
|
||||||
|
|
||||||
<a name="json-gson"></a>
|
<a name="json-gson"></a>
|
||||||
|
|
||||||
### Gson JSON Processor
|
### Gson JSON Processor
|
||||||
|
|
||||||
If you want to use Gson for JSON processing, just including the `io.jsonwebtoken:jjwt-gson` dependency as a
|
If you want to use Gson for JSON processing, just including the `io.jsonwebtoken:jjwt-gson` dependency as a
|
||||||
|
@ -1448,6 +1509,8 @@ scope which is the typical JJWT default). That is:
|
||||||
```groovy
|
```groovy
|
||||||
dependencies {
|
dependencies {
|
||||||
compile 'io.jsonwebtoken:jjwt-gson:0.11.2'
|
compile 'io.jsonwebtoken:jjwt-gson:0.11.2'
|
||||||
|
// if you are using gradle 7+, you need to use the implemetation dependency instead.
|
||||||
|
implementation 'io.jsonwebtoken:jjwt-gson:0.11.2'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1477,6 +1540,7 @@ Jwts.parser()
|
||||||
```
|
```
|
||||||
|
|
||||||
<a name="base64"></a>
|
<a name="base64"></a>
|
||||||
|
|
||||||
## Base64 Support
|
## Base64 Support
|
||||||
|
|
||||||
JJWT uses a very fast pure-Java [Base64](https://tools.ietf.org/html/rfc4648) codec for Base64 and
|
JJWT uses a very fast pure-Java [Base64](https://tools.ietf.org/html/rfc4648) codec for Base64 and
|
||||||
|
@ -1487,15 +1551,16 @@ utility classes.
|
||||||
|
|
||||||
`io.jsonwebtoken.io.Encoders`:
|
`io.jsonwebtoken.io.Encoders`:
|
||||||
|
|
||||||
* `BASE64` is an RFC 4648 [Base64](https://tools.ietf.org/html/rfc4648#section-4) encoder
|
- `BASE64` is an RFC 4648 [Base64](https://tools.ietf.org/html/rfc4648#section-4) encoder
|
||||||
* `BASE64URL` is an RFC 4648 [Base64URL](https://tools.ietf.org/html/rfc4648#section-5) encoder
|
- `BASE64URL` is an RFC 4648 [Base64URL](https://tools.ietf.org/html/rfc4648#section-5) encoder
|
||||||
|
|
||||||
`io.jsonwebtoken.io.Decoders`:
|
`io.jsonwebtoken.io.Decoders`:
|
||||||
|
|
||||||
* `BASE64` is an RFC 4648 [Base64](https://tools.ietf.org/html/rfc4648#section-4) decoder
|
- `BASE64` is an RFC 4648 [Base64](https://tools.ietf.org/html/rfc4648#section-4) decoder
|
||||||
* `BASE64URL` is an RFC 4648 [Base64URL](https://tools.ietf.org/html/rfc4648#section-5) decoder
|
- `BASE64URL` is an RFC 4648 [Base64URL](https://tools.ietf.org/html/rfc4648#section-5) decoder
|
||||||
|
|
||||||
<a name="base64-security"></a>
|
<a name="base64-security"></a>
|
||||||
|
|
||||||
### Understanding Base64 in Security Contexts
|
### Understanding Base64 in Security Contexts
|
||||||
|
|
||||||
All cryptographic operations, like encryption and message digest calculations, result in binary data - raw byte arrays.
|
All cryptographic operations, like encryption and message digest calculations, result in binary data - raw byte arrays.
|
||||||
|
@ -1511,10 +1576,11 @@ into the original raw byte arrays for decryption or signature verification as ne
|
||||||
That's nice and convenient, but there are two very important properties of Base64 (and Base64URL) text strings that
|
That's nice and convenient, but there are two very important properties of Base64 (and Base64URL) text strings that
|
||||||
are critical to remember when they are used in security scenarios like with JWTs:
|
are critical to remember when they are used in security scenarios like with JWTs:
|
||||||
|
|
||||||
* [Base64 is not encryption](#base64-not-encryption)
|
- [Base64 is not encryption](#base64-not-encryption)
|
||||||
* [Changing Base64 characters](#base64-changing-characters) **does not automatically invalidate data**.
|
- [Changing Base64 characters](#base64-changing-characters) **does not automatically invalidate data**.
|
||||||
|
|
||||||
<a name="base64-not-encryption"></a>
|
<a name="base64-not-encryption"></a>
|
||||||
|
|
||||||
#### Base64 is not encryption
|
#### Base64 is not encryption
|
||||||
|
|
||||||
Base64-encoded text is _not_ encrypted.
|
Base64-encoded text is _not_ encrypted.
|
||||||
|
@ -1534,6 +1600,7 @@ After Base64-encoding data into a string, it is possible to then encrypt the str
|
||||||
eyes if desired, but this is different. Encryption is not encoding. They are separate concepts.
|
eyes if desired, but this is different. Encryption is not encoding. They are separate concepts.
|
||||||
|
|
||||||
<a name="base64-changing-characters"></a>
|
<a name="base64-changing-characters"></a>
|
||||||
|
|
||||||
#### Changing Base64 Characters
|
#### Changing Base64 Characters
|
||||||
|
|
||||||
In an effort to see if signatures or encryption is truly validated correctly, some try to edit a JWT
|
In an effort to see if signatures or encryption is truly validated correctly, some try to edit a JWT
|
||||||
|
@ -1554,19 +1621,21 @@ and [JJWT issue comments](https://github.com/jwtk/jjwt/issues/211#issuecomment-2
|
||||||
Here's one [good answer](https://stackoverflow.com/questions/29941270/why-do-base64-decode-produce-same-byte-array-for-different-strings):
|
Here's one [good answer](https://stackoverflow.com/questions/29941270/why-do-base64-decode-produce-same-byte-array-for-different-strings):
|
||||||
|
|
||||||
> Remember that Base64 encodes each 8 bit entity into 6 bit chars. The resulting string then needs exactly
|
> Remember that Base64 encodes each 8 bit entity into 6 bit chars. The resulting string then needs exactly
|
||||||
> 11 * 8 / 6 bytes, or 14 2/3 chars. But you can't write partial characters. Only the first 4 bits (or 2/3 of the
|
> 11 \* 8 / 6 bytes, or 14 2/3 chars. But you can't write partial characters. Only the first 4 bits (or 2/3 of the
|
||||||
> last char) are significant. The last two bits are not decoded. Thus all of:
|
> last char) are significant. The last two bits are not decoded. Thus all of:
|
||||||
>
|
>
|
||||||
> dGVzdCBzdHJpbmo
|
> dGVzdCBzdHJpbmo
|
||||||
> dGVzdCBzdHJpbmp
|
> dGVzdCBzdHJpbmp
|
||||||
> dGVzdCBzdHJpbmq
|
> dGVzdCBzdHJpbmq
|
||||||
> dGVzdCBzdHJpbmr
|
> dGVzdCBzdHJpbmr
|
||||||
|
>
|
||||||
> All decode to the same 11 bytes (116, 101, 115, 116, 32, 115, 116, 114, 105, 110, 106).
|
> All decode to the same 11 bytes (116, 101, 115, 116, 32, 115, 116, 114, 105, 110, 106).
|
||||||
|
|
||||||
As you can see by the above 4 examples, they all decode to the same exact 11 bytes. So just changing one or two
|
As you can see by the above 4 examples, they all decode to the same exact 11 bytes. So just changing one or two
|
||||||
characters at the end of a Base64 string may not work and can often result in an invalid test.
|
characters at the end of a Base64 string may not work and can often result in an invalid test.
|
||||||
|
|
||||||
<a name="base64-invalid-characters"></a>
|
<a name="base64-invalid-characters"></a>
|
||||||
|
|
||||||
##### Adding Invalid Characters
|
##### Adding Invalid Characters
|
||||||
|
|
||||||
JJWT's default Base64/Base64URL decoders automatically ignore illegal Base64 characters located in the beginning and
|
JJWT's default Base64/Base64URL decoders automatically ignore illegal Base64 characters located in the beginning and
|
||||||
|
@ -1585,8 +1654,8 @@ byte array is changed, then yes, JJWT's cryptographic assertions will definitely
|
||||||
To help understand JJWT's approach, we have to remember why signatures exist. From our documentation above on
|
To help understand JJWT's approach, we have to remember why signatures exist. From our documentation above on
|
||||||
[signing JWTs](#jws):
|
[signing JWTs](#jws):
|
||||||
|
|
||||||
> * guarantees it was created by someone we know (it is authentic), as well as
|
> - guarantees it was created by someone we know (it is authentic), as well as
|
||||||
> * guarantees that no-one has manipulated or changed it after it was created (its integrity is maintained).
|
> - guarantees that no-one has manipulated or changed it after it was created (its integrity is maintained).
|
||||||
|
|
||||||
Just prepending or appending invalid text to try to 'trick' the algorithm doesn't change the integrity of the
|
Just prepending or appending invalid text to try to 'trick' the algorithm doesn't change the integrity of the
|
||||||
underlying claims or signature byte arrays, nor the authenticity of the claims byte array, because those byte
|
underlying claims or signature byte arrays, nor the authenticity of the claims byte array, because those byte
|
||||||
|
@ -1596,6 +1665,7 @@ Please see [JJWT Issue #518](https://github.com/jwtk/jjwt/issues/518) and its re
|
||||||
information.
|
information.
|
||||||
|
|
||||||
<a name="base64-custom"></a>
|
<a name="base64-custom"></a>
|
||||||
|
|
||||||
### Custom Base64
|
### Custom Base64
|
||||||
|
|
||||||
If for some reason you want to specify your own Base64Url encoder and decoder, you can use the `JwtBuilder`
|
If for some reason you want to specify your own Base64Url encoder and decoder, you can use the `JwtBuilder`
|
||||||
|
@ -1637,6 +1707,7 @@ Jwts.parserBuilder()
|
||||||
Maintained by Les Hazlewood & [Okta](https://okta.com/)
|
Maintained by Les Hazlewood & [Okta](https://okta.com/)
|
||||||
|
|
||||||
<a name="license"></a>
|
<a name="license"></a>
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is open-source via the [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0).
|
This project is open-source via the [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
|
Loading…
Reference in New Issue