#security #permissions #grant #web-api #actix

actix-web-grants

Authorization extension actix-web to protect your endpoints

28 releases (15 stable)

4.1.1 May 29, 2024
4.1.0 Mar 31, 2024
4.0.3 Dec 8, 2023
4.0.1 Nov 30, 2023
0.1.6 Jan 17, 2021

#29 in Authentication

Download history 3538/week @ 2024-07-30 3232/week @ 2024-08-06 2087/week @ 2024-08-13 3400/week @ 2024-08-20 3587/week @ 2024-08-27 3594/week @ 2024-09-03 2890/week @ 2024-09-10 2668/week @ 2024-09-17 3373/week @ 2024-09-24 2568/week @ 2024-10-01 1757/week @ 2024-10-08 2733/week @ 2024-10-15 4080/week @ 2024-10-22 3452/week @ 2024-10-29 2931/week @ 2024-11-05 2518/week @ 2024-11-12

13,529 downloads per month
Used in 3 crates (2 directly)

MIT/Apache

36KB
286 lines

actix-web-grants

actix-web-grants

Authorization extension for actix-web to protect your endpoints.

Crates.io Downloads Badge crates.io Documentation Apache 2.0 or MIT licensed

To check user access to specific services, you can use built-in proc-macro, AuthorityGuard or manual.

The library can also be integrated with third-party solutions (like actix-web-httpauth).

How to use

  1. Declare your own authority extractor

The easiest way is to declare a function with the following signature (trait is already implemented for such Fn):

use actix_web::{dev::ServiceRequest, Error};

// You can use custom type instead of String
async fn extract(req: &ServiceRequest) -> Result<HashSet<String>, Error>
  1. Add middleware to your application using the extractor defined in step 1
App::new()
    .wrap(GrantsMiddleware::with_extractor(extract))

Steps 1 and 2 can be replaced by custom middleware or integration with another libraries. Take a look at an jwt-httpauth example

  1. Protect your endpoints in any convenient way from the examples below:

Example of proc-macro way protection

#[get("/secure")]
#[actix_web_grants::protect("OP_READ_SECURED_INFO")]
async fn macro_secured() -> HttpResponse {
    HttpResponse::Ok().body("ADMIN_RESPONSE")
}
Example of ABAC-like protection and custom authority type

Here is an example using the ty and expr attributes. But these are independent features.

expr allows you to include some checks in the macro based on function params, it can be combined with authorities by using all/any.

ty allows you to use a custom type for th authorities (then the middleware needs to be configured). Take a look at an enum-role example

use enums::Role::{self, ADMIN};
use dto::User;

#[get("/info/{user_id}")]
#[actix_web_grants::protect("ADMIN", expr = "user_id.into_inner() == user.id", ty = "Role")]
async fn macro_secured(user_id: web::Path<i32>, user: web::Data<User>) -> HttpResponse {
    HttpResponse::Ok().body("some secured response")
}

#[post("/info/{user_id}")]
#[actix_web_grants::protect(any("ADMIN", expr = "user.is_super_user()"), ty = "Role")]
async fn admin_or_super_user(user_id: web::Path<i32>, user: web::Data<User>) -> HttpResponse {
    HttpResponse::Ok().body("some secured response")
}

Example of Guard way protection

use actix_web_grants::{AuthorityGuard, GrantsMiddleware};

App::new()
    .wrap(GrantsMiddleware::with_extractor(extract))
    .service(web::resource("/admin")
            .to(|| async { HttpResponse::Ok().finish() })
            .guard(AuthorityGuard::new("ROLE_ADMIN".to_string())))
    .service(web::resource("/admin") // fallback endpoint if you want to return a 403 HTTP code 
            .to(|| async { HttpResponse::Forbidden().finish() }))
Example of custom fallback endpoint for `Scope` with `Guard`

Since Guard is intended only for routing, if the user doesn't have authorities, it returns a 404 HTTP code. But you can override the behavior like this:

use actix_web_grants::{AuthorityGuard, GrantsMiddleware};
use actix_web::http::header;

App::new()
    .wrap(GrantsMiddleware::with_extractor(extract))
    .service(web::scope("/admin")
        .guard(AuthorityGuard::new("ROLE_ADMIN_ACCESS".to_string()))
        .service(web::resource("/users")
            .to(|| async { HttpResponse::Ok().finish() }))
    ).service(
        web::resource("/admin{regex:$|/.*?}").to(|| async { 
            HttpResponse::TemporaryRedirect().append_header((header::LOCATION, "/login")).finish()
        }))

When Guard lets you in the Scope (meaning you have "ROLE_ADMIN_ACCESS"), the redirect will be unreachable for you. Even if you will request /admin/some_undefined_page.

Note: regex is a Path variable containing passed link.

Example of manual way protection

use actix_web_grants::authorities::{AuthDetails, AuthoritiesCheck};

async fn manual_secure(details: AuthDetails) -> HttpResponse {
    if details.has_authority(ROLE_ADMIN) {
        return HttpResponse::Ok().body("ADMIN_RESPONSE");
    }
    HttpResponse::Ok().body("OTHER_RESPONSE")
}

You can find more examples in the git repository folder and documentation.

Supported actix-web versions

  • For actix-web-grants: 2.* supported version of actix-web is 3.*
  • For actix-web-grants: 3.* & 4.* supported version of actix-web is 4.*

Dependencies

~15–25MB
~432K SLoC