Observed since 20 Oct, 21:31 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
agentauth-agents
A scalable, framework-agnostic Python authentication library with JWT token management and password reset functionality
🚀 Ship AI Agents with Enterprise-Grade Security in Minutes
📚 Documentation • 🚀 Quick Start • 💡 Examples • 🤝 Contributing
AgentAuth is a battle-tested, production-ready Python authentication & authorization framework built specifically for AI agents, autonomous systems, and agent-to-agent (A2A) communication. Zero framework coupling. Maximum security.
✨ Used by teams building the future of AI ✨
db:read, email:send)low, medium, high) alongside scopes@require_scope decorator for function-level authorizationpip install agentauth-agents
# FastAPI + Uvicorn support
pip install agentauth-agents[fastapi]
# Flask support
pip install agentauth-agents[flask]
# PostgreSQL support
pip install agentauth-agents[psycopg]
git clone https://github.com/MrunalHedau4102/agentauth.git
cd agentauth
pip install -e ".[dev]"
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from agentauth.db import Base
# Create engine and initialize schema
engine = create_engine("postgresql://user:pass@localhost/agentdb")
Base.metadata.create_all(bind=engine)
Session = sessionmaker(bind=engine)
session = Session()
from agentauth import AgentIdentity, AgentRegistry
# Create agent identity
agent = AgentIdentity(
agent_id="agent-claude-001",
display_name="Claude AI Assistant",
owner="anthropic",
scopes_requested=["knowledge:search", "tools:execute"]
)
# Generate cryptographic key pair
private_key, public_key = AgentIdentity.generate_keypair(algorithm="ed25519")
agent.public_key = public_key
agent.private_key = private_key
# Register in database
registry = AgentRegistry(session)
registered = registry.register_agent(agent)
print(f"Registered: {registered['agent_id']} with trust level: {registered['trust_level']}")
from agentauth import ScopeManager
scope_manager = ScopeManager(session)
# Grant scopes with trust requirements
scope_manager.grant_scope("agent-claude-001", "knowledge:search", trust_level_required="low")
scope_manager.grant_scope("agent-claude-001", "tools:execute", trust_level_required="high")
scope_manager.grant_scope("agent-claude-001", "data:delete", trust_level_required="high")
from agentauth import EphemeralTokenVault
import os
# Initialize token vault
vault = EphemeralTokenVault(
secret_key=os.getenv("AGENTAUTH_SECRET_KEY"),
session=session
)
# Issue token
token = vault.issue(
agent_id="agent-claude-001",
scopes=["knowledge:search", "tools:execute"],
ttl_seconds=300, # 5-minute lifetime
bound_to="https://claude.anthropic.com",
trust_level="high"
)
print(f"Token issued: {token[:20]}...")
from agentauth import set_current_token, require_scope
import functools
# Verify token
payload = vault.verify(token, expected_bound_to="https://claude.anthropic.com")
print(f"Token valid for agent: {payload['agent_id']}")
# Use context to set token for scope checking
ctx_token = set_current_token(payload)
try:
@require_scope("knowledge:search", trust_level="low")
def search_knowledge_base(query: str):
"""This function requires 'knowledge:search' scope."""
return f"Results for: {query}"
# Function executes successfully if scope is granted
results = search_knowledge_base("AI agents")
print(results)
finally:
# Clean up context
from agentauth import clear_current_token
clear_current_token(ctx_token)
from agentauth import PromptInjectionGuard
guard = PromptInjectionGuard(strict=True, max_field_length=2000)
# Inspect tool arguments before execution
try:
guard.inspect("search_api", {
"query": "find documents about machine learning",
"limit": 10
})
# Safe to execute tool
except Exception as e:
print(f"Injection detected: {e}")
from agentauth import AuditLogger
audit = AuditLogger(session)
# Log events
audit.log(
event_type="token_issued",
agent_id="agent-claude-001",
outcome="success",
ip_address="192.168.1.100",
scopes=["knowledge:search", "tools:execute"],
metadata={"request_id": "req-12345"}
)
# Verify audit chain integrity
if audit.verify_chain():
print("Audit trail is tamper-free")
# Query events
recent_events = audit.get_events(agent_id="agent-claude-001")
for event in recent_events:
print(f"{event['timestamp']}: {event['event_type']} - {event['outcome']}")
Scopes define what an agent can do. Examples:
db:read — Read from databasedb:write — Write to databasedb:delete — Delete from databaseemail:send — Send emailsapi:call — Call external APIsknowledge:search — Search knowledge baseEvery security-relevant event is logged with:
AgentIdentity(
agent_id: str,
public_key: Optional[str] = None,
private_key: Optional[str] = None,
metadata_url: Optional[str] = None,
trust_level: str = "untrusted",
display_name: Optional[str] = None,
owner: Optional[str] = None,
scopes_requested: List[str] = []
)
generate_keypair(algorithm: str) -> Tuple[str, str] — Generate cryptographic key pairfrom_url(url: str) -> AgentIdentity — Fetch agent from remote JSONto_dict() -> Dict — Serialize to dictionaryregistry = AgentRegistry(session)
# Register agent
registry.register_agent(agent: AgentIdentity) -> Dict
# Retrieve agent
registry.get_agent(agent_id: str) -> AgentIdentity
# Update trust level
registry.trust_agent(agent_id: str, trust_level: str) -> Dict
# Revoke agent
registry.revoke_agent(agent_id: str) -> Dict
# List agents
registry.list_agents(include_revoked: bool = False) -> List[Dict]
vault = EphemeralTokenVault(secret_key: str, session: Optional[Session])
# Issue token
vault.issue(
agent_id: str,
scopes: Optional[List[str]] = None,
ttl_seconds: int = 30,
one_time_use: bool = False,
bound_to: Optional[str] = None,
trust_level: str = "low"
) -> str
# Verify token
vault.verify(
token: str,
expected_bound_to: Optional[str] = None
) -> Dict
scope_mgr = ScopeManager(session)
# Grant scope
scope_mgr.grant_scope(agent_id: str, scope: str, trust_level_required: str = "low") -> Dict
# Revoke scope
scope_mgr.revoke_scope(agent_id: str, scope: str) -> bool
# List scopes
scope_mgr.list_scopes(agent_id: str) -> List[Dict]
# Validate scope
scope_mgr.validate_scope(token_payload: Dict, scope: str, trust_level: str = "low") -> bool
@require_scope("scope:name", trust_level="low")
def protected_function():
return "This is protected"
# Before calling:
from agentauth import set_current_token, clear_current_token
token_ctx = set_current_token(token_payload)
try:
protected_function()
finally:
clear_current_token(token_ctx)
guard = PromptInjectionGuard(
strict: bool = True,
audit_logger: Optional[AuditLogger] = None,
max_field_length: int = 2000
)
# Inspect arguments
findings = guard.inspect(tool_name: str, args: Dict[str, Any]) -> List[Dict]
audit = AuditLogger(session)
# Log event
audit.log(
event_type: str,
agent_id: Optional[str] = None,
user_id: Optional[int] = None,
outcome: str = "success",
ip_address: Optional[str] = None,
scopes: Optional[List[str]] = None,
metadata: Optional[Dict] = None
) -> Dict
# Verify chain
audit.verify_chain() -> bool
# Query events
audit.get_events(
agent_id: Optional[str] = None,
event_type: Optional[str] = None,
since: Optional[datetime] = None
) -> List[Dict]
Create a .env file:
# JWT Configuration
JWT_SECRET_KEY=your-super-secret-key-change-this-in-production
JWT_ALGORITHM=HS256
# Database Configuration
DATABASE_URL=postgresql://user:password@localhost:5432/agentauth_db
# Token Configuration
TOKEN_EXPIRY_MINUTES=15
TOKEN_REFRESH_EXPIRY_DAYS=7
# Password Reset
PASSWORD_RESET_TOKEN_EXPIRY_MINUTES=60
# Bcrypt Configuration
BCRYPT_LOG_ROUNDS=12
See .env.example for all configuration options.
# Run all tests
pytest tests/ -v
# Run with coverage
pytest tests/ --cov=agentauth --cov-report=html
# Run specific test file
pytest tests/test_agents.py -v
# Run with markers
pytest tests/ -m "not slow" -v
See the examples/ directory for complete working examples:
We welcome contributions! See CONTRIBUTING.md for guidelines.
Found a security vulnerability? Please email mrunalh1234@gmail.com with details. See SECURITY.md for full disclosure policy.
This project is licensed under the MIT License - see the LICENSE file for details.
AgentAuth is maintained by the AuthLib Contributors.
Download counts and popularity will appear here as the collector receives them.
| Package / target | Requirement | Relationship |
|---|---|---|
sqlalchemyEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | sqlalchemy<3.0.0,>=2.0.0 | runtime |
PyJWTEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | PyJWT>=2.8.0 | runtime |
bcryptEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | bcrypt>=4.1.0 | runtime |
pydanticEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | pydantic>=2.5.0 | runtime |
python-dotenvEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | python-dotenv>=1.0.0 | runtime |
psycopg2-binaryEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | psycopg2-binary>=2.9.11 | runtime |
cryptographyEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | cryptography>=42.0.0 | runtime |
pytestEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | pytest<9.0.0,>=7.4.0; extra == "dev" | runtime |
pytest-covEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | pytest-cov<6.0.0,>=4.1.0; extra == "dev" | runtime |
pytest-asyncioEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | pytest-asyncio<1.0.0,>=0.21.0; extra == "dev" | runtime |
blackEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | black<25.0.0,>=23.0.0; extra == "dev" | runtime |
flake8Environment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | flake8<8.0.0,>=6.0.0; extra == "dev" | runtime |
mypyEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | mypy<2.0.0,>=1.0.0; extra == "dev" | runtime |
isortEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | isort<6.0.0,>=5.12.0; extra == "dev" | runtime |
fastapiEnvironment{
"extras": "",
"marker": "extra == \"fastapi\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | fastapi<1.0.0,>=0.104.0; extra == "fastapi" | runtime |
uvicornEnvironment{
"extras": "",
"marker": "extra == \"fastapi\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | uvicorn<1.0.0,>=0.24.0; extra == "fastapi" | runtime |
flaskEnvironment{
"extras": "",
"marker": "extra == \"flask\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | flask<4.0.0,>=3.0.0; extra == "flask" | runtime |
psycopgEnvironment{
"extras": "binary",
"marker": "extra == \"psycopg\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | psycopg[binary]<4.0.0,>=3.1.0; extra == "psycopg" | runtime |
bdist_wheel · 78.8 KB · Python py3
sdist · 73.5 KB · Python source
Observed since 20 Oct, 21:31 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package_version:caf60d6de7e5e23e83e8f9d35e41c77f8481bbef9b2ff9e6f71abc69f0c20cb6