> ## Documentation Index
> Fetch the complete documentation index at: https://memproof.kyberon.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Auth Middleware

> Pluggable authentication and authorization for memory operations

Memproof supports pluggable auth hooks that run before the pipeline executes. Each hook receives the operation context and returns `true` (allow) or `false` (deny). If any hook denies the request, the operation is rejected before risk assessment or policy evaluation begins.

## Built-in Auth Hooks

### BearerTokenAuth

Validates the `actor_id` in the operation context against a set of known tokens. Useful for service-to-service authentication where each caller has a static bearer token.

<Tabs>
  <Tab title="Python">
    ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    from memproof.auth import BearerTokenAuth

    auth = BearerTokenAuth(valid_tokens={"tok-abc", "tok-xyz"})

    # Returns True if actor_id matches a valid token
    allowed = auth.check(context={"actor_id": "tok-abc"})
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    import { BearerTokenAuth } from "@kyberon/memproof";

    const auth = new BearerTokenAuth(["tok-abc", "tok-xyz"]);

    // Returns true if actor_id matches a valid token
    const allowed = auth.check({ actorId: "tok-abc" });
    ```
  </Tab>
</Tabs>

### ScopeAuth

Grants access based on tenant, project, and agent scope. You register which actor IDs are allowed to operate within specific scopes, and the hook enforces those boundaries at request time.

<Tabs>
  <Tab title="Python">
    ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    from memproof.auth import ScopeAuth

    scope_auth = ScopeAuth()
    scope_auth.grant("agent-1", "tenant-1", "project-1")
    scope_auth.grant("agent-2", "tenant-1", "project-2")

    # Returns True -- agent-1 is granted access to tenant-1/project-1
    scope_auth.check(
        context={"actor_id": "agent-1"},
        scope={"tenant_id": "tenant-1", "project_id": "project-1"},
    )

    # Returns False -- agent-1 is not granted access to project-2
    scope_auth.check(
        context={"actor_id": "agent-1"},
        scope={"tenant_id": "tenant-1", "project_id": "project-2"},
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    import { ScopeAuth } from "@kyberon/memproof";

    const scopeAuth = new ScopeAuth();
    scopeAuth.grant("agent-1", "tenant-1", "project-1");
    scopeAuth.grant("agent-2", "tenant-1", "project-2");

    // Returns true
    scopeAuth.check(
      { actorId: "agent-1" },
      { tenantId: "tenant-1", projectId: "project-1" },
    );

    // Returns false
    scopeAuth.check(
      { actorId: "agent-1" },
      { tenantId: "tenant-1", projectId: "project-2" },
    );
    ```
  </Tab>
</Tabs>

### CompositeAuth

Chains multiple auth hooks together using AND logic. Every hook must return `true` for the operation to proceed. This lets you layer authentication (token validation) with authorization (scope checks).

<Tabs>
  <Tab title="Python">
    ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    from memproof.auth import BearerTokenAuth, ScopeAuth, CompositeAuth

    # Layer 1: token validation
    auth = BearerTokenAuth(valid_tokens={"tok-abc", "tok-xyz"})

    # Layer 2: scope authorization
    scope_auth = ScopeAuth()
    scope_auth.grant("agent-1", "tenant-1", "project-1")

    # Combined: both must pass
    composite = CompositeAuth(auth, scope_auth)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    import { BearerTokenAuth, ScopeAuth, CompositeAuth } from "@kyberon/memproof";

    // Layer 1: token validation
    const auth = new BearerTokenAuth(["tok-abc", "tok-xyz"]);

    // Layer 2: scope authorization
    const scopeAuth = new ScopeAuth();
    scopeAuth.grant("agent-1", "tenant-1", "project-1");

    // Combined: both must pass
    const composite = new CompositeAuth(auth.check, scopeAuth.check);
    ```
  </Tab>
</Tabs>

## Attaching Auth to Memproof

Pass the auth hook when constructing your Memproof instance. The hook is called before every operation enters the pipeline.

<Tabs>
  <Tab title="Python">
    ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    from memproof import Memproof
    from memproof.auth import BearerTokenAuth, ScopeAuth, CompositeAuth

    auth = BearerTokenAuth(valid_tokens={"tok-abc", "tok-xyz"})
    scope_auth = ScopeAuth()
    scope_auth.grant("agent-1", "tenant-1", "project-1")
    composite = CompositeAuth(auth, scope_auth)

    mp = Memproof(
        policy="memproof.yaml",
        adapter="in_memory",
        auth_hook=composite.check,
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    import { Memproof, CompositeAuth, BearerTokenAuth, ScopeAuth } from "@kyberon/memproof";

    const auth = new BearerTokenAuth(["tok-abc", "tok-xyz"]);
    const scopeAuth = new ScopeAuth();
    scopeAuth.grant("agent-1", "tenant-1", "project-1");
    const composite = new CompositeAuth(auth.check, scopeAuth.check);

    const mp = new Memproof({
        policy: "./memproof.yaml",
        config: { adapter: "in_memory" },
        authHook: composite.check,
    });
    ```
  </Tab>
</Tabs>

## Writing a Custom Auth Hook

Any function that accepts the operation context and scope and returns a boolean can serve as an auth hook. This makes it straightforward to integrate with external identity providers, JWTs, or custom RBAC systems.

<Tabs>
  <Tab title="Python">
    ```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    from memproof import Memproof

    async def my_custom_auth(context: dict, scope: dict) -> bool:
        """Validate actor against an external identity service."""
        actor = context.get("actor_id")
        if not actor:
            return False
        # Call your identity provider, check JWTs, query a database, etc.
        return await my_identity_service.is_authorized(actor, scope)

    mp = Memproof(
        policy="memproof.yaml",
        adapter="in_memory",
        auth_hook=my_custom_auth,
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
    import { Memproof } from "@kyberon/memproof";

    async function myCustomAuth(
      context: Record<string, string>,
      scope: Record<string, string>,
    ): Promise<boolean> {
      const actor = context.actorId;
      if (!actor) return false;
      // Call your identity provider, check JWTs, query a database, etc.
      return await myIdentityService.isAuthorized(actor, scope);
    }

    const mp = new Memproof({
        policy: "./memproof.yaml",
        config: { adapter: "in_memory" },
        authHook: myCustomAuth,
    });
    ```
  </Tab>
</Tabs>

<Warning>
  Auth hooks run on every operation. Keep them fast and avoid expensive I/O in the hot path. If you need to call an external service, consider caching the result with a short TTL.
</Warning>

<Tip>
  Use `CompositeAuth` to separate concerns: one hook for authentication (is this caller who they say they are?) and another for authorization (is this caller allowed to do this?). This makes each hook simpler to test and reason about.
</Tip>
