agentauthlayer 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. agentauthlayer-0.1.0/PKG-INFO +131 -0
  2. agentauthlayer-0.1.0/README.md +110 -0
  3. agentauthlayer-0.1.0/agent_auth/__init__.py +48 -0
  4. agentauthlayer-0.1.0/agent_auth/__main__.py +4 -0
  5. agentauthlayer-0.1.0/agent_auth/agents.py +40 -0
  6. agentauthlayer-0.1.0/agent_auth/audit.py +51 -0
  7. agentauthlayer-0.1.0/agent_auth/auth.py +36 -0
  8. agentauthlayer-0.1.0/agent_auth/cli.py +28 -0
  9. agentauthlayer-0.1.0/agent_auth/client.py +107 -0
  10. agentauthlayer-0.1.0/agent_auth/context.py +21 -0
  11. agentauthlayer-0.1.0/agent_auth/core.py +638 -0
  12. agentauthlayer-0.1.0/agent_auth/delegation.py +15 -0
  13. agentauthlayer-0.1.0/agent_auth/exceptions.py +72 -0
  14. agentauthlayer-0.1.0/agent_auth/models.py +72 -0
  15. agentauthlayer-0.1.0/agent_auth/policy.py +296 -0
  16. agentauthlayer-0.1.0/agent_auth/policy_service.py +176 -0
  17. agentauthlayer-0.1.0/agent_auth/principals.py +44 -0
  18. agentauthlayer-0.1.0/agent_auth/registry.py +90 -0
  19. agentauthlayer-0.1.0/agent_auth/session.py +135 -0
  20. agentauthlayer-0.1.0/agent_auth/storage.py +536 -0
  21. agentauthlayer-0.1.0/agent_auth/tokens.py +92 -0
  22. agentauthlayer-0.1.0/agent_auth/users.py +173 -0
  23. agentauthlayer-0.1.0/agentauthlayer.egg-info/PKG-INFO +131 -0
  24. agentauthlayer-0.1.0/agentauthlayer.egg-info/SOURCES.txt +36 -0
  25. agentauthlayer-0.1.0/agentauthlayer.egg-info/dependency_links.txt +1 -0
  26. agentauthlayer-0.1.0/agentauthlayer.egg-info/requires.txt +2 -0
  27. agentauthlayer-0.1.0/agentauthlayer.egg-info/top_level.txt +1 -0
  28. agentauthlayer-0.1.0/pyproject.toml +39 -0
  29. agentauthlayer-0.1.0/setup.cfg +4 -0
  30. agentauthlayer-0.1.0/tests/test_agent_auth_library.py +267 -0
  31. agentauthlayer-0.1.0/tests/test_auth_flow.py +123 -0
  32. agentauthlayer-0.1.0/tests/test_core_first_boundary.py +111 -0
  33. agentauthlayer-0.1.0/tests/test_health.py +16 -0
  34. agentauthlayer-0.1.0/tests/test_iam_policy.py +34 -0
  35. agentauthlayer-0.1.0/tests/test_project_flow.py +38 -0
  36. agentauthlayer-0.1.0/tests/test_sqlite_repos.py +167 -0
  37. agentauthlayer-0.1.0/tests/test_storage.py +237 -0
  38. agentauthlayer-0.1.0/tests/test_tool_registry.py +197 -0
