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

May 12, 2024

Canvas Gravity Balls

Pet project simulating bouncing balls with gravity, collisions, and elasticity on HTML Canvas.

JavaScriptHTML CanvasPhysics
February 19, 2026

Trypema Rate Limiter

High-performance Rust rate limiting primitives with local, Redis-backed, and hybrid providers, atomic Redis enforcement, and absolute/suppressed strategies.

RustRate LimitingRedis
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

Let's build something together

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

© 2026 David Oyinbo