# Access Control Mechanism in Buzz: NIP-42 Authentication and Scope-Based Authorization

> Discover Buzz's NIP-42 authentication and scope-based authorization. Learn how Buzz uses a token-less access control system for secure communication.

- Repository: [Block Open Source/buzz](https://github.com/block/buzz)
- Tags: how-to-guide
- Published: 2026-08-28

---

**Buzz implements a cryptographic, token-less access control system based on NIP-42 Nostr authentication and fine-grained scopes enforced via the `buzz-auth` crate.**

The **access control mechanism in Buzz** combines decentralized identity verification with declarative permission scopes to secure the Nostr relay. Built in the `block/buzz` repository, this architecture leverages the [`buzz-auth`](https://github.com/block/buzz/tree/main/crates/buzz-auth) crate to authenticate users via signed challenges and authorize actions through role-based scopes defined in the source code.

## How Buzz Authenticates Requests with NIP-42

Buzz uses **NIP-42** (Nostr Authentication) to establish identity without traditional API tokens. According to the source code in [[`crates/buzz-auth/src/nip42.rs`](https://github.com/block/buzz/blob/main/crates/buzz-auth/src/nip42.rs)](https://github.com/block/buzz/blob/main/crates/buzz-auth/src/nip42.rs), clients prove ownership of a Nostr public key by signing a server-generated challenge.

### Challenge-Response Flow and `AuthService`

The authentication flow centers on cryptographic signatures. When a client connects, the server issues a unique challenge string that the client must sign with their private key. The `AuthService` in [[`lib.rs`](https://github.com/block/buzz/blob/main/lib.rs)](https://github.com/block/buzz/blob/main/crates/buzz-auth/src/lib.rs) validates this signature against the claimed public key before generating an `AuthContext` that carries the user's identity and permissions.

```rust
use buzz_auth::{AuthService, AuthError};

let auth_service = AuthService::new(config);
match auth_service.authenticate(event) {
    Ok(auth_ctx) => {
        // auth_ctx now holds the public key and its scopes
        println!("Authenticated pubkey: {}", auth_ctx.pubkey);
    }
    Err(AuthError::InvalidSignature) => {
        eprintln!("Auth failed – bad signature");
    }
    Err(e) => return Err(e),
}

```

## Scope-Based Authorization Layers

Once authenticated, every request passes through scope validation. The system defines granular permissions in [[`scope.rs`](https://github.com/block/buzz/blob/main/scope.rs)](https://github.com/block/buzz/blob/main/crates/buzz-auth/src/scope.rs) and enforces them through the helper functions in [[`access.rs`](https://github.com/block/buzz/blob/main/access.rs)](https://github.com/block/buzz/blob/main/crates/buzz-auth/src/access.rs).

### The `Scope` Enum in [`scope.rs`](https://github.com/block/buzz/blob/main/scope.rs)

The `Scope` enum enumerates the permission families that a user may possess. As implemented in the source, these include **Admin**, **User**, **Read**, and **Write**. Scopes are attached to an `AuthConfig` and stored in the database as part of a user or API-token record, then populated into the `AuthContext` during the authentication phase.

### Enforcing Permissions with `require_scope` in [`access.rs`](https://github.com/block/buzz/blob/main/access.rs)

Protected endpoints invoke `require_scope` to validate permissions against the operation's requirements. This function receives the list of scopes a request carries and the required scope; it returns `AuthError::Forbidden` when the caller lacks necessary permissions.

```rust
use buzz_auth::{require_scope, Scope, AuthError};

fn handle_delete_message(ctx: &AuthContext) -> Result<(), AuthError> {
    // Only users with the `Write` scope may delete messages
    require_scope(&ctx.scopes, Scope::Write)?;
    // …perform delete…
    Ok(())
}

```

## Rate Limiting as an Access Control Guard

Beyond scope checking, Buzz employs **rate limiting** as a secondary access control layer to prevent abuse. This safeguard operates independently of authentication status and enforces usage quotas before business logic executes.

### Per-User and Per-IP Limits in [`rate_limit.rs`](https://github.com/block/buzz/blob/main/rate_limit.rs)

The [[`rate_limit.rs`](https://github.com/block/buzz/blob/main/rate_limit.rs)](https://github.com/block/buzz/blob/main/crates/buzz-auth/src/rate_limit.rs) module implements request throttling using keys derived from the `TenantContext`. The limiter uses a per-user or per-IP key to enforce configurable request caps, preventing abuse even for otherwise authorized users.

```rust
use buzz_auth::{rate_limit_key, RateLimitResult};

let key = rate_limit_key(&tenant_ctx, &pubkey, &LimitType::Message);
match RateLimiter::check(&key) {
    RateLimitResult::Allowed => { /* proceed */ }
    RateLimitResult::Denied => { return Err(AuthError::RateLimited); }
}

```

## Summary

- **NIP-42 Authentication**: Buzz verifies identity through cryptographic challenge-response signatures in [`nip42.rs`](https://github.com/block/buzz/blob/main/nip42.rs), eliminating the need for API tokens.
- **Scope Hierarchies**: The `Scope` enum and `require_scope` function in [`access.rs`](https://github.com/block/buzz/blob/main/access.rs) provide fine-grained, role-based access control.
- **Rate Limiting**: The [`rate_limit.rs`](https://github.com/block/buzz/blob/main/rate_limit.rs) module adds abuse prevention through per-user and per-IP request throttling.
- **Centralized Auth Logic**: All components consolidate in the `buzz-auth` crate, with [`lib.rs`](https://github.com/block/buzz/blob/main/lib.rs) exposing `AuthService` and `AuthContext` for integration across the relay.

## Frequently Asked Questions

### How does Buzz authenticate users without API tokens?

Buzz uses NIP-42, a Nostr protocol extension where clients sign server-generated challenges with their private keys. The `AuthService` in [`lib.rs`](https://github.com/block/buzz/blob/main/lib.rs) verifies these signatures cryptographically, creating an `AuthContext` that carries the authenticated public key and associated scopes without storing session tokens.

### What scopes are available in Buzz's access control system?

The `Scope` enum in [`scope.rs`](https://github.com/block/buzz/blob/main/scope.rs) defines permissions such as **Admin**, **User**, **Read**, and **Write**. Each scope represents a capability level, and the `require_scope` function validates that a user's context contains the necessary permission before executing protected operations.

### How does Buzz prevent abuse from authenticated users?

Even valid authentication does not guarantee unlimited access. The [`rate_limit.rs`](https://github.com/block/buzz/blob/main/rate_limit.rs) module enforces request quotas based on public key or IP address, returning `AuthError::RateLimited` when users exceed configured thresholds, effectively acting as a secondary access control mechanism.

### Where is the authorization logic centralized in the codebase?

All access control functionality resides in the `buzz-auth` crate. Key files include [`lib.rs`](https://github.com/block/buzz/blob/main/lib.rs) for the main `AuthService`, [`scope.rs`](https://github.com/block/buzz/blob/main/scope.rs) for permission definitions, [`access.rs`](https://github.com/block/buzz/blob/main/access.rs) for enforcement logic, [`nip42.rs`](https://github.com/block/buzz/blob/main/nip42.rs) for authentication, and [`rate_limit.rs`](https://github.com/block/buzz/blob/main/rate_limit.rs) for throttling guards.