Update docs

This commit is contained in:
Vincent Prouillet 2019-11-14 19:43:43 +01:00
parent 8e4757cb1d
commit 51dacd9bc4
17 changed files with 175 additions and 146 deletions

116
README.md
View File

@ -9,8 +9,7 @@ Add the following to Cargo.toml:
```toml
jsonwebtoken = "7"
serde_derive = "1"
serde = "1"
serde = {version = "1.0", features = ["derive"] }
```
## How to use
@ -18,11 +17,8 @@ Complete examples are available in the examples directory: a basic one and one w
In terms of imports and structs:
```rust
extern crate jsonwebtoken as jwt;
#[macro_use]
extern crate serde_derive;
use jwt::{encode, decode, Header, Algorithm, Validation};
use serde::{Serialize, Deserialize};
use jsonwebtoken::{encode, decode, Header, Algorithm, Validation};
/// Our claims struct, it needs to derive `Serialize` and/or `Deserialize`
#[derive(Debug, Serialize, Deserialize)]
@ -33,7 +29,7 @@ struct Claims {
}
```
### Encoding
### Header
The default algorithm is HS256.
```rust
@ -45,38 +41,84 @@ All the parameters from the RFC are supported but the default header only has `t
If you want to set the `kid` parameter or change the algorithm for example:
```rust
let mut header = Header::default();
let mut header = Header::new(Algorithm::HS512);
header.kid = Some("blabla".to_owned());
header.alg = Algorithm::HS512;
let token = encode(&header, &my_claims, "secret".as_ref())?;
```
Look at `examples/custom_header.rs` for a full working example.
### Encoding
```rust
// HS256
let token = encode(&Header::default(), &my_claims, "secret".as_ref())?;
// RSA
let token = encode(&Header::new(Algorithm::RS256), &my_claims, include_str!("privkey.pem"))?;
```
Encoding a JWT takes 3 parameters:
- a header: the `Header` struct
- some claims: your own struct
- a key
When using HS256, HS2384 or HS512, the key is always a shared secret like in the example above. When using
RSA/EC, the key should always be the content of the private key in the PEM format.
### Decoding
```rust
let token = decode::<Claims>(&token, "secret".as_ref(), &Validation::default())?;
// token is a struct with 2 params: header and claims
// token is a struct with 2 fields: `header` and `claims` and `claims` is your own struct.
```
`decode` can error for a variety of reasons:
- the token or its signature is invalid
- error while decoding base64 or the result of decoding base64 is not valid UTF-8
- the token had invalid base64
- validation of at least one reserved claim failed
In some cases, for example if you don't know the algorithm used, you will want to only decode the header:
As with encoding, when using HS256, HS2384 or HS512, the key is always a shared secret like in the example above. When using
RSA/EC, the key should always be the content of the public key in the PEM format.
In some cases, for example if you don't know the algorithm used or need to grab the `kid`, you can decode only the header:
```rust
let header = decode_header(&token)?;
```
This does not perform any validation on the token.
This does not perform any signature verification/validations on the token so it could have been tampered with.
You can also decode a token using the public key components of a RSA key in base64 format.
The main use-case is for JWK where your public key is a JSON format like so:
```json
{
"kty":"RSA",
"e":"AQAB",
"kid":"6a7a119f-0876-4f7e-8d0f-bf3ea1391dd8",
"n":"yRE6rHuNR0QbHO3H3Kt2pOKGVhQqGZXInOduQNxXzuKlvQTLUTv4l4sggh5_CYYi_cvI-SXVT9kPWSKXxJXBXd_4LkvcPuUakBoAkfh-eiFVMh2VrUyWyj3MFl0HTVF9KwRXLAcwkREiS3npThHRyIxuy0ZMeZfxVL5arMhw1SRELB8HoGfG_AtH89BIE9jDBHZ9dLelK9a184zAf8LwoPLxvJb3Il5nncqPcSfKDDodMFBIMc4lQzDKL5gvmiXLXB1AGLm8KBjfE8s3L5xqi-yUod-j8MtvIj812dkS4QMiRVN_by2h3ZY8LYVGrqZXZTcgn2ujn8uKjXLZVD5TdQ"
}
```
```rust
let token = decode_rsa_components::<Claims>(&token, jwk["n"], jwk["e"], &Validation::new(Algorithm::RS256))?;
// token is a struct with 2 fields: `header` and `claims` and `claims` is your own struct.
```
### Convertion .der to .pem
You can use openssl for that:
```bash
openssl rsa -inform DER -outform PEM -in mykey.der -out mykey.pem
```
#### Validation
This library validates automatically the `exp` claim. `nbf` is also validated if present. You can also validate the `sub`, `iss` and `aud` but
those require setting the expected value in the `Validation` struct.
Since validating time fields is always a bit tricky due to clock skew,
you can add some leeway to the `iat`, `exp` and `nbf` validation by setting a `leeway` parameter.
you can add some leeway to the `iat`, `exp` and `nbf` validation by setting the `leeway` field.
Last but not least, you will need to set the algorithm(s) allowed for this token if you are not using `HS256`.
@ -112,44 +154,6 @@ This library currently supports the following:
- ES256
- ES384
### RSA
`jsonwebtoken` can read DER and PEM encoded keys.
#### DER Encoded
If you have openssl installed, you can run the following commands to obtain the DER keys from PKCS#1 (ie with `BEGIN RSA PUBLIC KEY`) .pem.
If you have a PKCS#8 pem file (ie starting with `BEGIN PUBLIC KEY`), you will need to first convert it to PKCS#1:
`openssl rsa -pubin -in <filename> -RSAPublicKey_out -out <filename>`.
```bash
// private key
$ openssl rsa -in private_rsa_key.pem -outform DER -out private_rsa_key.der
// public key
$ openssl rsa -in private_rsa_key.der -inform DER -RSAPublicKey_out -outform DER -out public_key.der
```
If you are getting an error with your public key, make sure you get it by using the command above to ensure
it is in the right format.
#### PEM Encoded
To generate a PKCS#1 RSA key, run `openssl genrsa -out private_rsa_key_pkcs1.pem 2048`
To convert a PKCS#1 RSA key to a PKCS#8 RSA key, run `openssl pkcs8 -topk8 -inform pem -in private_rsa_key_pkcs1.pem -outform pem -nocrypt -out private_rsa_key_pkcs8.pem`
To use a PEM encoded private / public keys, a pem struct is returned by `decode_pem`.
This carries the lifetime of the data inside. Finally to use the key like any other
use the `.as_key(alg)` function on the pem struct.
```
let privkey_pem = decode_pem(pem_string_here).unwrap();
let privkey = privkey_pem.as_key(Algorithm::RS256).unwrap();
```
### ECDSA
`jsonwebtoken` can read PKCS#8 DER encoded private keys and public keys, as well as PEM encoded keys. Like RSA, to read a PEM key, you must use the pem decoder.
To generate an EC key, you can do the following.
```bash
// private key
openssl ecparam -genkey -name prime256v1 | openssl ec -out private_key.pem
// public key
openssl ec -in private_key.pem -pubout -out public_key.pem
```
### RSA & ECDSA
By default, the `encode`/`decode` functions takes the PEM format since it is the most common.
RSA can also use the public key components modulus/exponent in base64 format for decoding.

