crates.io ↗

iet-authz

core contracts official

Defines the ports for roles, resource grants, and policy decisions.

CoreFeaturesIntegrationsStacksTooling
Used byiet-auth-acliet-auth-acl-timescaleiet-auth-rbaciet-auth-rbac-timescale
iet-authzcontractsAuthorization contracts
Depends oniet-corecontract

How to use it

iet-authz defines the authorization ports (RoleStore, AccessStore, ResourceAuthorizer) and combinators, and re-exports iet_core::Authorizer. All/Any let you compose policies, while DenyPermissions is the fail-closed default for authenticated-only applications.

rust
// crates/core/iet-authz/tests/composition.rs
use iet_authz::{All, Any, Authorizer};
use iet_core::{AppError, AppResult, CallContext, ErrorKind};

struct Policy(Option<ErrorKind>);
impl Authorizer for Policy {
    async fn authorize(&self, _: &CallContext, _: &str) -> AppResult<()> {
        self.0.map_or(Ok(()), |kind| {
            Err(AppError::new(kind, "test.policy", "Policy result"))
        })
    }
}

// Both must allow; a denial from either propagates.
All(Policy(None), Policy(Some(ErrorKind::Forbidden)))
    .authorize(&CallContext::default(), "read")
    .await?;
// The first Forbidden falls through to the second; other errors do not.
Any(Policy(Some(ErrorKind::Forbidden)), Policy(None))
    .authorize(&CallContext::default(), "read")
    .await?;
  • Any swallows only ErrorKind::Forbidden; Unavailable, Internal, or Unauthenticated from the first policy are returned unchanged.
  • DenyPermissions always returns ErrorKind::Forbidden (authz.denied), so a permission-protected operation can never accidentally succeed.

How it works

A CallContext and a permission string are given to some Authorizer. All and Any compose two policies, forwarding the decision and treating only ErrorKind::Forbidden from the first as a fall-through; DenyPermissions fails closed.

flowchart LR
  A["CallContext and permission"] --> B["Authorizer::authorize"]
  B --> C["All"]
  B --> D["Any"]
  B --> E["DenyPermissions"]
  C --> F["both must allow"]
  D --> G["Forbidden falls through"]
  E --> H["always Forbidden"]

Core contract

This page is the crate reference. For the framework-wide runtime and trait model, read Architecture.

What it implements

  • Defines the traits other crates implement: RoleStore, AccessStore, ResourceAuthorizer.

What's inside

Modules

  • src/lib.rs

Public API

(root)

  • struct DenyPermissions — Explicit deny-by-default policy for applications with authenticated-only operations. Permission-protected operations cannot accidentally succeed.
  • trait RoleStore
rust
pub trait RoleStore: Send + Sync {
    fn allows(
        &self,
        identity: &Principal,
        permission: &str,
    ) -> impl Future<Output = AppResult<bool>> + Send;
}
  • trait AccessStore
rust
pub trait AccessStore: Send + Sync {
    fn allows(
        &self,
        identity: &Principal,
        action: &str,
        resource: &str,
    ) -> impl Future<Output = AppResult<bool>> + Send;
}
  • trait ResourceAuthorizer
rust
pub trait ResourceAuthorizer: Send + Sync {
    fn authorize(
        &self,
        context: &CallContext,
        action: &str,
        resource: &str,
    ) -> impl Future<Output = AppResult<()>> + Send;
}
  • pub fn identity(context: &CallContext) -> AppResult<&Principal>
  • pub fn denied() -> AppError
  • struct All
  • struct Any

Impl map

  • Authorizer for DenyPermissions
  • Authorizer for All<A, B>
  • Authorizer for Any<A, B>
  • Authorizer for Policy

Depends on

Used by

In this repository

  • examples/handbook-notes
  • examples/htmx-starter
  • examples/skills-only-app-task-tracker

Source: crates/core/iet-authz