use crate::{Error, Result, utils, Header};
pub fn decode<P>(
token: &str,
secret_key: &[u8],
) -> Result<P>
where
P: serde::de::DeserializeOwned,
{
let parts: Vec<&str> = token.split('.').collect();
if parts.len() < 3 {
return Err(Error::InvalidTokenLength);
}
let header = utils::from_json_b64::<Header>(parts[0])?;
let payload = utils::from_json_b64::<P>(parts[1])?;
let signature = parts[2];
let unsigned_jwt = format!("{}.{}", parts[0], parts[1]);
let expected_signature = header.alg.sign_fn()(unsigned_jwt.as_bytes(), secret_key)?;
let expected_signature_encoded = utils::to_b64(&expected_signature);
if signature != expected_signature_encoded {
return Err(Error::InvalidTokenSignature);
}
Ok(payload)
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct Claims {
pub user: String,
pub age: u16,
pub is_admin: bool,
}
const SECRET_KEY: &[u8] = b"super_secret_key";
#[test]
fn decode_success() {
let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoidXNlcm5hbWUiLCJhZ2UiOjEyOCwiaXNfYWRtaW4iOnRydWV9.3dTbG3tFs2QBcxkxmpxnRzPdCi-fpe9YzoLWX-lBBl0";
let decoded = decode::<Claims>(token, SECRET_KEY);
assert!(decoded.is_ok(), "Should be ok");
assert_eq!(Claims {user: String::from("username"), age: 128, is_admin: true }, decoded.unwrap());
}
#[test]
fn decode_fail_token_length() {
let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoidXNlcm5hbWUiLCJhZ2UiOjEyOCwiaXNfYWRtaW4iOnRydWV9";
let decoded = decode::<Claims>(token, SECRET_KEY);
match decoded {
Err(err) => match err {
crate::error::Error::InvalidTokenLength => (),
_ => panic!("Decoded isn't a InvalidTokenLength"),
},
_ => panic!("Decoded isn't a error"),
}
}
#[test]
fn decode_fail_token_signature() {
let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoidXNlcm5hbWUiLCJhZ2UiOjEyOCwiaXNfYWRtaW4iOnRydWV9.aR3g11ENGu8Bc5GfF5kNFbFVwEgmzyt-wl1w_gIPv9E";
let decoded = decode::<Claims>(token, SECRET_KEY);
match decoded {
Err(err) => match err {
crate::error::Error::InvalidTokenSignature => (),
_ => panic!("Decoded isn't a InvalidTokenSignature"),
},
_ => panic!("Decoded isn't a error"),
}
}
}