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.
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"})
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" });
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.
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"},
)
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" },
);
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).
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)
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);
Attaching Auth to Memproof
Pass the auth hook when constructing your Memproof instance. The hook is called before every operation enters the pipeline.
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,
)
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,
});
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.
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,
)
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,
});
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.
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.