Search code examples
rustjwtrust-result

Read claims without verification. , Understanding the Result return


I'm working JWT's in Rust and have come across a situation that I'm having some issues navigating. I'm new to both Rust and JWT's, so bare with me.

I'm using the jwt crate found here.

What I want to do is create a Signed JWT that contains a header and claims. The claims have a single field, issuer. I'm able to issue a new token with no issue.

fn issue_token(user_id: &str) -> Result<String, &'static str> {
    let header: Header = Default::default();
   
    let claims = RegisteredClaims {
        issuer: Some("user who issued token".into()),
        subject: Some(user_id.into()),
        ..Default::default()
    };

    let unsigned_token = Token::new(header, claims);

    let key: Hmac<Sha256> =
        Hmac::new_from_slice("secret_key".as_bytes()).map_err(|_e| "Invalid key")?;

    let signed_token = unsigned_token
        .sign_with_key(&key)
        .map_err(|_e| "Sign error")?;

    Ok(signed_token.into())
}

The issuer claim is important. As there are different processes that have their own tokens. All of the issuers have already registered their secret with the main server. Now, other users will connect to a specific issuer, validate who the user is, and will issue a JWT that has been signed. The user does not know what the secret is, that's only known between the issuer and the server.

What I'm trying to do, on the server-side, is read the claims to identify who the issuer is. Once I know who the issuer is I then know what secret to use to verify the signature.

I have no issues verifying the token, and once I verify the token, I'm able to read the claims. But I need to read the claims first, and then verify the token.

beyond the basic examples for signing and verifying, the documentation is clear to me.

looking at the documentation for the crate, here, I've not been able to figure out how to implement what I'm attempting to do.

I've found what I believe to be what I'm looking for, here, parse_unverified or Unverified, but I'm struggling to figure out how to use either.

parse_unverified looks to be the more promising of the two as the documentation states Not recommended. Parse the header and claims without checking the validity of the signature

Does anyone have any experience with Rust and the jwt crate?

I believe I've gotten it partially figured out.

it starts with importing the correct crate options

use jwt::{Claims, Error, Header, RegisteredClaims, Token, Unverified, VerifyWithKey};

I can then create a new variable, like

let unverified: Result<Token<Header, Claims, Unverified<'_>>, Error> =
            Token::parse_unverified(token);

Now this works, it builds and runs just fine. What I'm having an issue with now is actually parsing unverified now.

the more that I look at it, I think this might have less to do with JWT and more to do with standard Rust operations. As its returning a Result.

Any insight?


Solution

  • It's a standard Result, so you have to unwrap that as usual with ? to get at the Token inside. Even though this doesn't verify the signature, it can still fail due to invalid base64/JSON encoding or JWT framing. (If there's an error here the token isn't even structurally valid, so there's no point in going further.)

    let unverified: Token<Header, Claims, _> = Token::parse_unverified(token)?;
    

    Now you can use any facilities provided by Token on unverified, e.g. unverified.claims().

    You might want to parse with RegisteredClaims though, which gives you easier access to the issuer field:

    let unverified: Token<Header, RegisteredClaims, _> =
        Token::parse_unverified(token)?;
    
    let issuer = unverified.claims().issuer.as_ref()
        .ok_or(MissingIssuerError)?;
    

    issuer will be a &String. (MissingIssuerError is a placeholder for an error you can raise if the issuer field is absent.)