Understanding the ai-memory Four-Rung Auth Ladder: From Root to DB-User Tokens

The ai-memory four-rung auth ladder is a hierarchical authentication system that resolves every HTTP request to one of four tiers—Anonymous, Root, Proxy-Asserted User, or DB User—where the first matching credential wins and unknown tokens result in immediate 401 rejection.

The ai-memory project by akitaonrails implements a strict, ordered authentication hierarchy to handle everything from unauthenticated reads to administrative operations. This four-rung auth ladder evaluates credentials sequentially, ensuring that requests receive exactly the privileges they claim without implicit escalation.

What Is the ai-memory Four-Rung Auth Ladder?

The authentication system in ai-memory operates as a sticky ladder defined in docs/users.md【/cache/repos/github.com/akitaonrails/ai-memory/main/docs/users.md#L55-L64】. When a request arrives, the server checks credentials in a specific order, stopping at the first applicable rung. This design prevents privilege escalation attacks where a request might attempt to climb from anonymous to root access.

The ladder supports both single-user deployments (using root tokens) and multi-user environments (using database-stored user tokens), with an optional proxy tier for SSO integration.

The Four Authentication Rungs Explained

Rung 0: Anonymous Access

Trigger: No Authorization header or [auth].bearer_token is supplied.

Requests without authentication proceed as anonymous and carry no identity. This preserves backward compatibility with pre-multi-user behavior, allowing unauthenticated reads while restricting writes based on server configuration.

Rung 1: Root Authentication

Trigger: The bearer token matches [auth].bearer_token from the configuration.

