SimpleGuard¶
Zero-configuration security for signing and verifying A2A requests.
Overview¶
SimpleGuard is the recommended way to add security to your A2A agent. It handles:
- Signing outbound requests with JWS (JSON Web Signature)
- Verifying inbound requests against a trust store
- Key management with file-based storage
Basic Usage¶
from capiscio_sdk.simple_guard import SimpleGuard
# Initialize - uses convention over configuration
# Looks for capiscio_keys/ and agent-card.json in project root
guard = SimpleGuard(dev_mode=True) # Auto-generates keys for development
# Sign a request
body = b'{"method": "tasks/send", "params": {}}'
jws = guard.sign_outbound({}, body=body)
# Verify an incoming request
claims = guard.verify_inbound(jws, body=body)
Convention Over Configuration¶
SimpleGuard automatically finds keys based on directory structure:
your-project/
├── agent-card.json # Agent identity
└── capiscio_keys/
├── private.pem # Signing key
├── public.pem # Public key
└── trusted/ # Trust store
└── {kid}.pem # Trusted keys (filename = key ID)
In dev_mode=True, all files are auto-generated if missing.
API Reference¶
capiscio_sdk.simple_guard.SimpleGuard ¶
Zero-config security middleware for A2A agents.
SimpleGuard handles message signing and verification using Ed25519 keys. All cryptographic operations are performed by the capiscio-core Go library via gRPC, ensuring consistent behavior across all SDKs.
Example
guard = SimpleGuard(dev_mode=True) token = guard.sign_outbound({"sub": "test"}, body=b"hello") claims = guard.verify_inbound(token, body=b"hello")
With explicit agent_id:¶
guard = SimpleGuard(agent_id="did:web:example.com:agents:myagent")
In dev mode, did:key is auto-generated:¶
guard = SimpleGuard(dev_mode=True) print(guard.agent_id) # did
z6Mk...
__init__ ¶
__init__(
base_dir: Optional[Union[str, Path]] = None,
dev_mode: bool = False,
rpc_address: Optional[str] = None,
agent_id: Optional[str] = None,
badge_token: Optional[str] = None,
signing_kid: Optional[str] = None,
keys_preloaded: bool = False,
) -> None
Initialize SimpleGuard.
| PARAMETER | DESCRIPTION |
|---|---|
base_dir | Starting directory to search for config (defaults to cwd). TYPE: |
dev_mode | If True, auto-generates keys with did:key identity (RFC-002 §6.1). TYPE: |
rpc_address | gRPC server address. If None, auto-starts local server. TYPE: |
agent_id | Explicit agent DID. If None: - In dev_mode: Auto-generates did:key from keypair - Otherwise: Loaded from agent-card.json (deprecated) TYPE: |
badge_token | Pre-obtained badge token to use for identity. When set, make_headers() will use this token instead of signing. TYPE: |
signing_kid | Explicit key ID for signing. When provided with agent_id, skips agent-card.json entirely. TYPE: |
keys_preloaded | If True, skip file-based key loading (keys already loaded in gRPC server, e.g. from CapiscIO.connect()). TYPE: |
sign_outbound ¶
Sign a payload for outbound transmission.
| PARAMETER | DESCRIPTION |
|---|---|
payload | The JSON payload to sign. TYPE: |
body | Optional HTTP body bytes to bind to the signature. TYPE: |
| RETURNS | DESCRIPTION |
|---|---|
str | Compact JWS string. |
verify_inbound ¶
Verify an inbound JWS.
| PARAMETER | DESCRIPTION |
|---|---|
jws | The compact JWS string. TYPE: |
body | Optional HTTP body bytes to verify against 'bh' claim. TYPE: |
| RETURNS | DESCRIPTION |
|---|---|
Dict[str, Any] | The verified payload. |
| RAISES | DESCRIPTION |
|---|---|
VerificationError | If signature is invalid, key is untrusted, or integrity check fails. |
make_headers ¶
Generate headers containing the Badge (RFC-002 §9.1).
If a badge_token was provided at construction, it will be used. Otherwise, signs the payload to create a token.
| PARAMETER | DESCRIPTION |
|---|---|
payload | The JSON payload to sign (ignored if using badge_token). TYPE: |
body | Optional HTTP body bytes to bind to the signature. TYPE: |
| RETURNS | DESCRIPTION |
|---|---|
Dict[str, str] | Dict with X-Capiscio-Badge header. |
set_badge_token ¶
Update the badge token used for outbound requests.
This is typically called by the badge keeper when a new token is obtained.
| PARAMETER | DESCRIPTION |
|---|---|
token | The new badge token (compact JWS). TYPE: |
create_envelope ¶
create_envelope(
subject_did: str,
capability_class: str,
delegation_depth_remaining: int = 1,
issuer_badge_jti: str = "",
txn_id: str = "",
expires_in_seconds: int = 3600,
constraints: Optional[Dict[str, Any]] = None,
subject_badge_jti: str = "",
enforcement_mode_min: str = "",
) -> str
Create a root Authority Envelope delegating authority to another agent (RFC-008 §6.1).
The envelope is signed with this agent's key and authorizes subject_did to act within the specified capability class.
| PARAMETER | DESCRIPTION |
|---|---|
subject_did | DID of the agent receiving delegated authority. TYPE: |
capability_class | Dot-notation capability (e.g., "tools.database.read"). TYPE: |
delegation_depth_remaining | How many further delegations allowed (default: 1). TYPE: |
issuer_badge_jti | JTI of the issuer's badge (optional). TYPE: |
txn_id | Transaction ID (auto-generated if empty). TYPE: |
expires_in_seconds | TTL from now (default: 3600). TYPE: |
constraints | Optional constraints dict (JSON-serializable). TYPE: |
subject_badge_jti | JTI of the subject's badge (optional). TYPE: |
enforcement_mode_min | Minimum enforcement mode (optional). TYPE: |
| RETURNS | DESCRIPTION |
|---|---|
str | JWS Compact Serialization string of the signed envelope. |
| RAISES | DESCRIPTION |
|---|---|
ConfigurationError | If signing fails or key is not available. |
derive_envelope ¶
derive_envelope(
parent_envelope_jws: str,
subject_did: str,
capability_class: str,
delegation_depth_remaining: int = 0,
issuer_badge_jti: str = "",
expires_in_seconds: int = 1800,
constraints: Optional[Dict[str, Any]] = None,
subject_badge_jti: str = "",
enforcement_mode_min: str = "",
) -> str
Derive a child Authority Envelope from a parent (RFC-008 §6.3).
Creates a hash-linked child with monotonic narrowing validation.
| PARAMETER | DESCRIPTION |
|---|---|
parent_envelope_jws | The parent envelope JWS to derive from. TYPE: |
subject_did | DID of the next delegate. TYPE: |
capability_class | Must be equal or narrower than parent's capability. TYPE: |
delegation_depth_remaining | Must be < parent's depth (default: 0 = no further delegation). TYPE: |
issuer_badge_jti | JTI of the child issuer's own badge (optional). TYPE: |
expires_in_seconds | TTL from now (default: 1800). TYPE: |
constraints | Must be equal or more restrictive than parent's. TYPE: |
subject_badge_jti | JTI of the subject's badge (optional). TYPE: |
enforcement_mode_min | Minimum enforcement mode (optional, inherited from parent if not set). TYPE: |
| RETURNS | DESCRIPTION |
|---|---|
str | JWS Compact Serialization string of the signed child envelope. |
| RAISES | DESCRIPTION |
|---|---|
ConfigurationError | On narrowing violation, depth exceeded, or signing failure. |
make_delegation_headers ¶
make_delegation_headers(
chain: list[str],
badge_map: Optional[Dict[str, str]] = None,
payload: Optional[Dict[str, Any]] = None,
body: Optional[bytes] = None,
) -> Dict[str, str]
Generate HTTP headers for a delegated request (RFC-008 §15.1–§15.3).
Combines the delegation chain headers with the standard badge header.
| PARAMETER | DESCRIPTION |
|---|---|
chain | Ordered list of envelope JWS strings [root, ..., leaf]. TYPE: |
badge_map | DID → badge JWS for intermediate agents in the chain. TYPE: |
payload | Optional payload for badge signing (if badge_token not set). TYPE: |
body | Optional HTTP body bytes to bind to badge signature. TYPE: |
| RETURNS | DESCRIPTION |
|---|---|
Dict[str, str] | Dict with X-Capiscio-Badge, X-Capiscio-Authority, |
Dict[str, str] | X-Capiscio-Authority-Chain, and optionally X-Capiscio-Badge-Map headers. |
Authority Envelopes (RFC-008)¶
SimpleGuard provides methods for creating and verifying delegated authority chains. See the Delegation Chains concept for background.
create_envelope()¶
Create a root Authority Envelope delegating authority to another agent.
envelope_jws = guard.create_envelope(
subject_did="did:web:worker.example.com",
capability_class="tools.database.read",
delegation_depth_remaining=1,
expires_in_seconds=3600,
)
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
subject_did | str | (required) | DID of the agent receiving delegated authority |
capability_class | str | (required) | Dot-notation capability (e.g., tools.database.read) |
delegation_depth_remaining | int | 1 | How many further delegations allowed |
issuer_badge_jti | str | "" | JTI of the issuer's badge |
txn_id | str | "" | Transaction ID (auto-generated if empty) |
expires_in_seconds | int | 3600 | TTL from now |
constraints | dict | None | None | JSON-serializable constraints |
subject_badge_jti | str | "" | JTI of the subject's badge |
enforcement_mode_min | str | "" | Minimum enforcement mode |
Returns: str — JWS Compact Serialization of the signed envelope.
Raises: ConfigurationError — If signing fails or key is not available.
derive_envelope()¶
Derive a child Authority Envelope from a parent, with hash linking and monotonic narrowing validation.
child_jws = guard.derive_envelope(
parent_envelope_jws=root_envelope,
subject_did="did:web:reader.example.com",
capability_class="tools.database.read",
delegation_depth_remaining=0,
constraints={"tables": ["users"]},
)
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
parent_envelope_jws | str | (required) | Parent envelope JWS to derive from |
subject_did | str | (required) | DID of the next delegate |
capability_class | str | (required) | Must be equal or narrower than parent's |
delegation_depth_remaining | int | 0 | Must be less than parent's depth |
issuer_badge_jti | str | "" | JTI of the child issuer's own badge |
expires_in_seconds | int | 1800 | TTL from now |
constraints | dict | None | None | Must be equal or more restrictive than parent's |
subject_badge_jti | str | "" | JTI of the subject's badge |
enforcement_mode_min | str | "" | Cannot relax parent's mode |
Returns: str — JWS Compact Serialization of the signed child envelope.
Raises: ConfigurationError — On narrowing violation, depth exceeded, or signing failure.
make_delegation_headers()¶
Generate HTTP headers for a delegated request combining the delegation chain with the agent's badge.
headers = guard.make_delegation_headers(
chain=[root_envelope, child_envelope],
badge_map={"did:web:worker.example.com": worker_badge_jws},
)
# headers contains: X-Capiscio-Badge, X-Capiscio-Authority,
# X-Capiscio-Authority-Chain, X-Capiscio-Badge-Map
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
chain | list[str] | (required) | Ordered list of envelope JWS strings [root, ..., leaf] |
badge_map | dict | None | None | DID → badge JWS for intermediate agents in the chain |
payload | dict | None | None | Optional payload for badge signing |
body | bytes | None | None | Optional HTTP body bytes to bind to badge signature |
Returns: dict[str, str] — Dictionary with these headers:
| Header | Description |
|---|---|
X-Capiscio-Badge | This agent's badge JWS |
X-Capiscio-Authority | Leaf envelope JWS |
X-Capiscio-Authority-Chain | Base64url-encoded JSON array of the full chain |
X-Capiscio-Badge-Map | JSON mapping of intermediate DIDs to badge JWS tokens |