I want to write a function that intercepts the HttpRequest
of an actix-web route handler. In the function, I want to extract the Authorization header JWT and decode it. If it succeeds, I want to return the claims. If not, I want to send a 401 response and return an error:
fn extract_jwt(req: HttpRequest) -> Result<TokenData<Claims>, anyhow::Error> {
// forgive me my unwraps
let authorization_header = req
.headers()
.get("Authorization")
.unwrap()
.to_str()
.unwrap();
let token = authorization_header
.split_whitespace()
.collect::<Vec<&str>>()[1];
let key = DecodingKey::from_secret(&[]);
let mut validation = Validation::new(Algorithm::HS256);
validation.insecure_disable_signature_validation();
validation.set_audience(&["account"]);
match decode::<Claims>(&token, &key, &validation) {
Ok(claims) => Ok(claims),
Err(e) => {
HttpResponse::Unauthorized().finish();
anyhow::Error("Could not decode JWT: {:?}", e) // error here
}
}
}
In my match
arms, I return either the claims
, which is the TokenData<Claims>
of the Result
, and Rust is happy with that. But for the Err
arm, I get the error:
expected function, tuple struct or tuple variant, found struct `anyhow::Error`
Clearly I am not understanding how to propagate this error back to the caller. For example, in any given route, I want to extract the JWT with this function:
#[get("/some/route")]
async fn get_things(req: HttpRequest) {
if let claims = extract_jwt(req) {
// Handle the route logic here
// If there is an error in extract_jwt, it should handle sending the response
// as Unauthorized, so there is no need for an `else` statement here
}
}
Despite pouring over the Rust docs about match
statements, the Result
enum, and propagating errors, I haven't found the right combination to set this up right. What am I missing here?
anyhow::Error
is a struct with private fields, so you can't construct it directly. In other words anyhow::Error("Could not decode JWT: {:?}", e)
is invalid code.
Because you use a println
like syntax it's likely you meant to use the macro anyhow::anyhow
instead.
That leaves another problem still, your function returns a Result
that means any returned value has to be constructed with either Ok()
or Err()
. So you'll have to add that as well.
TL;DR replace anyhow::Error("Could not decode JWT: {:?}", e)
with Err(anyhow::anyhow!("Could not decode JWT: {:?}", e))