Skip to content

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: Optional[Union[str, Path]] DEFAULT: None

dev_mode

If True, auto-generates keys with did:key identity (RFC-002 §6.1).

TYPE: bool DEFAULT: False

rpc_address

gRPC server address. If None, auto-starts local server.

TYPE: Optional[str] DEFAULT: None

agent_id

Explicit agent DID. If None: - In dev_mode: Auto-generates did:key from keypair - Otherwise: Loaded from agent-card.json (deprecated)

TYPE: Optional[str] DEFAULT: None

badge_token

Pre-obtained badge token to use for identity. When set, make_headers() will use this token instead of signing.

TYPE: Optional[str] DEFAULT: None

signing_kid

Explicit key ID for signing. When provided with agent_id, skips agent-card.json entirely.

TYPE: Optional[str] DEFAULT: None

keys_preloaded

If True, skip file-based key loading (keys already loaded in gRPC server, e.g. from CapiscIO.connect()).

TYPE: bool DEFAULT: False

sign_outbound

sign_outbound(
    payload: Dict[str, Any], body: Optional[bytes] = None
) -> str

Sign a payload for outbound transmission.

PARAMETER DESCRIPTION
payload

The JSON payload to sign.

TYPE: Dict[str, Any]

body

Optional HTTP body bytes to bind to the signature.

TYPE: Optional[bytes] DEFAULT: None

RETURNS DESCRIPTION
str

Compact JWS string.

verify_inbound

verify_inbound(
    jws: str, body: Optional[bytes] = None
) -> Dict[str, Any]

Verify an inbound JWS.

PARAMETER DESCRIPTION
jws

The compact JWS string.

TYPE: str

body

Optional HTTP body bytes to verify against 'bh' claim.

TYPE: Optional[bytes] DEFAULT: None

RETURNS DESCRIPTION
Dict[str, Any]

The verified payload.

RAISES DESCRIPTION
VerificationError

If signature is invalid, key is untrusted, or integrity check fails.

make_headers

make_headers(
    payload: Dict[str, Any], body: Optional[bytes] = None
) -> Dict[str, str]

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: Dict[str, Any]

body

Optional HTTP body bytes to bind to the signature.

TYPE: Optional[bytes] DEFAULT: None

RETURNS DESCRIPTION
Dict[str, str]

Dict with X-Capiscio-Badge header.

set_badge_token

set_badge_token(token: str) -> None

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: str

close

close() -> None

Close the gRPC connection.

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: str

capability_class

Dot-notation capability (e.g., "tools.database.read").

TYPE: str

delegation_depth_remaining

How many further delegations allowed (default: 1).

TYPE: int DEFAULT: 1

issuer_badge_jti

JTI of the issuer's badge (optional).

TYPE: str DEFAULT: ''

txn_id

Transaction ID (auto-generated if empty).

TYPE: str DEFAULT: ''

expires_in_seconds

TTL from now (default: 3600).

TYPE: int DEFAULT: 3600

constraints

Optional constraints dict (JSON-serializable).

TYPE: Optional[Dict[str, Any]] DEFAULT: None

subject_badge_jti

JTI of the subject's badge (optional).

TYPE: str DEFAULT: ''

enforcement_mode_min

Minimum enforcement mode (optional).

TYPE: str DEFAULT: ''

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: str

subject_did

DID of the next delegate.

TYPE: str

capability_class

Must be equal or narrower than parent's capability.

TYPE: str

delegation_depth_remaining

Must be < parent's depth (default: 0 = no further delegation).

TYPE: int DEFAULT: 0

issuer_badge_jti

JTI of the child issuer's own badge (optional).

TYPE: str DEFAULT: ''

expires_in_seconds

TTL from now (default: 1800).

TYPE: int DEFAULT: 1800

constraints

Must be equal or more restrictive than parent's.

TYPE: Optional[Dict[str, Any]] DEFAULT: None

subject_badge_jti

JTI of the subject's badge (optional).

TYPE: str DEFAULT: ''

enforcement_mode_min

Minimum enforcement mode (optional, inherited from parent if not set).

TYPE: str DEFAULT: ''

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: list[str]

badge_map

DID → badge JWS for intermediate agents in the chain.

TYPE: Optional[Dict[str, str]] DEFAULT: None

payload

Optional payload for badge signing (if badge_token not set).

TYPE: Optional[Dict[str, Any]] DEFAULT: None

body

Optional HTTP body bytes to bind to badge signature.

TYPE: Optional[bytes] DEFAULT: None

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