8 releases (breaking)

Uses old Rust 2015

0.10.1 Feb 2, 2022
0.10.0 Jul 29, 2017
0.6.0 May 11, 2017
0.5.0 Oct 27, 2016
0.1.0 Apr 29, 2016

#9 in #jsonwebtoken

35 downloads per month

MIT/Apache

26KB
343 lines

nickel-jwt-session

Experimental jwt-based user session for nickel. Note that the latest version of nickel was released in January 2019 (and this depends on an even slighly older version). This should probably not be used any more, but may possibly be interesting to look at for someone.

Build Status docs

Configuration

By default, nickel-jwt-session will store and look for the token in a cookie named "jwt", and the token will expire in 24 hours. The only required argument to the constructor is a private signing key:

extern crate nickel;
extern crate nickel_jwt_session;

use nickel::Nickel;
use nickel_jwt_session::SessionMiddleware;

fn main() {
    let mut server = Nickel::new();
    server.utilize(SessionMiddleware::new("My very secret key"));
}

You can also customize the cookie name:

extern crate nickel;
extern crate nickel_jwt_session;

use nickel::Nickel;
use nickel_jwt_session::{SessionMiddleware, TokenLocation};

fn main() {
    let mut server = Nickel::new();
    server.utilize(SessionMiddleware::new("My very secret key")
                   .using(TokenLocation::Cookie("my-jwt-cookie".to_owned())));
}

Or use Authorization: Bearer headers instead of cookies:

extern crate nickel;
extern crate nickel_jwt_session;

use nickel::Nickel;
use nickel_jwt_session::{SessionMiddleware, TokenLocation};

fn main() {
    let mut server = Nickel::new();
    server.utilize(SessionMiddleware::new("My very secret key")
                   .using(TokenLocation::AuthorizationHeader));
}

And change the number of seconds the token will be valid for:

extern crate nickel;
extern crate nickel_jwt_session;

use nickel::Nickel;
use nickel_jwt_session::SessionMiddleware;

fn main() {
    let mut server = Nickel::new();
    server.utilize(SessionMiddleware::new("My very secret key")
                   .expiration_time(60 * 30)); // 30 min
}

Usage

Username only

If you only want to store a username, you can use the set_jwt_user(), clear_jwt(), and authorized_user() convenience methods.

When you have a user that you have authenticated, use the set_jwt_user() method to put a new token for that user into the response:

fn login<'mw>(req: &mut Request, mut res: Response<'mw>)
              -> MiddlewareResult<'mw> {
    let authenticated_user = your_authentication_method(req);
    match authenticated_user {
        Some(username) => {
            res.set_jwt_user(username);
            res.redirect("/")
        }
        None => {
            res.redirect("/login")
        }
    }
}

To check to see if you have an authenticated user, use the authorized_user() method:

fn private<'mw>(req: &mut Request, res: Response<'mw>)
                -> MiddlewareResult<'mw> {
    match req.authorized_user() {
        Some(user) => {
            // Whatever an authorized user is allowed to do
        },
        None => res.error(StatusCode::Forbidden, "Permission denied"),
    }
}

And to log a user out, call the clear_jwt() method:

fn logout<'mw>(_req: &mut Request, mut res: Response<'mw>)
               -> MiddlewareResult<'mw> {
    res.clear_jwt();
    res.redirect("/")
}

Customized claims payload only

If you would like to store arbitrary data in the claims payload instead of a username, use the set_jwt_custom_claims() and valid_custom_claims() methods. The custom claims must be in a BTreeMap<String, Json>. Logging out is still done with the clear_jwt() method.

When you have successfully authenticated, use the set_jwt_custom_claims() method to put a new token with the data you include into the response:

use std::collections::BTreeMap;

fn login<'mw>(req: &mut Request, mut res: Response<'mw>)
              -> MiddlewareResult<'mw> {
    let authentication_data = your_authentication_method(req);
    match authentication_data {
        Some(data) => {
            let mut d = BTreeMap::new();
            d.insert("who".to_owned(), data.who);
            d.insert("admin".to_owned(), data.admin);
            res.set_jwt_custom_claims(d);
            res.redirect("/")
        }
        None => {
            res.redirect("/login")
        }
    }
}

To get the claims out if the token is valid, use the valid_custom_claims() method:

fn private<'mw>(req: &mut Request, res: Response<'mw>)
                -> MiddlewareResult<'mw> {
    match req.valid_custom_claims() {
        Some(data) => {
            // Whatever you do with valid data in the claims
        },
        None => res.error(StatusCode::Forbidden, "Permission denied"),
    }
}

And to end a session, call the clear_jwt() method:

fn logout<'mw>(_req: &mut Request, mut res: Response<'mw>)
               -> MiddlewareResult<'mw> {
    res.clear_jwt();
    res.redirect("/")
}

Username and customized claims payload

If you would like to store both a username and arbitrary claims data, use the set_jwt_user_and_custom_claims() method to add the username and data to the token. You may then use both the authorized_user() and valid_custom_claims() methods, to get the username and the claims data, respectively. For example:

use std::collections::BTreeMap;

fn login<'mw>(req: &mut Request, mut res: Response<'mw>)
              -> MiddlewareResult<'mw> {
    let authentication_data = your_authentication_method(req);
    match authentication_data {
        Some(data) => {
            let mut d = BTreeMap::new();
            d.insert("full_name".to_owned(), data.full_name);
            d.insert("admin".to_owned(), data.admin);
            res.set_jwt_user_and_custom_claims(data.username, d);
            res.redirect("/")
        }
        None => {
            res.redirect("/login")
        }
    }
}

To get the username and claims out if the token is valid, use the authorized_user() and valid_custom_claims() methods:

fn private<'mw>(req: &mut Request, res: Response<'mw>)
                -> MiddlewareResult<'mw> {
    match (req.authorized_user(), req.valid_custom_claims()) {
        (Some(username), Some(data)) => {
            // Whatever you do with a username and claims data
        },
        (_, _) => res.error(StatusCode::Forbidden, "Permission denied"),
    }
}

And to end a session, call the clear_jwt() method:

fn logout<'mw>(_req: &mut Request, mut res: Response<'mw>)
               -> MiddlewareResult<'mw> {
    res.clear_jwt();
    res.redirect("/")
}

Examples

Full working examples can be found in the examples directory. Read the API documentation.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~11MB
~217K SLoC