mikkyang / rust-jwt

JSON Web Token library for Rust
MIT License
176 stars 38 forks source link

Error when using generics `missing field` #89

Open ilmari-h opened 1 year ago

ilmari-h commented 1 year ago

I get the error missing field exp at line 1 column 160 with the following struct using a generic parameter T in my JWT claims. The error is raised when calling verify_with_key

This is the type of my claims:

#[derive(Deserialize, Serialize, Clone)]
pub struct AuthJWT<T> {
    pub exp: usize,
    pub iat: usize,
    pub payload: T,
}

However, I get no such error when I leave out the generic T, and instead just use the exact same struct: in both cases User is the type of the payload.

#[derive(Deserialize, Serialize, Clone)]
pub struct AuthJWT {
    pub exp: usize,
    pub iat: usize,
    pub payload: User,
}

Am I missing something or is this a bug? Any help is appreciated.

gpollatos commented 12 months ago

Hi, I am very very new to Rust and am using this library. I am doing something similar but can't say I see any issue. I tried adapting your snippet above and reproduce what you are reporting but it seems to be working as expected. Please have a look:

#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)]
pub struct User {
    pub id: String,
    pub nickname: String,
    pub email: String,
}

#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)]
pub struct AuthJWT<T> {
    pub exp: usize,
    pub iat: usize,
    pub payload: T,
}

fn main() {
    let user = User {
        id: String::from("some-id"),
        nickname: String::from("some-nickname"),
        email: String::from("some-email")
    };
    let claim: AuthJWT<User> = AuthJWT {
        exp: usize::MAX,
        iat: usize::MAX,
        payload: user,
    };
    let tok = create_jwt(claim, b"some-secret");
    let u = verify_jwt(tok.as_str(), "some-secret").unwrap();
    println!("{:?}", u);
}

pub fn create_jwt(c: AuthJWT<User>, secret_key: &[u8]) -> String {
    let jwt_key: Hmac<Sha256> = Hmac::new_from_slice(secret_key).unwrap();
    let mut new_claim = BTreeMap::new();
    new_claim.insert("claim", c);
    return new_claim.sign_with_key(&jwt_key).unwrap();
}

pub fn verify_jwt(jwt_value: &str, secret_key: &str) -> Option<AuthJWT<User>> {
    let new_key: Hmac<Sha256> = Hmac::new_from_slice(secret_key.as_bytes()).unwrap();
    let result: Result<BTreeMap<String, AuthJWT<User>>, Error> = jwt_value.verify_with_key(&new_key);
    match result {
        Ok(existing_claim) => Some(existing_claim["claim"].clone()),
        Err(_) => None
    }
}

Output:

cargo run
...
AuthJWT { exp: 18446744073709551615, iat: 18446744073709551615, payload: User { id: "some-id", nickname: "some-nickname", email: "some-email" } }