Root requests receive full administrative privileges. If [auth].root_username is configured, audit logs attribute writes to that name; otherwise, the request remains technically anonymous in logs but retains root capabilities. All /admin/* endpoints require this authentication level when multi-user mode is active.

Rung 1b: Proxy-Asserted User

Trigger: The bearer token matches the distinct [auth].actor_proxy_bearer_token and trusted X-Memory-Actor-* headers are present.

This intermediate tier allows a trusted reverse proxy to assert user identity via headers like X-Memory-Actor-User. According to the source documentation, the server treats these requests as standard user requests unless the OIDC issuer/subject pair exactly matches the configured root pair【/cache/repos/github.com/akitaonrails/ai-memory/main/docs/users.md#L78-L88】. Missing or malformed identity headers result in immediate rejection rather than fallback to anonymous access.

Rung 2: DB User Authentication

Trigger: The bearer token does not match root or proxy tokens but validates against the users.token_hash table.

DB-user tokens occupy the standard multi-user tier. The server computes SHA-256(token + ":" + [auth].token_pepper) and compares it against stored hashes in crates/ai-memory-store/src/users.rs. Matching tokens grant normal read/write API access while restricting administrative endpoints. The audit log records the specific username, email, and name associated with the token.

Rung 3: 401 Unauthorized

Trigger: A bearer token is present but matches none of the above tiers.

Unknown credentials result in immediate rejection (401 Unauthorized). This rung closes the security bypass—unlike systems that fall back to anonymous access when authentication fails, ai-memory treats unrecognized tokens as errors.

How Authentication Is Resolved

The resolution logic implemented in crates/ai-memory-core/src/auth.rs evaluates the AuthLevel::resolve method sequentially. The system is strictly sticky: once a request matches a rung, evaluation stops and never climbs to a higher tier【/cache/repos/github.com/akitaonrails/ai-memory/main/docs/users.md#L65-L68】.

Critical safety checks include:

  • Token distinctness: The server refuses startup if [auth].bearer_token equals [auth].actor_proxy_bearer_token【/cache/repos/github.com/akitaonrails/ai-memory/main/docs/users.md#L91-L93】.
  • Proxy isolation: The proxy token should only be used when ai-memory sits behind a trusted reverse proxy that sanitizes external X-Memory-Actor-* headers.

Configuration and Implementation Details

Configuration Schema

Define the ladder parameters in your config.toml:

[auth]
bearer_token = "<root-token>"               # Rung 1: Root admin token

actor_proxy_bearer_token = "<proxy-token>"  # Rung 1b: Optional SSO proxy token

token_pepper = "<generated-pepper>"         # Rung 2: Required for DB-user hashing

root_username = "admin"                     # Optional attribution for root actions

Request Examples by Rung


# Rung 0: Anonymous request (no token)

curl http://localhost:49374/api/v1/pages/foo.md

# Rung 1: Root request (full admin access)

curl -H "Authorization: Bearer <root-token>" \
     http://localhost:49374/admin/users

# Rung 1b: Proxy-asserted user (SSO via trusted proxy)

curl -H "Authorization: Bearer <proxy-token>" \
     -H "X-Memory-Actor-User: alice" \
     -H "X-Memory-Actor-Email: alice@example.com" \
     http://localhost:49374/api/v1/pages/foo.md

# Rung 2: DB-user request (standard multi-user token)

curl -H "Authorization: Bearer <alice-db-token>" \
     http://localhost:49374/api/v1/pages/foo.md

Source File References

Component File Path Purpose
Auth Resolution crates/ai-memory-core/src/auth.rs Implements AuthLevel::resolve logic and ActorContext injection
Token Storage crates/ai-memory-store/src/users.rs Stores SHA-256 hashed tokens for Rung 2 verification
Proxy Middleware crates/ai-memory-mcp/src/middleware/auth.rs Processes X-Memory-Actor-* headers for Rung 1b
Admin Guards crates/ai-memory-mcp/src/routes/admin.rs Enforces Root-only access to /admin/* endpoints

Security Considerations

When deploying the ai-memory four-rung auth ladder in production, consider these constraints:

  • Proxy token exposure: Never expose [auth].actor_proxy_bearer_token directly to client applications. This credential grants the ability to impersonate any user via headers and should remain restricted to your internal reverse proxy infrastructure.
  • Pepper generation: The [auth].token_pepper value must be cryptographically random and consistent across server restarts. Changing the pepper invalidates all existing DB-user tokens (Rung 2).
  • Admin isolation: Normal DB users (Rung 2) cannot access administrative endpoints. Route guards in crates/ai-memory-mcp/src/routes/admin.rs explicitly check for AuthLevel::Root regardless of other permissions.

Summary

  • The ai-memory four-rung auth ladder evaluates requests in strict order: Anonymous → Root → Proxy-Asserted User → DB User → 401 Rejection.
  • First-match wins: Once a request authenticates at any rung, it never escalates to higher privileges.
  • Root and proxy tokens must be distinct values; the server fails fast on configuration conflicts.
  • DB-user tokens use SHA-256 hashing with a configurable pepper to prevent rainbow table attacks against the users table.
  • The proxy tier (Rung 1b) enables SSO integration but requires a trusted network boundary to prevent header spoofing.

Frequently Asked Questions

What happens if I provide a wrong bearer token in ai-memory?

The request immediately receives a 401 Unauthorized response. Unlike some systems that fall back to anonymous access, ai-memory treats unrecognized tokens as authentication failures and rejects the request at Rung 3 of the auth ladder.

Can I use the same token for root and proxy authentication?

No. The server performs a startup validation that ensures [auth].bearer_token and [auth].actor_proxy_bearer_token are distinct values. If these collide, ai-memory refuses to start【/cache/repos/github.com/akitaonrails/ai-memory/main/docs/users.md#L91-L93】.

How are DB-user tokens stored securely?

DB-user tokens are stored as SHA-256 hashes computed from the concatenation of the raw token, a colon separator, and the [auth].token_pepper value. The raw token is never persisted; only this peppered hash exists in the database, making offline brute-force attacks computationally expensive even if the users table is compromised.

Why does the proxy tier exist in the auth ladder?

The proxy tier (Rung 1b) enables SSO integration and service mesh authentication. When ai-memory runs behind a trusted reverse proxy (like Envoy or NGINX with OAuth2/OIDC), the proxy handles the complex authentication flow and asserts the user identity via X-Memory-Actor-* headers. This separates authentication concerns from the core application while maintaining the security guarantees of the four-rung ladder.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →