# Authentication and Authorization Model for Multi-User Deployments in ai-memory

> Explore the ai-memory authentication and authorization model for multi-user deployments. Learn about its four-tier system and attribution-only approach for secure data management.

- Repository: [Fabio Akita/ai-memory](https://github.com/akitaonrails/ai-memory)
- Tags: architecture
- Published: 2026-08-19

---

**ai-memory implements a four-tier authentication ladder that distinguishes between anonymous users, root administrators, trusted proxy assertions, and database-backed users, using an attribution-only model where all wiki data remains globally readable but every write is stamped with the acting identity.**

The ai-memory repository provides a lightweight memory server for AI agents that scales from single-user deployments to multi-tenant environments. Understanding the authentication and authorization model for multi-user deployments is essential for securely configuring production instances while maintaining the system's simple, performant semantics.

## The Four-Tier Authentication Ladder

The authentication system evaluates incoming requests against a strict hierarchy, using the first matching tier without escalation. This prevents privilege confusion between different credential types.

- **Tier 0 — Anonymous:** When no `[auth].bearer_token` is configured, requests proceed without identity attribution. This maintains backward compatibility for pre-multi-user deployments but provides no accountability.

- **Tier 1 — Root:** When the bearer token matches `[auth].bearer_token`, the request receives full administrative privileges. If `[auth].root_username` is configured, write operations are attributed to that name; otherwise, attribution remains anonymous according to the source logic.

- **Tier 1b — Proxy-Asserted User:** When the bearer token matches `[auth].actor_proxy_bearer_token`, the system extracts identity from trusted `X-Memory-Actor-*` headers. The proxy forwards OIDC claims via `X-Memory-Actor-Issuer` and `X-Memory-Actor-Sub`, or a simple username via `X-Memory-Actor-User`. The proxy token must differ from the root token, and startup aborts if they collide.

- **Tier 2 — Database User:** When the bearer token does not match root or proxy credentials but matches a `users.token_hash` entry (SHA-256 of token + pepper), the request authenticates as that specific user with normal read/write rights.

- **Tier 3 — 401 Rejection:** If a bearer token is present but matches no tier, the request is rejected immediately.

## Secure Token Storage and Verification

In [`crates/ai-memory-store/src/users.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/users.rs), tokens are generated as 256-bit CSPRNG values encoded in URL-safe base64 (43 characters). The system never stores raw tokens; instead, it persists only the SHA-256 digest of `token || ":" || pepper`, where the pepper is a per-server secret read from `[auth].token_pepper` ([users.rs line 7-9](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/users.rs)).

To prevent timing attacks during verification, the implementation uses `subtle::ConstantTimeEq` for hash comparison ([users.rs line 98-100](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/users.rs)). This constant-time comparison ensures that attackers cannot deduce valid tokens through side-channel analysis.

## Trusted Proxy Authentication and SSO Integration

For organizations running ai-memory behind a reverse proxy that terminates SSO, tier 1b enables seamless integration. The proxy strips any client-supplied `X-Memory-Actor-*` headers and injects its own based on the authenticated session ([users.md line 71-77](https://github.com/akitaonrails/ai-memory/blob/main/docs/users.md)).

Configure your reverse proxy to forward the proxy token and actor headers:

```nginx
proxy_set_header Authorization "Bearer <proxy-token>";
proxy_set_header X-Memory-Actor-User "$remote_user";

# If using OIDC, also forward issuer and subject:

proxy_set_header X-Memory-Actor-Issuer "$oidc_issuer";
proxy_set_header X-Memory-Actor-Sub "$oidc_sub";

```

The `X-Memory-Actor-User` header asserts a plain username, while the OIDC pair (`Issuer`/`Sub`) creates a qualified identity in `issuer:subject` format. All write operations stamp this identity on rows such as handoffs, sessions, and pages, preventing cross-user pollution ([users.md line 31-38](https://github.com/akitaonrails/ai-memory/blob/main/docs/users.md)).

## Request Authorization and Capability Checks

The middleware in [`crates/ai-memory-mcp/src/middleware/auth.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-mcp/src/middleware/auth.rs) injects `Extension<AuthLevel>` and `Extension<ActorContext>` into every request. Handlers invoke `AuthLevel::authorize(Capability::…)` to verify privileges for specific actions ([users.md line 11-18](https://github.com/akitaonrails/ai-memory/blob/main/docs/users.md)).

All `/admin/*` endpoints require Tier 1 (Root) authentication regardless of other settings. Database users (Tier 2) receive HTTP 403 when attempting admin routes, while anonymous requests in multi-user mode receive HTTP 401.

Checking admin rights in a handler:

```rust
fn admin_endpoint(auth: Extension<AuthLevel>) -> Result<..., Err> {
    auth.authorize(Capability::Admin)?;
    // …admin logic…
}

```

## User Lifecycle and Token Management

User administration occurs through the `ai-memory user` CLI implemented in [`crates/ai-memory-cli/src/commands/user.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-cli/src/commands/user.rs). Administrators create users, rotate tokens, and manage expiration without database access.

Creating a root token and adding a user:

```bash

# Set root token (replace <root-token> with your generated token)

AI_MEMORY_AUTH_TOKEN=<root-token> ai-memory user add \
  --username alice --email alice@home --name "Alice Smith"

# → prints a one-time token for Alice

```

Expiration nullifies the `token_hash` but preserves the row for historical attribution. Revived users receive new tokens, and the `rotate-token` command forces immediate credential rotation without deleting audit history.

## Summary

- **Four-tier ladder:** Anonymous, Root, Proxy-asserted, and Database User tiers provide flexible deployment options from personal use to enterprise SSO.
- **Attribution-only security:** All wiki data remains globally readable; security focuses on verifying who performed writes rather than hiding data.
- **Cryptographic storage:** SHA-256 hashing with server-specific peppers and constant-time comparison prevents token theft via database breaches or timing attacks.
- **SSO integration:** Trusted proxy mode allows external identity providers to assert users via HTTP headers without modifying ai-memory's core.
- **Strict admin boundaries:** Root credentials exclusively protect administrative endpoints, ensuring database users cannot escalate privileges.

## Frequently Asked Questions

### How does ai-memory store authentication tokens securely?

ai-memory stores only SHA-256 hashes of tokens combined with a server-specific pepper, never the plaintext tokens themselves. The implementation in [`crates/ai-memory-store/src/users.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/users.rs) uses 256-bit CSPRNG generation and `subtle::ConstantTimeEq` for comparison to resist timing attacks.

### Can I integrate ai-memory with my corporate SSO provider?

Yes, using the trusted proxy authentication tier. Configure your reverse proxy (such as Nginx with OIDC) to validate SSO sessions and forward identity via `X-Memory-Actor-*` headers while providing the `[auth].actor_proxy_bearer_token` in the Authorization header. This allows ai-memory to accept assertions from external identity providers without native protocol support.

### What is the difference between root and database user authentication?

Root authentication uses the single master token configured in `[auth].bearer_token` and grants full administrative access including `/admin/*` endpoints. Database user authentication uses individual tokens stored in the `users` table (hashed with a pepper) and grants standard read/write access without administrative capabilities. Root tokens preempt database tokens if both match, preventing accidental privilege reduction.

### How does the system prevent one user's data from affecting another?

While all wiki data remains readable by any authenticated party, every write operation stamps the qualified identity (`issuer:subject` or `user:<name>`) onto the record. This attribution prevents cross-user interference in operations like handoffs and session management, ensuring one operator's pending handoff is not delivered to another user even though the underlying data is technically visible to both.