May 13, 2026   -   David Oyinbo

Laye

A framework-agnostic role and permission based access control library for Rust. Implement the Principal trait on your auth type, build composable AccessPolicy rules, and wire the provided middleware into actix-web or tower/axum.

RustRBACAccess ControlLibraryActix WebAxum

Overview

Laye handles the authorization layer without dictating how you authenticate. You implement the Principal trait on whatever auth struct your application already uses, giving laye access to roles, permissions, and authentication state. From there you compose policies using require_all (AND) and require_any (OR), and attach the middleware to any route. Unauthenticated requests get a 401; authenticated but unauthorized requests get a 403. The library ships with optional feature flags for actix-web and tower so you only pull in what you need.

Usage

Implement Principal

use laye::Principal;

#[derive(Clone)]
struct MyUser {
    roles: Vec<String>,
    permissions: Vec<String>,
    authenticated: bool,
}

impl Principal for MyUser {
    fn roles(&self) -> &[String] { &self.roles }
    fn permissions(&self) -> &[String] { &self.permissions }
    fn is_authenticated(&self) -> bool { self.authenticated }
}

Define a Policy

use laye::{AccessPolicy, AccessRule};

let policy = AccessPolicy::require_all()
    .add_rule(AccessRule::Authenticated)
    .add_policy(
        AccessPolicy::require_any()
            .add_rule(AccessRule::Role("admin".into()))
            .add_rule(AccessRule::Role("editor".into())),
    );

Wire into actix-web

[dependencies]
laye = { version = "0.1", features = ["actix-web"] }
use laye::actix::PolicyMiddlewareFactory;

App::new()
    .service(
        web::resource("/admin")
            .wrap(PolicyMiddlewareFactory::new(policy))
            .route(web::get().to(handler)),
    )

Wire into axum/tower

[dependencies]
laye = { version = "0.1", features = ["tower"] }
use laye::tower::AccessControlLayer;

let app = Router::new()
    .route("/admin", get(handler))
    .layer(AccessControlLayer::new(policy));

Highlights

Policy DSL

  • require_all for AND logic across rules and nested policies
  • require_any for OR logic
  • Unlimited nesting depth for complex access scenarios

Framework Support

  • actix-web middleware via PolicyMiddlewareFactory
  • tower/axum middleware via AccessControlLayer
  • Feature flags keep unused framework code out of your binary

HTTP Responses

  • 401 Unauthorized for requests with no authenticated principal
  • 403 Forbidden for authenticated but policy-failing requests
  • No manual status code handling needed in your handlers

Ergonomics

  • Zero coupling to your auth implementation
  • Bring your own user struct, roles, and permissions
  • Minimal install: laye = "0.1" for the core with no framework overhead

Other Projects

October 1, 2021

Payaza Web SDK

A JavaScript Web SDK that simplifies integrating Payaza checkout on web applications. Built as part of my role at Payaza Africa.

SDKJavaScriptPayments
December 4, 2024

Country flags and currency package

Lightweight TypeScript library for country flags, capitals, dial codes, currencies, and simple location distance utilities.

TypeScriptLibraryNPM
January 22, 2025

Auth module for Nuxt server apps

Auth module for Nuxt 3 server apps with local and social providers, tokens, middlewares, and typed composables.

TypeScriptNuxt 3Auth

Let's build something together

Available for senior engineering roles, consulting, and architecture reviews.

© 2026 David Oyinbo