• Stars
    star
    1,681
  • Rank 27,769 (Top 0.6 %)
  • Language
    Rust
  • License
    MIT License
  • Created about 9 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

JWT lib in rust

jsonwebtoken

API documentation on docs.rs

See JSON Web Tokens for more information on what JSON Web Tokens are.

Installation

Add the following to Cargo.toml:

jsonwebtoken = "9"
# If you do not need pem decoding, you can disable the default feature `use_pem` that way:
# jsonwebtoken = {version = "9", default-features = false }
serde = {version = "1.0", features = ["derive"] }

The minimum required Rust version (MSRV) is 1.67.

Algorithms

This library currently supports the following:

  • HS256
  • HS384
  • HS512
  • RS256
  • RS384
  • RS512
  • PS256
  • PS384
  • PS512
  • ES256
  • ES384
  • EdDSA

How to use

Complete examples are available in the examples directory: a basic one and one with a custom header.

In terms of imports and structs:

use serde::{Serialize, Deserialize};
use jsonwebtoken::{encode, decode, Header, Algorithm, Validation, EncodingKey, DecodingKey};

/// Our claims struct, it needs to derive `Serialize` and/or `Deserialize`
#[derive(Debug, Serialize, Deserialize)]
struct Claims {
    sub: String,
    company: String,
    exp: usize,
}

Claims

The claims fields which can be validated. (see validation)

#[derive(Debug, Serialize, Deserialize)]
struct Claims {
    aud: String,         // Optional. Audience
    exp: usize,          // Required (validate_exp defaults to true in validation). Expiration time (as UTC timestamp)
    iat: usize,          // Optional. Issued at (as UTC timestamp)
    iss: String,         // Optional. Issuer
    nbf: usize,          // Optional. Not Before (as UTC timestamp)
    sub: String,         // Optional. Subject (whom token refers to)
}

Header

The default algorithm is HS256, which uses a shared secret.

let token = encode(&Header::default(), &my_claims, &EncodingKey::from_secret("secret".as_ref()))?;

Custom headers & changing algorithm

All the parameters from the RFC are supported but the default header only has typ and alg set. If you want to set the kid parameter or change the algorithm for example:

let mut header = Header::new(Algorithm::HS512);
header.kid = Some("blabla".to_owned());
let token = encode(&header, &my_claims, &EncodingKey::from_secret("secret".as_ref()))?;

Look at examples/custom_header.rs for a full working example.

Encoding

// HS256
let token = encode(&Header::default(), &my_claims, &EncodingKey::from_secret("secret".as_ref()))?;
// RSA
let token = encode(&Header::new(Algorithm::RS256), &my_claims, &EncodingKey::from_rsa_pem(include_bytes!("privkey.pem"))?)?;

Encoding a JWT takes 3 parameters:

  • a header: the Header struct
  • some claims: your own struct
  • a key/secret

When using HS256, HS384, 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 PEM or DER format.

If your key is in PEM format, it is better performance wise to generate the EncodingKey once in a lazy_static or something similar and reuse it.

Decoding

// `token` is a struct with 2 fields: `header` and `claims` where `claims` is your own struct.
let token = decode::<Claims>(&token, &DecodingKey::from_secret("secret".as_ref()), &Validation::default())?;

decode can result in errors for a variety of reasons:

  • the token or its signature is invalid
  • the token had invalid base64
  • validation of at least one reserved claim failed

As with encoding, when using HS256, HS384, 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 PEM (or certificate in this case) or DER format.

In some cases, for example if you don't know the algorithm used or need to grab the kid, you can choose to decode only the header:

let header = decode_header(&token)?;

This does not perform any signature verification or validate the token claims.

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 in a JSON format like so:

{
   "kty":"RSA",
   "e":"AQAB",
   "kid":"6a7a119f-0876-4f7e-8d0f-bf3ea1391dd8",
   "n":"yRE6rHuNR0QbHO3H3Kt2pOKGVhQqGZXInOduQNxXzuKlvQTLUTv4l4sggh5_CYYi_cvI-SXVT9kPWSKXxJXBXd_4LkvcPuUakBoAkfh-eiFVMh2VrUyWyj3MFl0HTVF9KwRXLAcwkREiS3npThHRyIxuy0ZMeZfxVL5arMhw1SRELB8HoGfG_AtH89BIE9jDBHZ9dLelK9a184zAf8LwoPLxvJb3Il5nncqPcSfKDDodMFBIMc4lQzDKL5gvmiXLXB1AGLm8KBjfE8s3L5xqi-yUod-j8MtvIj812dkS4QMiRVN_by2h3ZY8LYVGrqZXZTcgn2ujn8uKjXLZVD5TdQ"
}
// `token` is a struct with 2 fields: `header` and `claims` where `claims` is your own struct.
let token = decode::<Claims>(&token, &DecodingKey::from_rsa_components(jwk["n"], jwk["e"]), &Validation::new(Algorithm::RS256))?;

If your key is in PEM format, it is better performance wise to generate the DecodingKey once in a lazy_static or something similar and reuse it.

Convert SEC1 private key to PKCS8

jsonwebtoken currently only supports PKCS8 format for private EC keys. If your key has BEGIN EC PRIVATE KEY at the top, this is a SEC1 type and can be converted to PKCS8 like so:

openssl pkcs8 -topk8 -nocrypt -in sec1.pem -out pkcs8.pem

Validation

This library automatically validates the exp claim, and nbf is validated if present. You can also validate the sub, iss, and aud but those require setting the expected values in the Validation struct. In the case of aud, if there is a value set in the token but not in the Validation, the token will be rejected.

Validation is only made on present fields in the claims. It is possible to define the required claims, hence verifying that a JWT has a value for each of these claims before it is considered for validation. The required claims can be set in the Validation struct. The default option requires the exp claim to be present.

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 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.

Look at examples/validation.rs for a full working example.

More Repositories

1

tera

A template engine for Rust based on Jinja2/Django
Rust
3,512
star
2

validator

Simple validation for Rust structs
Rust
2,024
star
3

kickstart

A scaffolding tool to get new projects up and running quickly
Rust
363
star
4

rust-bcrypt

Easily hash and verify passwords using Bcrypt
Rust
335
star
5

dbmigrate

PostgreSQL/SQLite/MySQL migration tool in rust
Rust
129
star
6

rodent

Turn your laptop into a CCTV!
Python
71
star
7

scl

A simple configuration language
Rust
63
star
8

ng-boilerplate

AngularJS boilerplate app
CSS
60
star
9

webrust

Rust
51
star
10

rust-cli-template

A template to get started with writing cross-platforms CLI applications
Shell
51
star
11

tera2

Rust
39
star
12

react-ts-boilerplate

A React + Typescript + Sass boilerplate
TypeScript
33
star
13

django-drf-template

A django template to start a DRF project
Python
28
star
14

graphql-parser

Rust
20
star
15

vincentprouillet

My website
HTML
15
star
16

flow-typescript

JavaScript
9
star
17

invoicer

TypeScript
8
star
18

vat

VAT number validation and VAT rates for the EU
Rust
7
star
19

playbook-mailinabox

Shell
6
star
20

gulp-example

Example setup for blogpost
CoffeeScript
6
star
21

hn-react

TypeScript
5
star
22

pelican-hyde

Port of https://github.com/poole/hyde to Pelican with slight changes
CSS
4
star
23

react-example

Basic example using react, redux and react-router.
JavaScript
3
star
24

Artemis

Entity-Components-Systems framework in coffeescript
JavaScript
3
star
25

react-redux-boilerplate

JavaScript
2
star
26

papyrus

Start of a contenteditable editor (not worked on)
JavaScript
1
star
27

kcalculator-react

TypeScript
1
star
28

markdown-benches-rs

Rust
1
star
29

dotfiles

Shell
1
star
30

serde-tera

Experiment
Rust
1
star
31

Punchstone

Game engine written in coffeescript
JavaScript
1
star
32

hackertyper

Python
1
star
33

restacular-old

REST Server
Go
1
star
34

webpack-react-typescript

JavaScript
1
star