Adding header to a http request with Swagger

I'm using the utoipa crate in order to create a Swagger UI. I need to add a header and this doesn't work. Do I have to add something to my function?

#[utoipa::path(
    context_path = "/tools",
    tag = "tools",
    params(
        ("url", 
            description = "URL that should be scanned for fingerprints.", 
            example = "https://example.com"
        ),
        ("authorization" = String, Header, description = "JWT")
    ),
    responses(
        (status = 200, description = "JSON output of the blacklight collector.", body = String),
        (status = 401, description = "Unauthorized request."),
        (status = 400, description = "Wrong URL.", body = String)
    )
)]
#[get("/blacklight/{url}")]
pub async fn blacklight(
    path: web::Path<String>, 
    claims: Option<web::ReqData<Claims>>
) -> impl Responder {
    let url: String = path.into_inner();

    match url_check::is_url(url.as_str()) {
        true => {
            if let Some(claims) = claims {
                publish_service::publisher(claims.sub.clone(), &url);
            }

            HttpResponse::Ok().json("Ok")
        },
        false => HttpResponse::BadRequest().body("ProtocolError: Cannot navigate to invalid URL")
    }
}

It works if I use curl to create a request.

I assume you have to do something like described here to make your Swagger UI add a bearer token to your requests. Judging from the Utoipa docs, you can't define components/securitySchemes with Utoipa the utoipa::OpenApi derive macro yet:

Currently only schema and response components are supported.


Edit: Utoipa provides the types needed to describe security schemes, including bearer tokens. I'm not sure how to use them to create the right spec, but probably in conjunction with the OpenApiBuilder type.

Ok, it is weird that I can add the Header param.

This Header param means that there's some custom parameter passed via header:

  • in Must be placed after name or parameter_type. Define the place of the parameter. This must be one of the variants of openapi::path::ParameterIn. E.g. Path, Query, Header, Cookie

It's not used for Swagger UI authorization, if that's what you want.

I figured it out. Here is the solution:

In Swagger this trait needs to be implemented with the bearerAuth scheme.

The trait has to look like this:

impl Modify for SecurityAddon {
    fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
        let components: &mut utoipa::openapi::Components = openapi.components.as_mut().unwrap(); // we can unwrap safely since there already is components registered.
        components.add_security_scheme(
            "bearerAuth",
            SecurityScheme::Http(Http::new(HttpAuthScheme::Bearer)),
        )
    }
}

And the endpoint attribute has to look like this:

#[utoipa::path(
    context_path = "/tools",
    tag = "tools",
    params(
        ("url", 
            description = "URL that should be scanned for fingerprints", 
            example = "https://example.com"
        )
    ),
    responses(
        (status = 200, description = "JSON output of the blacklight collector", body = String),
        (status = 401, description = "Access token is missing or invalid"),
        (status = 400, description = "URL is missing or invalid", body = String)
    ),
    security(
        ("bearerAuth" = [])
    )
)]
#[get("/blacklight/{url}")]
pub async fn blacklight(
    path: web::Path<String>, 
    claims: Option<web::ReqData<Claims>>
) -> impl Responder {
    let url: String = path.into_inner();

    match url_check::is_url(url.as_str()) {
        true => {
            if let Some(claims) = claims {
                publish_service::publisher(claims.sub.clone(), &url);
            }

            HttpResponse::Ok().json("Ok")
        },
        false => HttpResponse::BadRequest().body("Cannot navigate to invalid URL")
    }
}

An example for the complete security-scheme can be found here.

1 Like