Observed since 20 Oct, 16:50 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
AAC sidecar-to-agent invoke-push authentication (AAC1-HMAC-SHA256) — signing and verification core, with FastAPI mounting surfaces.
Authenticate /invoke pushes from your paired AAC sidecar.
When your agent runs behind an AAC sidecar, the sidecar verifies the
cross-organizational authority chain and then POSTs the verified context
to your agent's /invoke endpoint. The X-AAC-* headers on that push
are your agent's entire view of the verified chain — so your agent
must be able to tell a genuine sidecar push from a forged one. This
package is that check: the sidecar HMAC-signs every push with a pairing
secret shared with exactly one agent, and your agent verifies the
signature before trusting anything.
The verification core is standard-library only (hmac, hashlib) and
framework-agnostic. FastAPI mounting surfaces ship behind an extra:
pip install aac-invoke-auth[fastapi]
Generate the pairing secret once and share the file with your sidecar
(the sidecar's sidecar.agent_invoke_auth.secret_file points at the
same file; one secret per sidecar–agent pair, never shared across
pairs):
openssl rand -hex 32 > /etc/aac/invoke-auth/invoke-auth.secret
Point your agent at it and mount the middleware:
export AAC_INVOKE_AUTH_SECRET_FILE=/etc/aac/invoke-auth/invoke-auth.secret
from fastapi import FastAPI
from aac_invoke_auth.fastapi import InvokeAuthGuard, InvokeAuthMiddleware
app = FastAPI()
app.add_middleware(
InvokeAuthMiddleware,
guard=InvokeAuthGuard.from_env(),
protected_paths=("/invoke",), # required, exact-match
)
That's the whole integration. Unsigned, tampered, replayed-stale, or
wrong-secret pushes get a 401 with a generic detail and never reach
your business logic; your handlers read request.json() unchanged.
Prefer route-scoped protection? The guard is also a plain FastAPI dependency:
from fastapi import Depends
guard = InvokeAuthGuard.from_env()
@app.post("/invoke", dependencies=[Depends(guard)])
async def invoke(request: Request): ...
Both surfaces call the same verifier — pick whichever fits your app.
InvokeAuthGuard.from_env() refuses to start when
AAC_INVOKE_AUTH_SECRET_FILE is unset. A missing secret is a security
downgrade; it should fail your deployment loudly at boot, not degrade
into a log line nobody reads.
The single escape hatch — for extraordinary cases only, such as tenant test/pilot environments or debugging a suspected signing mismatch — is setting
export AAC_INVOKE_AUTH_ALLOW_UNAUTHENTICATED=true
explicitly (only the exact value true; a typo still fails the boot).
An opted-out agent accepts every push unverified and logs a prominent
warning at startup so the posture is visible in your logs. Never run
this in production: the sidecar side has a symmetric dev_mode
interlock, and both exist to make "unauthenticated" impossible to reach
by accident.
aac_invoke_auth.testing ships with the package:
from aac_invoke_auth.testing import signing_test_client
client = signing_test_client(app) # wraps FastAPI's TestClient
response = client.post("/invoke", headers=aac_headers, json=payload)
post() calls to protected paths are signed exactly the way the paired
sidecar signs them (secret read from AAC_INVOKE_AUTH_SECRET_FILE);
everything else passes through. So your test suite exercises the real
production verification path instead of opting out of it.
AAC1-HMAC-SHA256 over method, path, timestamp, a SHA-256 body digest,
and every X-AAC-* header (derived by rule, so header
insertion/removal after signing fails verification). Freshness window
±30s. The canonicalization is frozen behind the algorithm name: a
change that alters any signature is a wire-format break and ships under
a new algorithm prefix, never as an update to AAC1-HMAC-SHA256.
Ports of this middleware for other stacks (Express, Spring, Go net/http) follow the same model; the core stays standard-library-only in every language precisely to keep those ports mechanical.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.1.2 | 14 Sept 2026 | 3 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 16:50 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:d2a3955cbf586cb47d7a76c100bc8da33cae613600ce95961c0aed5ba5430f10