Jwt token extractor - actix web

I am trying to build an extractor in actix_web where I extract a Bearer token from an Authorization header, decode the JWT token and store it in a struct.

use actix_web::dev::Payload;
use actix_web::{FromRequest, HttpRequest, HttpResponse};
use std::future::{ready, Ready};
use uuid::Uuid;

use crate::domain::UserRoles;

use crate::helpers::unauthorized_error;
use crate::services::{JwtService, JwtTokenType};

#[derive(Debug)]
pub struct AuthedUser {
    id: Uuid,
    tenant: Uuid,
    role: UserRoles,
}

impl FromRequest for AuthedUser {
    type Error = HttpResponse;
    type Future = Ready<Result<AuthedUser, Self::Error>>;

    fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future {
        let authorization_header = req.headers().get("Authorization").ok_or(|_| {
            tracing::error!("No 'Authorization' header present");
            ready(Err(unauthorized_error()))
        })?;

        // Extract JWT token from 'Authorization header'
        let bearer_token: Vec<&str> = authorization_header
            .to_str()
            .map_err(|e| {
                tracing::error!("Header should only contain ASCII characters: {}", e);
                ready(Err(unauthorized_error()))
            })?
            .split_whitespace()
            .collect();

        // Make sure that it is a Bearer token
        if bearer_token[0] != "Bearer" {
            tracing::error!("Authorization header is not a Bearer token");
            return ready(Err(unauthorized_error()));
        }

        let token = bearer_token[1];

        // Get secret key to decode JWT token
        let token_data = JwtService::decode(token, JwtTokenType::AccessToken).map_err(|e| {
            tracing::error!("Header should only contain ASCII characters: {}", e);
            ready(Err(unauthorized_error()))
        })?;

        ready(Ok(Self {
            id: token_data.user_id,
            tenant: token_data.tenant_id,
            role: token_data.user_role,
        }))
    }
}

I get the following errors:

error: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`)

note: required because of the requirements on the impl of `std::convert::From<HttpResponse>` for `actix_web::Error`
label: the trait `ResponseError` is not implemented for `HttpResponse`

How can I return the errors in this situation? The function unauthorized_error simply returns HttpResponse::Unauthorized().finish()

You can't use the question mark operator if the function returns a future in this way. Consider extracting the implementation into a standalone function that returns a Result<AuthedUser, Self::Error> and then implement from_request like this:

fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
    ready(my_helper_fn(req, payload))
}

Then you will be able to use the question mark inside the helper function.

Thank you! I managed to make it work with this solution.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.