View File

@ -1,10 +1,8 @@
#![feature(test)]
extern crate jsonwebtoken as jwt;
extern crate test;
#[macro_use]
extern crate serde_derive;
use jwt::{decode, encode, Header, Hmac, Validation};
use jsonwebtoken::{decode, encode, Header, Validation};
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
struct Claims {
@ -16,7 +14,7 @@ struct Claims {
fn bench_encode(b: &mut test::Bencher) {
let claim = Claims { sub: "b@b.com".to_owned(), company: "ACME".to_owned() };
b.iter(|| encode(&Header::default(), &claim, Hmac::from(b"secret")));
b.iter(|| encode(&Header::default(), &claim, "secret".as_ref()));
}
#[bench]

View File

@ -2,7 +2,7 @@ use crate::errors::{Error, ErrorKind, Result};
use serde::{Deserialize, Serialize};
use std::str::FromStr;
/// The algorithms supported for signing/verifying
/// The algorithms supported for signing/verifying JWTs
#[derive(Debug, PartialEq, Copy, Clone, Serialize, Deserialize)]
pub enum Algorithm {
/// HMAC using SHA-256

View File

@ -2,7 +2,7 @@ use ring::{rand, signature};
use crate::algorithms::Algorithm;
use crate::errors::Result;
use crate::pem_decoder::PemEncodedKey;
use crate::pem::decoder::PemEncodedKey;
use crate::serialization::b64_encode;
/// Only used internally when validating EC, to map from our enum to the Ring EcdsaVerificationAlgorithm structs.

View File

@ -3,7 +3,7 @@ use ring::{hmac, signature};
use crate::algorithms::Algorithm;
use crate::errors::Result;
use crate::pem_decoder::PemEncodedKey;
use crate::pem::decoder::PemEncodedKey;
use crate::serialization::{b64_decode, b64_encode};
pub(crate) mod ecdsa;
@ -19,7 +19,8 @@ pub(crate) fn sign_hmac(alg: hmac::Algorithm, key: &[u8], message: &str) -> Resu
/// Take the payload of a JWT, sign it using the algorithm given and return
/// the base64 url safe encoded of the result.
///
/// Only use this function if you want to do something other than JWT.
/// If you just want to encode a JWT, use `encode` instead.
///
/// `key` is the secret for HMAC and a pem encoded string otherwise
pub fn sign(message: &str, key: &[u8], algorithm: Algorithm) -> Result<String> {
match algorithm {
@ -57,7 +58,7 @@ fn verify_ring(
/// Compares the signature given with a re-computed signature for HMAC or using the public key
/// for RSA/EC.
///
/// Only use this function if you want to do something other than JWT.
/// If you just want to decode a JWT, use `decode` instead.
///
/// `signature` is the signature part of a jwt (text after the second '.')
///
@ -109,5 +110,10 @@ pub fn verify_rsa_components(
alg: Algorithm,
) -> Result<bool> {
let signature_bytes = b64_decode(signature)?;
rsa::verify_from_components(rsa::alg_to_rsa_parameters(alg), &signature_bytes, message, components)
rsa::verify_from_components(
rsa::alg_to_rsa_parameters(alg),
&signature_bytes,
message,
components,
)
}

View File

@ -3,7 +3,7 @@ use simple_asn1::BigUint;
use crate::algorithms::Algorithm;
use crate::errors::{ErrorKind, Result};
use crate::pem_decoder::PemEncodedKey;
use crate::pem::decoder::PemEncodedKey;
use crate::serialization::{b64_decode, b64_encode};
/// Only used internally when validating RSA, to map from our enum to the Ring param structs.

View File

@ -3,9 +3,18 @@ use serde::de::DeserializeOwned;
use crate::crypto::{verify, verify_rsa_components};
use crate::errors::{new_error, ErrorKind, Result};
use crate::header::Header;
use crate::serialization::{from_jwt_part_claims, TokenData};
use crate::serialization::from_jwt_part_claims;
use crate::validation::{validate, Validation};
/// The return type of a successful call to [decode](fn.decode.html).
#[derive(Debug)]
pub struct TokenData<T> {
/// The decoded JWT header
pub header: Header,
/// The decoded JWT claims
pub claims: T,
}
/// Takes the result of a rsplit and ensure we only get 2 parts
/// Errors if we don't
macro_rules! expect_two {
@ -54,7 +63,7 @@ fn _decode<T: DeserializeOwned>(
Ok(TokenData { header, claims: decoded_claims })
}
/// Decode a token into a struct containing 2 fields: `claims` and `header`.
/// Decode and validate a JWT using a secret for HS and a public PEM format for RSA/EC
///
/// If the token or its signature is invalid or the claims fail validation, it will return an error.
///
@ -80,8 +89,27 @@ pub fn decode<T: DeserializeOwned>(
_decode(token, DecodingKey::SecretOrPem(key), validation)
}
/// TO TEST
pub fn decode_rsa_jwk<T: DeserializeOwned>(
/// Decode and validate a JWT using (n, e) base64 encoded public key components for RSA
///
/// If the token or its signature is invalid or the claims fail validation, it will return an error.
///
/// ```rust
/// use serde::{Deserialize, Serialize};
/// use jsonwebtoken::{decode_rsa_components, Validation, Algorithm};
///
/// #[derive(Debug, Serialize, Deserialize)]
/// struct Claims {
/// sub: String,
/// company: String
/// }
///
/// let modulus = "some-base64-data";
/// let exponent = "some-base64-data";
/// let token = "a.jwt.token".to_string();
/// // Claims is a struct that implements Deserialize
/// let token_message = decode_rsa_components::<Claims>(&token, &modulus, &exponent, &Validation::new(Algorithm::HS256));
/// ```
pub fn decode_rsa_components<T: DeserializeOwned>(
token: &str,
modulus: &str,
exponent: &str,
@ -90,7 +118,7 @@ pub fn decode_rsa_jwk<T: DeserializeOwned>(
_decode(token, DecodingKey::RsaModulusExponent { n: modulus, e: exponent }, validation)
}
/// Decode a token without any signature validation into a struct containing 2 fields: `claims` and `header`.
/// Decode a JWT without any signature verification/validations.
///
/// NOTE: Do not use this unless you know what you are doing! If the token's signature is invalid, it will *not* return an error.
///
@ -118,10 +146,9 @@ pub fn dangerous_unsafe_decode<T: DeserializeOwned>(token: &str) -> Result<Token
Ok(TokenData { header, claims: decoded_claims })
}
/// Decode a token and return the Header. This is not doing any kind of validation: it only splits
/// on the `.` and return the base64 decoded header.
/// Decode a JWT without any signature verification/validations and return its [Header](struct.Header.html).
///
/// If the token has an invalid format, it will return an error.
/// If the token has an invalid format (ie 3 parts separated by a `.`), it will return an error.
///
/// ```rust
/// use jsonwebtoken::decode_header;

View File

@ -93,11 +93,11 @@ impl StdError for Error {
ErrorKind::InvalidAlgorithm => "algorithms don't match",
ErrorKind::InvalidAlgorithmName => "not a known algorithm",
ErrorKind::InvalidKeyFormat => "invalid key format",
ErrorKind::__Nonexhaustive => "unknown error",
ErrorKind::Base64(ref err) => err.description(),
ErrorKind::Json(ref err) => err.description(),
ErrorKind::Utf8(ref err) => err.description(),
ErrorKind::Crypto(ref err) => err.description(),
ErrorKind::__Nonexhaustive => "unknown error",
}
}
@ -115,11 +115,11 @@ impl StdError for Error {
ErrorKind::InvalidAlgorithm => None,
ErrorKind::InvalidAlgorithmName => None,
ErrorKind::InvalidKeyFormat => None,
ErrorKind::__Nonexhaustive => None,
ErrorKind::Base64(ref err) => Some(err),
ErrorKind::Json(ref err) => Some(err),
ErrorKind::Utf8(ref err) => Some(err),
ErrorKind::Crypto(ref err) => Some(err),
ErrorKind::__Nonexhaustive => None,
}
}
}

View File

@ -4,21 +4,21 @@
#![deny(missing_docs)]
mod algorithms;
mod crypto;
/// Lower level functions, if you want to do something other than JWTs
pub mod crypto;
mod decoding;
/// All the errors
/// All the errors that can be encountered while encoding/decoding JWTs
pub mod errors;
mod header;
mod pem_decoder;
mod pem_encoder;
mod pem;
mod serialization;
mod validation;
pub use algorithms::Algorithm;
pub use crypto::{sign, verify};
pub use decoding::{dangerous_unsafe_decode, decode, decode_header, decode_rsa_jwk};
pub use decoding::{
dangerous_unsafe_decode, decode, decode_header, decode_rsa_components, TokenData,
};
pub use header::Header;
pub use serialization::TokenData;
pub use validation::Validation;
use serde::ser::Serialize;
@ -26,7 +26,8 @@ use serde::ser::Serialize;
use crate::errors::Result;
use crate::serialization::b64_encode_part;
/// Encode the header and claims given and sign the payload using the algorithm from the header and the key
/// Encode the header and claims given and sign the payload using the algorithm from the header and the key.
/// If the algorithm given is RSA or EC, the key needs to be in the PEM format.
///
/// ```rust
/// use serde::{Deserialize, Serialize};
@ -51,37 +52,7 @@ pub fn encode<T: Serialize>(header: &Header, claims: &T, key: &[u8]) -> Result<S
let encoded_header = b64_encode_part(&header)?;
let encoded_claims = b64_encode_part(&claims)?;
let message = [encoded_header.as_ref(), encoded_claims.as_ref()].join(".");
let signature = sign(&*message, key, header.alg)?;
let signature = crypto::sign(&*message, key, header.alg)?;
Ok([message, signature].join("."))
}
/// TODO
pub fn encode_rsa_public_pkcs1_pem(modulus: &[u8], exponent: &[u8]) -> Result<String> {
pem_encoder::encode_rsa_public_pkcs1_pem(modulus, exponent)
}
/// TODO
pub fn encode_rsa_public_pkcs1_der(modulus: &[u8], exponent: &[u8]) -> Result<Vec<u8>> {
pem_encoder::encode_rsa_public_pkcs1_der(modulus, exponent)
}
/// TODO
pub fn encode_rsa_public_pkcs8_pem(modulus: &[u8], exponent: &[u8]) -> Result<String> {
pem_encoder::encode_rsa_public_pkcs8_pem(modulus, exponent)
}
/// TODO
pub fn encode_rsa_public_pkcs8_der(modulus: &[u8], exponent: &[u8]) -> Result<Vec<u8>> {
pem_encoder::encode_rsa_public_pkcs8_der(modulus, exponent)
}
/// TODO
pub fn encode_ec_public_pem(x_coordinate: &[u8]) -> Result<String> {
pem_encoder::encode_ec_public_pem(x_coordinate)
}
/// TODO
pub fn encode_ec_public_der(x_coordinate: &[u8]) -> Result<Vec<u8>> {
pem_encoder::encode_ec_public_der(x_coordinate)
}

View File

@ -1,8 +1,5 @@
use crate::errors::{ErrorKind, Result};
extern crate pem;
extern crate simple_asn1;
use simple_asn1::{BigUint, OID};
/// Supported PEM files for EC and RSA Public and Private Keys

View File

@ -2,43 +2,39 @@ use crate::errors::{ErrorKind, Result};
use pem::Pem;
use simple_asn1::{ASN1Block, BigInt, BigUint, OID};
extern crate base64;
extern crate pem;
extern crate simple_asn1;
pub fn encode_rsa_public_pkcs1_pem(modulus: &[u8], exponent: &[u8]) -> Result<String> {
pub(crate) fn encode_rsa_public_pkcs1_pem(modulus: &[u8], exponent: &[u8]) -> Result<String> {
Ok(pem::encode(&Pem {
contents: encode_rsa_public_pkcs1_der(modulus, exponent)?,
tag: "RSA PUBLIC KEY".to_string(),
}))
}
pub fn encode_rsa_public_pkcs1_der(modulus: &[u8], exponent: &[u8]) -> Result<Vec<u8>> {
pub(crate) fn encode_rsa_public_pkcs1_der(modulus: &[u8], exponent: &[u8]) -> Result<Vec<u8>> {
match simple_asn1::to_der(&encode_rsa_public_pksc1_asn1(modulus, exponent)) {
Ok(bytes) => Ok(bytes),
Err(_) => Err(ErrorKind::InvalidRsaKey.into()),
}
}
pub fn encode_rsa_public_pkcs8_pem(modulus: &[u8], exponent: &[u8]) -> Result<String> {
pub(crate) fn encode_rsa_public_pkcs8_pem(modulus: &[u8], exponent: &[u8]) -> Result<String> {
Ok(pem::encode(&Pem {
contents: encode_rsa_public_pkcs8_der(modulus, exponent)?,
tag: "PUBLIC KEY".to_string(),
}))
}
pub fn encode_rsa_public_pkcs8_der(modulus: &[u8], exponent: &[u8]) -> Result<Vec<u8>> {
pub(crate) fn encode_rsa_public_pkcs8_der(modulus: &[u8], exponent: &[u8]) -> Result<Vec<u8>> {
match simple_asn1::to_der(&encode_rsa_public_pksc8_asn1(modulus, exponent)?) {
Ok(bytes) => Ok(bytes),
Err(_) => Err(ErrorKind::InvalidRsaKey.into()),
}
}
pub fn encode_ec_public_pem(x: &[u8]) -> Result<String> {
pub(crate) fn encode_ec_public_pem(x: &[u8]) -> Result<String> {
Ok(pem::encode(&Pem { contents: encode_ec_public_der(x)?, tag: "PUBLIC KEY".to_string() }))
}
pub fn encode_ec_public_der(x: &[u8]) -> Result<Vec<u8>> {
pub(crate) fn encode_ec_public_der(x: &[u8]) -> Result<Vec<u8>> {
match simple_asn1::to_der(&encode_ec_public_asn1(x)) {
Ok(bytes) => Ok(bytes),
Err(_) => Err(ErrorKind::InvalidEcdsaKey.into()),

34
src/pem/mod.rs Normal file
View File

@ -0,0 +1,34 @@
pub(crate) mod decoder;
mod encoder;
use crate::errors::Result;
/// Encode (n, e) components into the public PKCS1 PEM format
pub fn encode_rsa_public_pkcs1_pem(modulus: &[u8], exponent: &[u8]) -> Result<String> {
encoder::encode_rsa_public_pkcs1_pem(modulus, exponent)
}
/// Encode (n, e) components into the public PKCS1 PEM format
pub fn encode_rsa_public_pkcs1_der(modulus: &[u8], exponent: &[u8]) -> Result<Vec<u8>> {
encoder::encode_rsa_public_pkcs1_der(modulus, exponent)
}
/// TODO
pub fn encode_rsa_public_pkcs8_pem(modulus: &[u8], exponent: &[u8]) -> Result<String> {
encoder::encode_rsa_public_pkcs8_pem(modulus, exponent)
}
/// TODO
pub fn encode_rsa_public_pkcs8_der(modulus: &[u8], exponent: &[u8]) -> Result<Vec<u8>> {
encoder::encode_rsa_public_pkcs8_der(modulus, exponent)
}
/// TODO
pub fn encode_ec_public_pem(x_coordinate: &[u8]) -> Result<String> {
encoder::encode_ec_public_pem(x_coordinate)
}
/// TODO
pub fn encode_ec_public_der(x_coordinate: &[u8]) -> Result<Vec<u8>> {
encoder::encode_ec_public_der(x_coordinate)
}

View File

@ -4,16 +4,6 @@ use serde_json::map::Map;
use serde_json::{from_str, to_string, Value};
use crate::errors::Result;
use crate::header::Header;
/// The return type of a successful call to decode
#[derive(Debug)]
pub struct TokenData<T> {
/// The decoded JWT header
pub header: Header,
/// The decoded JWT claims
pub claims: T,
}
pub(crate) fn b64_encode(input: &[u8]) -> String {
base64::encode_config(input, base64::URL_SAFE_NO_PAD)

View File

@ -7,7 +7,7 @@ use serde_json::{from_value, Value};
use crate::algorithms::Algorithm;
use crate::errors::{new_error, ErrorKind, Result};
/// Contains the various validations that are applied after decoding a token.
/// Contains the various validations that are applied after decoding a JWT.
///
/// All time validation happen on UTC timestamps as seconds.
///

View File

@ -1,5 +1,8 @@
use chrono::Utc;
use jsonwebtoken::{decode, encode, sign, verify, Algorithm, Header, Validation};
use jsonwebtoken::{
crypto::{sign, verify},
decode, encode, Algorithm, Header, Validation,
};
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]

View File

@ -1,7 +1,7 @@
use chrono::Utc;
use jsonwebtoken::{
dangerous_unsafe_decode, decode, decode_header, encode, sign, verify, Algorithm, Header,
Validation,
crypto::{sign, verify},
dangerous_unsafe_decode, decode, decode_header, encode, Algorithm, Header, Validation,
};
use serde::{Deserialize, Serialize};

View File

@ -1,5 +1,8 @@
use chrono::Utc;
use jsonwebtoken::{decode, decode_rsa_jwk, encode, sign, verify, Algorithm, Header, Validation};
use jsonwebtoken::{
crypto::{sign, verify},
decode, decode_rsa_components, encode, Algorithm, Header, Validation,
};
use serde::{Deserialize, Serialize};
const RSA_ALGORITHMS: &[Algorithm] = &[
@ -76,7 +79,7 @@ fn rsa_modulus_exponent() {
let e = "AQAB";
let encrypted = encode(&Header::new(Algorithm::RS256), &my_claims, privkey.as_ref()).unwrap();
let res = decode_rsa_jwk::<Claims>(&encrypted, n, e, &Validation::new(Algorithm::RS256));
let res = decode_rsa_components::<Claims>(&encrypted, n, e, &Validation::new(Algorithm::RS256));
assert!(res.is_ok());
}