@@ -0,0 +1,131 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentauthlayer
3
+ Version: 0.1.0
4
+ Summary: Library-first authentication and authorization SDK for AI agents
5
+ Author: Vaibhav Ahluwalia
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/VaibhavAhluwalia/Agent-Auth-
8
+ Project-URL: Repository, https://github.com/VaibhavAhluwalia/Agent-Auth-
9
+ Keywords: agents,auth,authorization,iam,security,sdk
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Topic :: Security
16
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
+ Requires-Python: >=3.10
18
+ Description-Content-Type: text/markdown
19
+ Requires-Dist: requests>=2.31.0
20
+ Requires-Dist: python-jose>=3.3.0
21
+
22
+ # Agent Auth SDK
23
+
24
+ A library-first authentication and authorization SDK for AI agents.
25
+
26
+ ## What this package is
27
+
28
+ `agent-auth-sdk` is the reusable Python SDK layer of the Agent Auth platform. It is designed for developers who want to:
29
+ - register agents
30
+ - issue and verify access with the Agent Auth control plane
31
+ - sync tool definitions
32
+ - evaluate permissions
33
+ - embed policy enforcement into agent runtimes
34
+
35
+ This package is the **developer-facing library**, not the full FastAPI server or React admin UI.
36
+
37
+ ## Install
38
+
39
+ ```bash
40
+ pip install agent-auth-sdk
41
+ ```
42
+
43
+ For local development:
44
+
45
+ ```bash
46
+ pip install -e .
47
+ ```
48
+
49
+ ## Quickstart
50
+
51
+ ```python
52
+ from agent_auth import AuthAPIClient
53
+
54
+ client = AuthAPIClient(
55
+ base_url="http://127.0.0.1:8002",
56
+ token="YOUR_ADMIN_OR_SERVICE_TOKEN",
57
+ )
58
+
59
+ agent = client.create_agent(
60
+ agent_id="research-bot-01",
61
+ name="Research Bot 01",
62
+ owner="vaibhav@company.com",
63
+ role="research_agent",
64
+ scopes=[],
65
+ project_id="ai-platform",
66
+ )
67
+
68
+ print(agent)
69
+ ```
70
+
71
+ ## Environment variables
72
+
73
+ If you prefer, the SDK reads these automatically:
74
+
75
+ ```bash
76
+ export AGENT_AUTH_URL=http://127.0.0.1:8002
77
+ export AGENT_AUTH_TOKEN=YOUR_ADMIN_OR_SERVICE_TOKEN
78
+ ```
79
+
80
+ Then:
81
+
82
+ ```python
83
+ from agent_auth import AuthAPIClient
84
+
85
+ client = AuthAPIClient()
86
+ print(client.health())
87
+ ```
88
+
89
+ ## Common capabilities
90
+
91
+ ### Sync tools from code
92
+
93
+ ```python
94
+ client.sync_tools([
95
+ {"action": "tool.search_web", "description": "Search the web"},
96
+ {"action": "docs.read", "description": "Read protected docs"},
97
+ ])
98
+ ```
99
+
100
+ ### Evaluate access
101
+
102
+ ```python
103
+ decision = client.evaluate(
104
+ principal_id="research-bot-01",
105
+ action="tool.search_web",
106
+ resource="web/*",
107
+ role="research_agent",
108
+ )
109
+
110
+ print(decision)
111
+ ```
112
+
113
+ ## Package scope
114
+
115
+ This package currently exposes the reusable SDK and policy primitives under `agent_auth/`.
116
+ The full control plane server, admin UI, and demos remain in the same repository but are not part of the SDK package build.
117
+
118
+ ## Dev-ready validation checklist
119
+
120
+ Before publishing, verify:
121
+
122
+ ```bash
123
+ pip install -e .
124
+ python -c "import agent_auth; print(agent_auth.__all__)"
125
+ python -m build
126
+ pip install dist/*.whl
127
+ ```
128
+
129
+ ## Repository
130
+
131
+ - Source: <https://github.com/VaibhavAhluwalia/Agent-Auth->
@@ -0,0 +1,110 @@
1
+ # Agent Auth SDK
2
+
3
+ A library-first authentication and authorization SDK for AI agents.
4
+
5
+ ## What this package is
6
+
7
+ `agent-auth-sdk` is the reusable Python SDK layer of the Agent Auth platform. It is designed for developers who want to:
8
+ - register agents
9
+ - issue and verify access with the Agent Auth control plane
10
+ - sync tool definitions
11
+ - evaluate permissions
12
+ - embed policy enforcement into agent runtimes
13
+
14
+ This package is the **developer-facing library**, not the full FastAPI server or React admin UI.
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ pip install agent-auth-sdk
20
+ ```
21
+
22
+ For local development:
23
+
24
+ ```bash
25
+ pip install -e .
26
+ ```
27
+
28
+ ## Quickstart
29
+
30
+ ```python
31
+ from agent_auth import AuthAPIClient
32
+
33
+ client = AuthAPIClient(
34
+ base_url="http://127.0.0.1:8002",
35
+ token="YOUR_ADMIN_OR_SERVICE_TOKEN",
36
+ )
37
+
38
+ agent = client.create_agent(
39
+ agent_id="research-bot-01",
40
+ name="Research Bot 01",
41
+ owner="vaibhav@company.com",
42
+ role="research_agent",
43
+ scopes=[],
44
+ project_id="ai-platform",
45
+ )
46
+
47
+ print(agent)
48
+ ```
49
+
50
+ ## Environment variables
51
+
52
+ If you prefer, the SDK reads these automatically:
53
+
54
+ ```bash
55
+ export AGENT_AUTH_URL=http://127.0.0.1:8002
56
+ export AGENT_AUTH_TOKEN=YOUR_ADMIN_OR_SERVICE_TOKEN
57
+ ```
58
+
59
+ Then:
60
+
61
+ ```python
62
+ from agent_auth import AuthAPIClient
63
+
64
+ client = AuthAPIClient()
65
+ print(client.health())
66
+ ```
67
+
68
+ ## Common capabilities
69
+
70
+ ### Sync tools from code
71
+
72
+ ```python
73
+ client.sync_tools([
74
+ {"action": "tool.search_web", "description": "Search the web"},
75
+ {"action": "docs.read", "description": "Read protected docs"},
76
+ ])
77
+ ```
78
+
79
+ ### Evaluate access
80
+
81
+ ```python
82
+ decision = client.evaluate(
83
+ principal_id="research-bot-01",
84
+ action="tool.search_web",
85
+ resource="web/*",
86
+ role="research_agent",
87
+ )
88
+
89
+ print(decision)
90
+ ```
91
+
92
+ ## Package scope
93
+
94
+ This package currently exposes the reusable SDK and policy primitives under `agent_auth/`.
95
+ The full control plane server, admin UI, and demos remain in the same repository but are not part of the SDK package build.
96
+
97
+ ## Dev-ready validation checklist
98
+
99
+ Before publishing, verify:
100
+
101
+ ```bash
102
+ pip install -e .
103
+ python -c "import agent_auth; print(agent_auth.__all__)"
104
+ python -m build
105
+ pip install dist/*.whl
106
+ ```
107
+
108
+ ## Repository
109
+
110
+ - Source: <https://github.com/VaibhavAhluwalia/Agent-Auth->
@@ -0,0 +1,48 @@
1
+ """agent_auth — reusable authentication and authorization primitives for Agent Auth."""
2
+
3
+ from agent_auth.auth import principal_fields, principal_from_agent, principal_from_user
4
+ from agent_auth.client import AuthAPIClient
5
+ from agent_auth.context import AuthContext
6
+ from agent_auth.delegation import DelegationGrant
7
+ from agent_auth.exceptions import (
8
+ AgentAuthError,
9
+ AgentNotFoundError,
10
+ AuthServiceError,
11
+ InvalidTokenError,
12
+ PermissionDeniedError,
13
+ RevokedTokenError,
14
+ )
15
+ from agent_auth.models import Agent, TokenClaims, TokenRecord, User, UserClaims
16
+ from agent_auth.policy import PolicyDecision, PolicyEvaluator, PolicyRequest, PolicyStatement, RoleDefinition, require_permission
17
+ from agent_auth.principals import AgentPrincipal, Principal, SystemPrincipal, UserPrincipal, user_scopes_for_role
18
+
19
+ __all__ = [
20
+ "Agent",
21
+ "AgentAuthError",
22
+ "AgentNotFoundError",
23
+ "AgentPrincipal",
24
+ "AuthAPIClient",
25
+ "AuthContext",
26
+ "AuthServiceError",
27
+ "DelegationGrant",
28
+ "InvalidTokenError",
29
+ "PermissionDeniedError",
30
+ "PolicyDecision",
31
+ "PolicyEvaluator",
32
+ "PolicyRequest",
33
+ "PolicyStatement",
34
+ "Principal",
35
+ "RevokedTokenError",
36
+ "RoleDefinition",
37
+ "SystemPrincipal",
38
+ "TokenClaims",
39
+ "TokenRecord",
40
+ "User",
41
+ "UserClaims",
42
+ "UserPrincipal",
43
+ "principal_fields",
44
+ "principal_from_agent",
45
+ "principal_from_user",
46
+ "require_permission",
47
+ "user_scopes_for_role",
48
+ ]
@@ -0,0 +1,4 @@
1
+ from agent_auth.cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Protocol, TypeVar
4
+
5
+
6
+ AgentT = TypeVar("AgentT")
7
+
8
+
9
+ class AgentStore(Protocol[AgentT]):
10
+ def save(self, agent: AgentT) -> AgentT:
11
+ ...
12
+
13
+ def get(self, agent_id: str) -> AgentT | None:
14
+ ...
15
+
16
+ def list_all(self, project_id: str | None = None) -> list[AgentT]:
17
+ ...
18
+
19
+
20
+ class AgentIdentityService:
21
+ """Core agent lifecycle orchestration over a configured agent store."""
22
+
23
+ def __init__(self, store: AgentStore[AgentT]):
24
+ self.store = store
25
+
26
+ def save(self, agent: AgentT) -> AgentT:
27
+ return self.store.save(agent)
28
+
29
+ def get(self, agent_id: str) -> AgentT | None:
30
+ return self.store.get(agent_id)
31
+
32
+ def list_agents(self, project_id: str | None = None) -> list[AgentT]:
33
+ return self.store.list_all(project_id=project_id)
34
+
35
+ def update_scopes(self, agent_id: str, scopes: list[str]) -> AgentT | None:
36
+ agent = self.store.get(agent_id)
37
+ if not agent:
38
+ return None
39
+ agent.scopes = scopes
40
+ return self.store.save(agent)
@@ -0,0 +1,51 @@
1
+ """agent_auth audit logger — pluggable, default prints to stderr."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import logging
7
+ import sys
8
+ from datetime import datetime, timezone
9
+ from typing import Any, Protocol
10
+
11
+ logger = logging.getLogger("agent_auth.audit")
12
+
13
+
14
+ class AuditBackend(Protocol):
15
+ """Interface that any custom audit backend must implement."""
16
+
17
+ def log(self, event: dict[str, Any]) -> None: ...
18
+
19
+
20
+ class StderrAuditBackend:
21
+ """Default backend — writes JSON lines to stderr."""
22
+
23
+ def log(self, event: dict[str, Any]) -> None:
24
+ line = json.dumps(event, default=str)
25
+ print(line, file=sys.stderr)
26
+
27
+
28
+ class InMemoryAuditBackend:
29
+ """Keeps events in a list — useful for testing."""
30
+
31
+ def __init__(self) -> None:
32
+ self.events: list[dict[str, Any]] = []
33
+
34
+ def log(self, event: dict[str, Any]) -> None:
35
+ self.events.append(event)
36
+
37
+
38
+ class AuditLogger:
39
+ """Thin wrapper around a backend that stamps every event."""
40
+
41
+ def __init__(self, backend: AuditBackend | None = None) -> None:
42
+ self._backend: AuditBackend = backend or StderrAuditBackend()
43
+
44
+ def record(self, event_type: str, **details: Any) -> None:
45
+ event = {
46
+ "event": event_type,
47
+ "ts": datetime.now(timezone.utc).isoformat(),
48
+ **details,
49
+ }
50
+ self._backend.log(event)
51
+ logger.debug("audit: %s", event)
@@ -0,0 +1,36 @@
1
+ from __future__ import annotations
2
+
3
+ from agent_auth.principals import AgentPrincipal, Principal, UserPrincipal, user_scopes_for_role
4
+
5
+
6
+ def principal_from_agent(*, agent_id: str, role: str | None = None, scopes: list[str] | None = None, owner: str | None = None, status: str | None = None) -> AgentPrincipal:
7
+ return AgentPrincipal(
8
+ principal_id=agent_id,
9
+ principal_type='agent',
10
+ role=role,
11
+ scopes=list(scopes or []),
12
+ owner=owner,
13
+ status=status,
14
+ )
15
+
16
+
17
+ def principal_from_user(*, user_id: str, email: str, role: str, scopes: list[str] | None = None, status: str | None = None) -> UserPrincipal:
18
+ effective_scopes = list(scopes) if scopes is not None else user_scopes_for_role(role)
19
+ return UserPrincipal(
20
+ principal_id=user_id,
21
+ principal_type='user',
22
+ role=role,
23
+ scopes=effective_scopes,
24
+ email=email,
25
+ status=status,
26
+ )
27
+
28
+
29
+ def principal_fields(principal: Principal) -> tuple[str, str, list[str], str | None, str | None]:
30
+ return (
31
+ principal.principal_id,
32
+ principal.principal_type,
33
+ list(principal.scopes),
34
+ principal.role,
35
+ principal.email,
36
+ )
@@ -0,0 +1,28 @@
1
+ import argparse
2
+ import sys
3
+ import uvicorn
4
+
5
+ def main():
6
+ parser = argparse.ArgumentParser(
7
+ description="Agent Auth Platform CLI - Manage and run the control plane.",
8
+ prog="agent-auth"
9
+ )
10
+ subparsers = parser.add_subparsers(dest="command", help="Available commands")
11
+
12
+ # The "ui" command (like "mlflow ui")
13
+ ui_parser = subparsers.add_parser("ui", help="Launch the integrated Auth API and React Dashboard")
14
+ ui_parser.add_argument("--host", default="0.0.0.0", help="Host to bind to (default: 0.0.0.0)")
15
+ ui_parser.add_argument("--port", type=int, default=8002, help="Port to bind to (default: 8002)")
16
+ ui_parser.add_argument("--reload", action="store_true", help="Enable auto-reload for development")
17
+
18
+ args = parser.parse_args()
19
+
20
+ if args.command == "ui":
21
+ print(f"Starting Agent Auth UI & Control Plane on http://{args.host}:{args.port}")
22
+ uvicorn.run("auth_app.main:app", host=args.host, port=args.port, reload=args.reload)
23
+ else:
24
+ parser.print_help()
25
+ sys.exit(1)
26
+
27
+ if __name__ == "__main__":
28
+ main()
@@ -0,0 +1,107 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from typing import Any
5
+
6
+ import requests
7
+
8
+ from agent_auth.context import AuthContext
9
+ from agent_auth.exceptions import (
10
+ AgentNotFoundError,
11
+ AuthServiceError,
12
+ InvalidTokenError,
13
+ PermissionDeniedError,
14
+ RevokedTokenError,
15
+ )
16
+
17
+
18
+ class AuthAPIClient:
19
+ """Thin SDK client for talking to the Agent Auth control plane."""
20
+
21
+ def __init__(self, base_url: str | None = None, token: str | None = None, timeout: int = 30) -> None:
22
+ self.base_url = (base_url or os.getenv("AGENT_AUTH_URL") or "http://127.0.0.1:8002").rstrip("/")
23
+ self.token = token or os.getenv("AGENT_AUTH_TOKEN")
24
+ self.timeout = timeout
25
+
26
+ def _headers(self) -> dict[str, str]:
27
+ headers = {"Content-Type": "application/json"}
28
+ if self.token:
29
+ headers["Authorization"] = f"Bearer {self.token}"
30
+ return headers
31
+
32
+ def _request(self, method: str, path: str, json: dict[str, Any] | None = None) -> Any:
33
+ response = requests.request(
34
+ method,
35
+ f"{self.base_url}{path}",
36
+ json=json,
37
+ headers=self._headers(),
38
+ timeout=self.timeout,
39
+ )
40
+
41
+ if response.ok:
42
+ if not response.content:
43
+ return None
44
+ return response.json()
45
+
46
+ detail = None
47
+ try:
48
+ detail = response.json().get("detail")
49
+ except Exception:
50
+ detail = response.text or "Request failed"
51
+
52
+ if response.status_code == 401:
53
+ if detail and ("revoked" in detail.lower() or "inactive" in detail.lower()):
54
+ raise RevokedTokenError(detail)
55
+ raise InvalidTokenError(detail or "Invalid token")
56
+ if response.status_code == 403:
57
+ raise PermissionDeniedError(detail or "Permission denied")
58
+ if response.status_code == 404 and path.startswith("/agents/"):
59
+ raise AgentNotFoundError(detail or "Agent not found")
60
+ raise AuthServiceError(detail or f"Request failed with status {response.status_code}")
61
+
62
+ def health(self) -> dict[str, Any]:
63
+ return self._request("GET", "/health")
64
+
65
+ def create_agent(self, agent_id: str, name: str, owner: str, role: str, scopes: list[str], project_id: str | None = None) -> dict[str, Any]:
66
+ payload = {
67
+ "agent_id": agent_id,
68
+ "name": name,
69
+ "owner": owner,
70
+ "role": role,
71
+ "scopes": scopes,
72
+ }
73
+ if project_id:
74
+ payload["project_id"] = project_id
75
+ return self._request("POST", "/agents", json=payload)
76
+
77
+ def get_agent(self, agent_id: str) -> dict[str, Any]:
78
+ return self._request("GET", f"/agents/{agent_id}")
79
+
80
+ def issue_token(self, agent_id: str) -> dict[str, Any]:
81
+ return self._request("POST", "/auth/token", json={"agent_id": agent_id})
82
+
83
+ def sync_tools(self, permissions: list[dict[str, str]]) -> dict[str, Any]:
84
+ return self._request("POST", "/policy/permissions/sync", json={"permissions": permissions})
85
+
86
+ def evaluate(self, principal_id: str, action: str, resource: str | None = None, granted_scopes: list[str] | None = None, role: str | None = None, context: dict[str, str] | None = None) -> dict[str, Any]:
87
+ return self._request(
88
+ "POST",
89
+ "/policy/evaluate",
90
+ json={
91
+ "principal_id": principal_id,
92
+ "action": action,
93
+ "resource": resource,
94
+ "granted_scopes": granted_scopes or [],
95
+ "role": role,
96
+ "context": context or {},
97
+ },
98
+ )
99
+
100
+ def auth_context(self, principal_id: str, scopes: list[str], role: str | None = None, principal_type: str = "agent", email: str | None = None) -> AuthContext:
101
+ return AuthContext(
102
+ principal_id=principal_id,
103
+ principal_type=principal_type,
104
+ scopes=scopes,
105
+ role=role,
106
+ email=email,
107
+ )
@@ -0,0 +1,21 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+
5
+
6
+ @dataclass(slots=True)
7
+ class AuthContext:
8
+ principal_id: str
9
+ principal_type: str
10
+ jti: str
11
+ scopes: list[str] = field(default_factory=list)
12
+ role: str | None = None
13
+ email: str | None = None
14
+
15
+ @property
16
+ def subject_id(self) -> str:
17
+ return self.principal_id
18
+
19
+ @property
20
+ def subject_type(self) -> str:
21
+ return self.principal_type