Metadata-Version: 2.4
Name: auth51
Version: 0.1.1
Summary: auth51 client (embed mode) — in-process egress interception that gives every agent action a scoped, verifiable, DPoP-bound intent token, minted at the source and verified at the resource.
Project-URL: Homepage, https://auth51.com
Project-URL: Repository, https://github.com/unforge-io/auth51-client-python
Author-email: unforge <dev-admin@unforge.io>
License: Proprietary
Keywords: agent-identity,ai-agents,auth51,dpop,intent-token,mcp,oauth
Classifier: Intended Audience :: Developers
Classifier: License :: Other/Proprietary License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: auth51-checksum>=0.1.1
Requires-Dist: cryptography>=42
Requires-Dist: pyjwt>=2.9
Provides-Extra: dev
Requires-Dist: httpx>=0.27; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Description-Content-Type: text/markdown

# auth51 — Python client (embed mode)

The in-process enforcement point: it intercepts your agent's egress and gives
every governed call a **scoped, verifiable intent token** — minted at the source,
verified at the resource. This is the generalized, MCP-era successor to the
original A-JWT client shim, with **contextvar-based agent attribution** (no call-
stack introspection) per DESIGN §7b.

It's the **durable, unbypassable** path: it sees *all* egress in-process (native
tool calls *and* MCP calls), and depends only on the HTTP library — not on any
agent host's conventions.

## Use
```python
import auth51

auth51.configure(
    authority_url="https://authority.auth51.com",
    client_id="...", client_secret="...",
    audiences=["api.internal"],          # hosts to govern; everything else passes through
)

with auth51.agent("ReviewBot", checksum=agent_checksum, scope="read:repo"):
    httpx.get("https://api.internal/repos/...")   # ← stamped with an intent token
```
Config can also come from env: `AUTH51_AUTHORITY_URL`, `AUTH51_CLIENT_ID`,
`AUTH51_CLIENT_SECRET`, `AUTH51_AUDIENCES` (comma-sep), `AUTH51_FAIL_OPEN`.

## How it works
- **One import installs it** (idempotent; a no-op until configured + inside an `agent()` context).
- A framework adapter (LangChain/CrewAI — next) or the app sets the current agent via a contextvar at the tool-call boundary; the interceptor reads it.
- On governed egress: mint a scoped intent token (Hop A) → attach as a Bearer header → forward. Minting uses **stdlib urllib** so it never re-enters the patched HTTP client.
- **fail-open** by default (mint failure → forward unstamped, don't wedge the agent); set `fail_open=False` to fail closed.

## Retained from the original A-JWT client shim
- **Startup-sync (`load_agents`)** — preload registered agents from the authority, index by checksum, detect collisions, and fail-fast on drift when the app declares expected checksums. *Boot-time validation: a mis-deployed agent is caught before it runs.*
- **Workflow seams** — `with auth51.workflow(id): ...` + `record_step(...)` track an execution; the chain + completed-steps + `prev_jti` ride into each intent token's `delegation_context` (§4.3 tamper-evident trace).
- **contextvar attribution** + smart caching — kept; **call-stack introspection dropped.**

## Status
- ✅ contextvar agent attribution · httpx **sync + async** + **requests** interception · mint + attach · fail-open/closed
- ✅ `load_agents()` startup-sync (cache + collision + drift validation) · workflow seams (delegation_context + `prev_jti` chain)
- ✅ LangChain adapter (`auth51.adapters.langchain.Auth51CallbackHandler`) — sets agent context + records steps at tool boundaries
- ⏭️ next: PoP signing (the `cnf` binding) · MCP `_meta` injection · `aiohttp` · local checksum recompute (shared lib) · live e2e against the deployed authority
