mirror of https://github.com/jwtk/jjwt.git
Revert "update readme.md: installation in gradle 7+"
This reverts commit 371577df98
.
This commit is contained in:
parent
915a3753c4
commit
861ec66832
365
README.md
365
README.md
|
@ -23,121 +23,117 @@ 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)
|
||||
<!-- * [Error Handling](#jws-read-errors) -->
|
||||
- [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)
|
||||
|
||||
<a name="features"></a>
|
||||
|
||||
## 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
|
||||
* 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-256<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>
|
||||
* 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-256<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>
|
||||
|
||||
<sup>1. Requires JDK 11 or a compatible JCA Provider (like BouncyCastle) in the runtime classpath.</sup>
|
||||
- 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...
|
||||
* 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...
|
||||
|
||||
<a name="features-unsupported"></a>
|
||||
|
||||
### 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!
|
||||
|
||||
<a name="community"></a>
|
||||
|
||||
## Community
|
||||
|
||||
<a name="help"></a>
|
||||
|
||||
### Getting Help
|
||||
|
||||
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.
|
||||
|
||||
<a name="help-questions"></a>
|
||||
|
||||
#### Questions
|
||||
|
||||
If the documentation or the API JavaDoc isn't sufficient, and you either have usability questions or are confused
|
||||
|
@ -161,7 +157,6 @@ described above.
|
|||
**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>
|
||||
|
||||
#### Bugs and Feature Requests
|
||||
|
||||
If you do not have a usability question and believe you have a legitimate bug or feature request,
|
||||
|
@ -171,11 +166,9 @@ If you feel like you'd like to help fix a bug or implement the new feature yours
|
|||
section next before starting any work.
|
||||
|
||||
<a name="contributing"></a>
|
||||
|
||||
### Contributing
|
||||
|
||||
<a name="contributing-pull-requests"></a>
|
||||
|
||||
#### Pull Requests
|
||||
|
||||
Simple Pull Requests that fix anything other than JJWT core code (documentation, JavaDoc, typos, test cases, etc) are
|
||||
|
@ -194,7 +187,6 @@ So, please [create a new JJWT issue](https://github.com/jwtk/jjwt/issues/new) fi
|
|||
(or how) a PR is warranted. Thank you!
|
||||
|
||||
<a name="contributing-help-wanted"></a>
|
||||
|
||||
#### Help Wanted
|
||||
|
||||
If you would like to help, but don't know where to start, please visit the
|
||||
|
@ -206,7 +198,6 @@ appreciated based on the above caveats concerning [contributing pull reqeuests](
|
|||
to discuss or ask questions first if you're not sure. :)
|
||||
|
||||
<a name="overview"></a>
|
||||
|
||||
## 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.
|
||||
|
@ -234,7 +225,6 @@ If you pass the first two parts through a base 64 url decoder, you'll get the fo
|
|||
clarity):
|
||||
|
||||
`header`
|
||||
|
||||
```
|
||||
{
|
||||
"alg": "HS256"
|
||||
|
@ -242,7 +232,6 @@ clarity):
|
|||
```
|
||||
|
||||
`body`
|
||||
|
||||
```
|
||||
{
|
||||
"sub": "Joe"
|
||||
|
@ -258,7 +247,6 @@ 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.
|
||||
|
||||
<a name="install"></a>
|
||||
|
||||
## Installation
|
||||
|
||||
Use your favorite Maven-compatible build tool to pull the dependencies from Maven Central.
|
||||
|
@ -267,13 +255,11 @@ The dependencies could differ slightly if you are working with a [JDK project](#
|
|||
[Android project](#install-android).
|
||||
|
||||
<a name="install-jdk"></a>
|
||||
|
||||
### JDK Projects
|
||||
|
||||
If you're building a (non-Android) JDK project, you will want to define the following dependencies:
|
||||
|
||||
<a name="install-jdk-maven"></a>
|
||||
|
||||
#### Maven
|
||||
|
||||
```xml
|
||||
|
@ -307,7 +293,6 @@ If you're building a (non-Android) JDK project, you will want to define the foll
|
|||
```
|
||||
|
||||
<a name="install-jdk-gradle"></a>
|
||||
|
||||
#### Gradle
|
||||
|
||||
```groovy
|
||||
|
@ -317,20 +302,15 @@ dependencies {
|
|||
// Uncomment the next line if you want to use RSASSA-PSS (PS256, PS384, PS512) algorithms:
|
||||
//'org.bouncycastle:bcprov-jdk15on:1.60',
|
||||
'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>
|
||||
|
||||
### Android Projects
|
||||
|
||||
Android projects will want to define the following dependencies and Proguard exclusions:
|
||||
|
||||
<a name="install-android-dependencies"></a>
|
||||
|
||||
#### Dependencies
|
||||
|
||||
Add the dependencies to your project:
|
||||
|
@ -348,7 +328,6 @@ dependencies {
|
|||
```
|
||||
|
||||
<a name="install-android-proguard"></a>
|
||||
|
||||
#### Proguard
|
||||
|
||||
You can use the following [Android Proguard](https://developer.android.com/studio/build/shrink-code) exclusion rules:
|
||||
|
@ -366,7 +345,6 @@ You can use the following [Android Proguard](https://developer.android.com/studi
|
|||
```
|
||||
|
||||
<a name="install-understandingdependencies"></a>
|
||||
|
||||
### Understanding JJWT Dependencies
|
||||
|
||||
Notice the above dependency declarations all have only one compile-time dependency and the rest are declared as
|
||||
|
@ -388,7 +366,6 @@ implementations whenever and however necessary. This helps us implement features
|
|||
you more quickly and efficiently.
|
||||
|
||||
<a name="quickstart"></a>
|
||||
|
||||
## 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:
|
||||
|
@ -410,10 +387,10 @@ How easy was that!?
|
|||
|
||||
In this case, we are:
|
||||
|
||||
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
|
||||
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'.
|
||||
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
|
||||
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'.
|
||||
|
||||
The resultant `jws` String looks like this:
|
||||
|
||||
|
@ -451,7 +428,6 @@ try {
|
|||
```
|
||||
|
||||
<a name="jws"></a>
|
||||
|
||||
## Signed JWTs
|
||||
|
||||
The JWT specification provides for the ability to
|
||||
|
@ -468,7 +444,6 @@ 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:
|
||||
|
||||
**header**
|
||||
|
||||
```
|
||||
{
|
||||
"alg": "HS256"
|
||||
|
@ -476,7 +451,6 @@ So how is a JWT signed? Let's walk through it with some easy-to-read pseudocode:
|
|||
```
|
||||
|
||||
**body**
|
||||
|
||||
```
|
||||
{
|
||||
"sub": "Joe"
|
||||
|
@ -518,6 +492,7 @@ So how is a JWT signed? Let's walk through it with some easy-to-read pseudocode:
|
|||
String jws = concatenated + '.' + base64URLEncode( signature )
|
||||
```
|
||||
|
||||
|
||||
And there you have it, the final `jws` String looks like this:
|
||||
|
||||
```
|
||||
|
@ -535,24 +510,23 @@ Keys, specifically as they relate to the JWT specifications. Understanding them
|
|||
JWS properly.
|
||||
|
||||
<a name="jws-key"></a>
|
||||
|
||||
### Signature Algorithms Keys
|
||||
|
||||
The JWT specification identifies 12 standard signature algorithms - 3 secret key algorithms and 9 asymmetric
|
||||
key algorithms - identified by the following names:
|
||||
|
||||
- `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-256
|
||||
- `PS384`: RSASSA-PSS using SHA-384 and MGF1 with SHA-384
|
||||
- `PS512`: RSASSA-PSS using SHA-512 and MGF1 with SHA-512
|
||||
* `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-256
|
||||
* `PS384`: RSASSA-PSS using SHA-384 and MGF1 with SHA-384
|
||||
* `PS512`: RSASSA-PSS using SHA-512 and MGF1 with SHA-512
|
||||
|
||||
These are all represented in the `io.jsonwebtoken.SignatureAlgorithm` enum.
|
||||
|
||||
|
@ -572,23 +546,22 @@ one wants completely insecure JWTs, right? Neither would we.
|
|||
So what are the requirements?
|
||||
|
||||
<a name="jws-key-hmacsha"></a>
|
||||
|
||||
#### HMAC-SHA
|
||||
|
||||
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).
|
||||
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.
|
||||
- `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.
|
||||
|
||||
- `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.
|
||||
|
||||
<a name="jws-key-rsa"></a>
|
||||
|
||||
#### RSA
|
||||
|
||||
JWT RSA signature algorithms `RS256`, `RS384`, `RS512`, `PS256`, `PS384` and `PS512` all require a minimum key length
|
||||
|
@ -599,28 +572,27 @@ 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
|
||||
recoommends that you use:
|
||||
|
||||
- at least 2048 bit keys with `RS256` and `PS256`
|
||||
- at least 3072 bit keys with `RS384` and `PS384`
|
||||
- at least 4096 bit keys with `RS512` and `PS512`
|
||||
* at least 2048 bit keys with `RS256` and `PS256`
|
||||
* at least 3072 bit keys with `RS384` and `PS384`
|
||||
* at least 4096 bit keys with `RS512` and `PS512`
|
||||
|
||||
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.
|
||||
|
||||
<a name="jws-key-ecdsa"></a>
|
||||
|
||||
#### Elliptic Curve
|
||||
|
||||
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
|
||||
`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.
|
||||
- `ES384` requires that you use a private key that is at least 384 bits (48 bytes) long.
|
||||
* `ES256` requires that you use a private key that is at least 256 bits (32 bytes) long.
|
||||
|
||||
- `ES512` requires that you use a private key that is at least 512 bits (64 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.
|
||||
|
||||
<a name="jws-key-create"></a>
|
||||
|
||||
#### Creating Safe Keys
|
||||
|
||||
If you don't want to think about bit length requirements or just want to make your life easier, JJWT has
|
||||
|
@ -628,7 +600,6 @@ provided the `io.jsonwebtoken.security.Keys` utility class that can generate suf
|
|||
JWT signature algorithm you might want to use.
|
||||
|
||||
<a name="jws-key-create-secret"></a>
|
||||
|
||||
##### Secret Keys
|
||||
|
||||
If you want to generate a sufficiently strong `SecretKey` for use with the JWT HMAC-SHA algorithms, use the
|
||||
|
@ -652,7 +623,6 @@ Ensure you save the resulting `secretString` somewhere safe -
|
|||
further encrypt it, etc, before saving to disk (for example).
|
||||
|
||||
<a name="jws-key-create-asym"></a>
|
||||
|
||||
##### Asymmetric Keys
|
||||
|
||||
If you want to generate sufficiently strong Elliptic Curve or RSA asymmetric key pairs for use with JWT ECDSA or RSA
|
||||
|
@ -671,7 +641,6 @@ the [Installation](#Installation) section to see how to enable BouncyCastle. All
|
|||
supported by the JDK.
|
||||
|
||||
<a name="jws-create"></a>
|
||||
|
||||
### Creating a JWS
|
||||
|
||||
You create a JWS as follows:
|
||||
|
@ -694,7 +663,6 @@ String jws = Jwts.builder() // (1)
|
|||
```
|
||||
|
||||
<a name="jws-create-header"></a>
|
||||
|
||||
#### Header Parameters
|
||||
|
||||
A JWT Header provides metadata about the contents, format and cryptographic operations relevant to the JWT's Claims.
|
||||
|
@ -719,7 +687,6 @@ potentially overwriting any existing identically-named key/value pair.
|
|||
depending on the signature algorithm or compression algorithm used.
|
||||
|
||||
<a name="jws-create-header-instance"></a>
|
||||
|
||||
##### Header Instance
|
||||
|
||||
If you want to specify the entire header at once, you can use the `Jwts.header()` method and build up the header
|
||||
|
@ -744,7 +711,6 @@ already been set. In all cases however, JJWT will still set (and overwrite) any
|
|||
if those are in the specified `header` object or not.
|
||||
|
||||
<a name="jws-create-header-map"></a>
|
||||
|
||||
##### 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`
|
||||
|
@ -762,30 +728,29 @@ String jws = Jwts.builder()
|
|||
|
||||
```
|
||||
|
||||
|
||||
**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
|
||||
if those are in the specified `header` object or not.
|
||||
|
||||
<a name="jws-create-claims"></a>
|
||||
|
||||
#### Claims
|
||||
|
||||
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>
|
||||
|
||||
##### Standard Claims
|
||||
|
||||
The `JwtBuilder` provides convenient setter methods for standard registered Claim names defined in the JWT
|
||||
specification. They are:
|
||||
|
||||
- `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)
|
||||
- `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)
|
||||
- `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)
|
||||
- `setId`: sets the [`jti` (JWT ID) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.7)
|
||||
* `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)
|
||||
* `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)
|
||||
* `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)
|
||||
* `setId`: sets the [`jti` (JWT ID) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.7)
|
||||
|
||||
For example:
|
||||
|
||||
|
@ -805,7 +770,6 @@ String jws = Jwts.builder()
|
|||
```
|
||||
|
||||
<a name="jws-create-claims-custom"></a>
|
||||
|
||||
##### Custom Claims
|
||||
|
||||
If you need to set one or more custom claims that don't match the standard setter method claims shown above, you
|
||||
|
@ -827,7 +791,6 @@ 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.
|
||||
|
||||
<a name="jws-create-claims-instance"></a>
|
||||
|
||||
###### Claims Instance
|
||||
|
||||
If you want to specify all claims at once, you can use the `Jwts.claims()` method and build up the claims
|
||||
|
@ -851,7 +814,6 @@ String jws = Jwts.builder()
|
|||
already been set.
|
||||
|
||||
<a name="jws-create-claims-map"></a>
|
||||
|
||||
###### Claims Map
|
||||
|
||||
If you want to specify all claims at once and you don't want to use `Jwts.claims()`, you can use `JwtBuilder`
|
||||
|
@ -873,7 +835,6 @@ String jws = Jwts.builder()
|
|||
already been set.
|
||||
|
||||
<a name="jws-create-key"></a>
|
||||
|
||||
#### Signing Key
|
||||
|
||||
It is recommended that you specify the signing key by calling call the `JwtBuilder`'s `signWith` method and let JJWT
|
||||
|
@ -904,7 +865,6 @@ The same selection logic applies for Elliptic Curve `PrivateKey`s.
|
|||
`PublicKey` for signing with an `InvalidKeyException`.
|
||||
|
||||
<a name="jws-create-key-secret"></a>
|
||||
|
||||
##### SecretKey Formats
|
||||
|
||||
If you want to sign a JWS using HMAC-SHA algorithms and you have a secret key `String` or
|
||||
|
@ -913,24 +873,22 @@ to convert it into a `SecretKey` instance to use as the `signWith` method argume
|
|||
|
||||
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
|
||||
SecretKey key = Keys.hmacShaKeyFor(encodedKeyBytes);
|
||||
```
|
||||
- A Base64-encoded string:
|
||||
* A Base64-encoded string:
|
||||
```java
|
||||
SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretString));
|
||||
```
|
||||
- A Base64URL-encoded string:
|
||||
* A Base64URL-encoded string:
|
||||
```java
|
||||
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
|
||||
SecretKey key = Keys.hmacShaKeyFor(secretString.getBytes(StandardCharsets.UTF_8));
|
||||
```
|
||||
|
||||
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
|
||||
|
@ -938,7 +896,6 @@ If your secret key is:
|
|||
If you are able, prefer creating a [new secure-random secret key](#jws-key-create-secret) instead.
|
||||
|
||||
<a name="jws-create-key-algoverride"></a>
|
||||
|
||||
##### SignatureAlgorithm Override
|
||||
|
||||
In some specific cases, you might want to override JJWT's default selected algorithm for a given key.
|
||||
|
@ -963,17 +920,15 @@ bits.
|
|||
used for that algorithm according to the JWT specification requirements.**
|
||||
|
||||
<a name="jws-create-compression"></a>
|
||||
|
||||
#### 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
|
||||
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.
|
||||
|
||||
<a name="jws-read"></a>
|
||||
|
||||
### Reading a JWS
|
||||
|
||||
You read (parse) a JWS as follows:
|
||||
|
@ -1011,7 +966,6 @@ catch (JwtException ex) { // (5)
|
|||
available) as this guarantees the correct security model for parsing signed JWTs.
|
||||
|
||||
<a name="jws-read-key"></a>
|
||||
|
||||
#### Verification Key
|
||||
|
||||
The most important thing to do when reading a JWS is to specify the key to use to verify the JWS's
|
||||
|
@ -1020,7 +974,7 @@ discarded.
|
|||
|
||||
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
|
||||
Jwts.parserBuilder()
|
||||
|
@ -1030,8 +984,7 @@ So which key do we use for verification?
|
|||
.build()
|
||||
.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:
|
||||
|
||||
```java
|
||||
|
@ -1051,7 +1004,6 @@ In these cases, you can't call the `JwtParserBuilder`'s `setSigningKey` method w
|
|||
to use a `SigningKeyResolver`, covered next.
|
||||
|
||||
<a name="jws-read-key-resolver"></a>
|
||||
|
||||
##### Signing Key Resolver
|
||||
|
||||
If your application expects JWSs that can be signed with different keys, you won't call the `setSigningKey` method.
|
||||
|
@ -1136,14 +1088,13 @@ Finally remember that for HMAC algorithms, the returned verification key should
|
|||
algorithms, the key returned should be a `PublicKey` (not a `PrivateKey`).
|
||||
|
||||
<a name="jws-read-claims"></a>
|
||||
|
||||
#### Claim Assertions
|
||||
|
||||
You can enforce that the JWS you are parsing conforms to expectations that you require and are important for your
|
||||
application.
|
||||
|
||||
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`:
|
||||
|
||||
```java
|
||||
|
@ -1176,14 +1127,12 @@ try {
|
|||
// the 'myfield' field was missing or did not have a 'myRequiredValue' value
|
||||
}
|
||||
```
|
||||
|
||||
(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.
|
||||
|
||||
<a name="jws-read-clock"></a>
|
||||
|
||||
#### Accounting for Clock Skew
|
||||
|
||||
When parsing a JWT, you might find that `exp` or `nbf` claim assertions fail (throw exceptions) because the clock on
|
||||
|
@ -1192,7 +1141,7 @@ obvious problems since `exp` and `nbf` are time-based assertions, and clock time
|
|||
assertions.
|
||||
|
||||
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
|
||||
long seconds = 3 * 60; //3 minutes
|
||||
|
@ -1205,20 +1154,18 @@ Jwts.parserBuilder()
|
|||
.build()
|
||||
.parseClaimsJws(jwt);
|
||||
```
|
||||
|
||||
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
|
||||
atomic clocks around the world.
|
||||
|
||||
<a name="jws-read-clock-custom"></a>
|
||||
|
||||
##### Custom Clock Support
|
||||
|
||||
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`
|
||||
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();
|
||||
|
||||
Jwts.parserBuilder().setClock(myClock) //... etc ...
|
||||
|
@ -1229,7 +1176,6 @@ as most would expect. However, supplying your own clock could be useful, especia
|
|||
guarantee deterministic behavior.
|
||||
|
||||
<a name="jws-read-decompression"></a>
|
||||
|
||||
#### JWS Decompression
|
||||
|
||||
If you used JJWT to compress a JWS and you used a custom compression algorithm, you will need to tell the `JwtParserBuilder`
|
||||
|
@ -1240,7 +1186,6 @@ Please see the [Compression](#compression) section below to see how to decompres
|
|||
<!-- TODO: ## Encrypted JWTs -->
|
||||
|
||||
<a name="compression"></a>
|
||||
|
||||
## Compression
|
||||
|
||||
**The JWT specification only standardizes this feature for JWEs (Encrypted JWTs) and not JWSs (Signed JWTs), however
|
||||
|
@ -1269,7 +1214,6 @@ 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.
|
||||
|
||||
<a name="compression-custom"></a>
|
||||
|
||||
### Custom Compression Codec
|
||||
|
||||
If however, you used your own custom compression codec when creating the JWT (via `JwtBuilder` `compressWith`), then
|
||||
|
@ -1304,7 +1248,6 @@ public class MyCompressionCodecResolver implements CompressionCodecResolver {
|
|||
```
|
||||
|
||||
<a name="json"></a>
|
||||
|
||||
## JSON Support
|
||||
|
||||
A `JwtBuilder` will serialize the `Header` and `Claims` maps (and potentially any Java objects they
|
||||
|
@ -1317,14 +1260,16 @@ 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
|
||||
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.
|
||||
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
|
||||
project runtime dependency.
|
||||
|
||||
**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
|
||||
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
|
||||
`io.jsonwebtoken:jjwt-gson` dependency** (or implement your own Serializer and Deserializer if desired). **But beware**,
|
||||
|
@ -1332,7 +1277,6 @@ Jackson will force a sizable (> 1 MB) dependency to an Android application thus
|
|||
mobile users.
|
||||
|
||||
<a name="json-custom"></a>
|
||||
|
||||
### Custom JSON Processor
|
||||
|
||||
If you don't want to use JJWT's runtime dependency approach, or just want to customize how JSON serialization and
|
||||
|
@ -1364,7 +1308,6 @@ Jwts.parserBuilder()
|
|||
```
|
||||
|
||||
<a name="json-jackson"></a>
|
||||
|
||||
### Jackson JSON Processor
|
||||
|
||||
If you want to use Jackson for JSON processing, just including the `io.jsonwebtoken:jjwt-jackson` dependency as a
|
||||
|
@ -1397,8 +1340,6 @@ scope which is the typical JJWT default). That is:
|
|||
```groovy
|
||||
dependencies {
|
||||
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'
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -1427,7 +1368,6 @@ Jwts.parserBuilder()
|
|||
```
|
||||
|
||||
<a name="json-jackson-custom-types"></a>
|
||||
|
||||
#### 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:
|
||||
|
@ -1470,7 +1410,6 @@ consequences for a shared `ObjectMapper` instance. This should work for most app
|
|||
parsing options, [configure the mapper directly](#json-jackson).
|
||||
|
||||
<a name="json-gson"></a>
|
||||
|
||||
### Gson JSON Processor
|
||||
|
||||
If you want to use Gson for JSON processing, just including the `io.jsonwebtoken:jjwt-gson` dependency as a
|
||||
|
@ -1509,8 +1448,6 @@ scope which is the typical JJWT default). That is:
|
|||
```groovy
|
||||
dependencies {
|
||||
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'
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -1540,7 +1477,6 @@ Jwts.parser()
|
|||
```
|
||||
|
||||
<a name="base64"></a>
|
||||
|
||||
## Base64 Support
|
||||
|
||||
JJWT uses a very fast pure-Java [Base64](https://tools.ietf.org/html/rfc4648) codec for Base64 and
|
||||
|
@ -1551,16 +1487,15 @@ utility classes.
|
|||
|
||||
`io.jsonwebtoken.io.Encoders`:
|
||||
|
||||
- `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
|
||||
* `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
|
||||
|
||||
`io.jsonwebtoken.io.Decoders`:
|
||||
|
||||
- `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
|
||||
* `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
|
||||
|
||||
<a name="base64-security"></a>
|
||||
|
||||
### Understanding Base64 in Security Contexts
|
||||
|
||||
All cryptographic operations, like encryption and message digest calculations, result in binary data - raw byte arrays.
|
||||
|
@ -1576,11 +1511,10 @@ 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
|
||||
are critical to remember when they are used in security scenarios like with JWTs:
|
||||
|
||||
- [Base64 is not encryption](#base64-not-encryption)
|
||||
- [Changing Base64 characters](#base64-changing-characters) **does not automatically invalidate data**.
|
||||
* [Base64 is not encryption](#base64-not-encryption)
|
||||
* [Changing Base64 characters](#base64-changing-characters) **does not automatically invalidate data**.
|
||||
|
||||
<a name="base64-not-encryption"></a>
|
||||
|
||||
#### Base64 is not encryption
|
||||
|
||||
Base64-encoded text is _not_ encrypted.
|
||||
|
@ -1600,7 +1534,6 @@ 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.
|
||||
|
||||
<a name="base64-changing-characters"></a>
|
||||
|
||||
#### Changing Base64 Characters
|
||||
|
||||
In an effort to see if signatures or encryption is truly validated correctly, some try to edit a JWT
|
||||
|
@ -1621,21 +1554,19 @@ 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):
|
||||
|
||||
> 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:
|
||||
>
|
||||
> dGVzdCBzdHJpbmo
|
||||
> dGVzdCBzdHJpbmp
|
||||
> dGVzdCBzdHJpbmq
|
||||
> dGVzdCBzdHJpbmr
|
||||
>
|
||||
> 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
|
||||
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>
|
||||
|
||||
##### Adding Invalid Characters
|
||||
|
||||
JJWT's default Base64/Base64URL decoders automatically ignore illegal Base64 characters located in the beginning and
|
||||
|
@ -1654,8 +1585,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
|
||||
[signing JWTs](#jws):
|
||||
|
||||
> - 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 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).
|
||||
|
||||
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
|
||||
|
@ -1665,7 +1596,6 @@ Please see [JJWT Issue #518](https://github.com/jwtk/jjwt/issues/518) and its re
|
|||
information.
|
||||
|
||||
<a name="base64-custom"></a>
|
||||
|
||||
### Custom Base64
|
||||
|
||||
If for some reason you want to specify your own Base64Url encoder and decoder, you can use the `JwtBuilder`
|
||||
|
@ -1707,7 +1637,6 @@ Jwts.parserBuilder()
|
|||
Maintained by Les Hazlewood & [Okta](https://okta.com/)
|
||||
|
||||
<a name="license"></a>
|
||||
|
||||
## License
|
||||
|
||||
This project is open-source via the [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0).
|
||||
|
|
Loading…
Reference in New Issue