jsonwebtoken/src/lib.rs

165 lines
5.2 KiB
Rust
Raw Normal View History

2015-10-31 11:37:15 -04:00
//! Create and parses JWT (JSON Web Tokens)
//!
2017-04-13 03:36:32 -04:00
//! Documentation: [stable](https://docs.rs/jsonwebtoken/)
2017-02-22 02:45:28 -05:00
#![recursion_limit = "300"]
2017-04-12 21:08:07 -04:00
#![deny(missing_docs)]
2017-02-22 02:45:28 -05:00
#[macro_use]
extern crate serde_derive;
extern crate base64;
2018-10-28 14:58:35 -04:00
extern crate chrono;
2016-08-23 12:39:18 -04:00
extern crate ring;
2018-10-28 14:58:35 -04:00
extern crate serde;
extern crate serde_json;
2017-02-22 02:45:28 -05:00
extern crate untrusted;
2016-08-23 12:39:18 -04:00
2018-10-28 14:58:35 -04:00
mod crypto;
2017-04-12 21:08:07 -04:00
/// All the errors, generated using error-chain
2015-10-31 11:37:15 -04:00
pub mod errors;
mod header;
2017-02-22 02:45:28 -05:00
mod serialization;
2017-04-11 01:41:44 -04:00
mod validation;
2018-10-28 14:58:35 -04:00
pub use crypto::{sign, verify, Algorithm};
pub use header::Header;
2017-07-02 17:49:14 -04:00
pub use serialization::TokenData;
2018-10-28 14:58:35 -04:00
pub use validation::Validation;
2017-04-13 03:36:32 -04:00
use serde::de::DeserializeOwned;
2017-04-13 03:36:32 -04:00
use serde::ser::Serialize;
2018-10-28 14:58:35 -04:00
use errors::{new_error, ErrorKind, Result};
2017-07-02 17:49:14 -04:00
use serialization::{from_jwt_part, from_jwt_part_claims, to_jwt_part};
2018-10-28 14:58:35 -04:00
use validation::validate;
2017-04-13 03:36:32 -04:00
/// Encode the header and claims given and sign the payload using the algorithm from the header and the key
///
/// ```rust,ignore
/// #[macro_use]
/// extern crate serde_derive;
/// use jsonwebtoken::{encode, Algorithm, Header};
///
/// /// #[derive(Debug, Serialize, Deserialize)]
/// struct Claims {
/// sub: String,
/// company: String
/// }
///
/// let my_claims = Claims {
/// sub: "b@b.com".to_owned(),
/// company: "ACME".to_owned()
/// };
///
/// // my_claims is a struct that implements Serialize
/// // This will create a JWT using HS256 as algorithm
/// let token = encode(&Header::default(), &my_claims, "secret".as_ref()).unwrap();
/// ```
pub fn encode<T: Serialize>(header: &Header, claims: &T, key: &[u8]) -> Result<String> {
let encoded_header = to_jwt_part(&header)?;
let encoded_claims = to_jwt_part(&claims)?;
let signing_input = [encoded_header.as_ref(), encoded_claims.as_ref()].join(".");
2018-10-28 14:58:06 -04:00
let signature = sign(&*signing_input, key, header.alg)?;
2017-04-13 03:36:32 -04:00
Ok([signing_input, signature].join("."))
}
/// Used in decode: takes the result of a rsplit and ensure we only get 2 parts
/// Errors if we don't
macro_rules! expect_two {
($iter:expr) => {{
let mut i = $iter;
match (i.next(), i.next(), i.next()) {
(Some(first), Some(second), None) => (first, second),
2018-10-28 14:58:35 -04:00
_ => return Err(new_error(ErrorKind::InvalidToken)),
2017-04-13 03:36:32 -04:00
}
2018-10-28 14:58:35 -04:00
}};
2017-04-13 03:36:32 -04:00
}
/// Decode a token into a struct containing 2 fields: `claims` and `header`.
///
/// If the token or its signature is invalid or the claims fail validation, it will return an error.
///
/// ```rust,ignore
/// #[macro_use]
/// extern crate serde_derive;
2017-10-22 07:20:01 -04:00
/// use jsonwebtoken::{decode, Validation, Algorithm};
2017-04-13 03:36:32 -04:00
///
/// #[derive(Debug, Serialize, Deserialize)]
/// struct Claims {
/// sub: String,
/// company: String
/// }
///
/// let token = "a.jwt.token".to_string();
/// // Claims is a struct that implements Deserialize
2017-10-22 07:20:01 -04:00
/// let token_data = decode::<Claims>(&token, "secret", &Validation::new(Algorithm::HS256));
2017-04-13 03:36:32 -04:00
/// ```
2018-10-28 14:58:35 -04:00
pub fn decode<T: DeserializeOwned>(
token: &str,
key: &[u8],
validation: &Validation,
) -> Result<TokenData<T>> {
2017-04-13 03:36:32 -04:00
let (signature, signing_input) = expect_two!(token.rsplitn(2, '.'));
2017-04-22 02:21:16 -04:00
let (claims, header) = expect_two!(signing_input.rsplitn(2, '.'));
let header: Header = from_jwt_part(header)?;
2017-04-13 03:36:32 -04:00
if !verify(signature, signing_input, key, header.alg)? {
2018-07-25 08:43:58 -04:00
return Err(new_error(ErrorKind::InvalidSignature));
2017-04-13 03:36:32 -04:00
}
2017-10-22 07:20:01 -04:00
if !validation.algorithms.contains(&header.alg) {
2018-07-25 08:43:58 -04:00
return Err(new_error(ErrorKind::InvalidAlgorithm));
2017-04-13 03:36:32 -04:00
}
2017-04-22 02:21:16 -04:00
2018-10-28 14:58:35 -04:00
let (decoded_claims, claims_map): (T, _) = from_jwt_part_claims(claims)?;
validate(&claims_map, validation)?;
2017-04-13 03:36:32 -04:00
Ok(TokenData { header, claims: decoded_claims })
2017-04-13 03:36:32 -04:00
}
/// Decode a token without any signature validation into a struct containing 2 fields: `claims` and `header`.
///
/// 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.
///
/// ```rust,ignore
/// #[macro_use]
/// extern crate serde_derive;
/// use jsonwebtoken::{dangerous_unsafe_decode, Validation, Algorithm};
///
/// #[derive(Debug, Serialize, Deserialize)]
/// struct Claims {
/// sub: String,
/// company: String
/// }
///
/// let token = "a.jwt.token".to_string();
/// // Claims is a struct that implements Deserialize
/// let token_data = dangerous_unsafe_decode::<Claims>(&token, &Validation::new(Algorithm::HS256));
/// ```
pub fn dangerous_unsafe_decode<T: DeserializeOwned>(token: &str) -> Result<TokenData<T>> {
let (_, signing_input) = expect_two!(token.rsplitn(2, '.'));
let (claims, header) = expect_two!(signing_input.rsplitn(2, '.'));
let header: Header = from_jwt_part(header)?;
2018-10-28 14:58:35 -04:00
let (decoded_claims, _): (T, _) = from_jwt_part_claims(claims)?;
2018-10-28 14:58:06 -04:00
Ok(TokenData { header, claims: decoded_claims })
}
/// Decode a token and return the Header. This is not doing any kind of validation: it is meant to be
2017-09-08 03:23:15 -04:00
/// used when you don't know which `alg` the token is using and want to find out.
///
2017-09-08 03:23:15 -04:00
/// If the token has an invalid format, it will return an error.
///
/// ```rust,ignore
/// use jsonwebtoken::decode_header;
///
/// let token = "a.jwt.token".to_string();
/// let header = decode_header(&token);
/// ```
pub fn decode_header(token: &str) -> Result<Header> {
let (_, signing_input) = expect_two!(token.rsplitn(2, '.'));
let (_, header) = expect_two!(signing_input.rsplitn(2, '.'));
from_jwt_part(header)
}