Keats / jsonwebtoken

JWT lib in rust
MIT License
1.66k stars 266 forks source link

Validating Google Login Tokens #326

Open Tapwatero opened 1 year ago

Tapwatero commented 1 year ago

I am quite sorry - as despite my best efforts and research I could not find any conclusive way of decoding google jwts.

Google uses RS256 to sign the tokens I receieve.


    match jsonwebtoken::decode::<Claims>(body.jwt.to_string().as_str(), &DecodingKey::from_secret(env::var("SECRET").unwrap().as_ref()), &Validation::new(Algorithm::RS256)) {
        Ok(res) => {
            println!("{:?}", res);
        },
        Err(error) => {
            println!("{error:}");
        }
    }

Doing this results in InvalidAlgorithm. Anyone know how to fix this.

Keats commented 1 year ago

There is not enough information to resolve the issue. Can you provide an example key and JWT?

nlopes commented 10 months ago

I might be able to help. Instead of doing Validation::new(Algorithm::RS256) do Validation::new(header.alg) where header is:

let header = jwt::decode_header(jwt);

In total it should be something like:

# Let's assume your jwt content is in a `&str` named `jwt` and
# const GOOGLE_APIS_TOKEN_URL: &str = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com";

let header = jwt::decode_header(jwt);

match header.kid {
  None => { oops },
  Some(kid) => {
       let secret = tokens /* this comes from the content at the url GOOGLE_APIS_TOKEN_URL (I've put it into a HashMap mapping kid to the secret */
                .get(kid.as_str())?;
        let jwt_payload = jwt::decode::<Claims>(
                jwt,
                &jwt::DecodingKey::from_rsa_pem(secret.as_bytes())?,
                &jwt::Validation::new(header.alg),
            )?;
  }
}

The above is some copy&paste from a project and some "old" knowledge so forgive me if I got something wrong.

Ali-Javanmardi commented 9 months ago

I might be able to help. Instead of doing Validation::new(Algorithm::RS256) do Validation::new(header.alg) where header is:

let header = jwt::decode_header(jwt);

In total it should be something like:

# Let's assume your jwt content is in a `&str` named `jwt` and
# const GOOGLE_APIS_TOKEN_URL: &str = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com";

let header = jwt::decode_header(jwt);

match header.kid {
  None => { oops },
  Some(kid) => {
       let secret = tokens /* this comes from the content at the url GOOGLE_APIS_TOKEN_URL (I've put it into a HashMap mapping kid to the secret */
                .get(kid.as_str())?;
        let jwt_payload = jwt::decode::<Claims>(
                jwt,
                &jwt::DecodingKey::from_rsa_pem(secret.as_bytes())?,
                &jwt::Validation::new(header.alg),
            )?;
  }
}

The above is some copy&paste from a project and some "old" knowledge so forgive me if I got something wrong.

@nlopes , I think there is a security risk in your suggested code. there is a known trick that someone can make a crafted token and sign it by a well known RS256 public key but with HS256 algorithm, So when your code trust on the algorithm introduced by token header it will validate token by HS256 instead of RS256 and falsely validate it as true.

Codename-404 commented 5 months ago

Same issue, i can't verify jwt from google oauth.

            `let token = decode::<Claims>(
                &google_res.id_token,
                &DecodingKey::from_secret(google_client_secret.as_ref()),
                &Validation::new(Algorithm::RS256),
            );`

            this always returns InvalidAlgorithm
Codename-404 commented 5 months ago
     ` let key = DecodingKey::from_secret(&[]);
            let mut validation = Validation::new(Algorithm::HS256);
            validation.insecure_disable_signature_validation();
            validation.validate_exp = false;
            validation.validate_aud = false;

            let payload = decode::<GoogleTokenInfo>(&google_res.id_token, &key, &validation);`

This is how you can decode google token, as it's coming from google and verified there, we don't need to verify again anyway. However make sure to verify your own token with your secret before using any claims.