Method C — Kubernetes / SPIFFE (Python SDK)
The strongest credential: no stored secret at all. The SPIRE agent on the node attests your pod and issues a short-lived (~5 min) JWT-SVID; AuthSec verifies it against your registered trust domain.
For registering the trust domain and connecting the workload with screenshots, see Kubernetes / SPIFFE (dashboard guide).
Read Workload identity and SPIFFE for the conceptual background — what SPIFFE is, why it matters for AI workloads, and how it compares to other credential types.
How the attestation chain works
your pod ──(unix socket)──▶ SPIRE agent ──▶ JWT-SVID (5 min)
│ │
└── SDK sends SVID as client assertion ──────┘
│
▼
AuthSec verifies against your trust domain's
OIDC discovery (the "workload identity provider")
│
▼
scoped access token
SPIRE prerequisites
You need a running SPIRE deployment with:
- SPIRE server + agents — the standard SPIRE quickstart
- A registration entry mapping your pod to a SPIFFE ID:
spire-server entry create \
-spiffeID spiffe://your-trust-domain/your-workload \
-parentID spiffe://your-trust-domain/spire-agent \
-selector k8s:ns:default -selector k8s:sa:your-service-account - The OIDC discovery endpoint exposed (spire-oidc-discovery-provider) — the public URL AuthSec fetches your trust domain's keys from
- The agent socket mounted into the pod:
volumes:
- name: spire-agent-socket
hostPath: { path: /run/spire/sockets, type: Directory }
containers:
- name: your-app
volumeMounts:
- name: spire-agent-socket
mountPath: /run/spire/sockets
readOnly: true
Configuration parameters
SpiffeConfig takes these values (passed directly, not from env vars):
| Parameter | What it does | Where it comes from |
|---|---|---|
mcp_server_url | The target MCP server's Resource URI. The SDK requests tokens scoped to this audience. | The Resource URI from registration |
client_id | The workload's client ID in AuthSec. Identifies which grant to use for the token exchange. | Shown on the Install screen of the connect wizard |
spiffe_id | The SPIFFE ID this pod presents. Must match the SVID's sub claim exactly and the ID registered in the wizard's Trust step. | Your SPIRE registration entry |
scopes | The OAuth scopes to request. Must exist on the target server's scope vocabulary. | From the server's PRM or the Scopes tab |
agent_socket_path | Path to the SPIRE agent's unix socket. Defaults to /run/spire/sockets/agent.sock. | Your pod spec volume mount (step 4 of SPIRE prereqs) |
SpiffeWorkloadIdentity — the high-level class
Inside the pod, the SDK fetches and renews SVIDs automatically from the agent socket:
import asyncio
from authsec_sdk import SpiffeWorkloadIdentity, SpiffeConfig
async def main():
spiffe = SpiffeWorkloadIdentity(SpiffeConfig(
mcp_server_url="https://your-mcp-server.example.com/mcp",
client_id="YOUR_SPIFFE_CLIENT_ID",
spiffe_id="spiffe://your-domain/your-workload",
scopes=["my_mcp:read"],
# agent_socket_path="/run/spire/sockets/agent.sock", # default
))
async with spiffe:
token = await spiffe.access_for()
print("token:", token[:25], "…")
asyncio.run(main())
SpiffeWorkloadIdentity handles SVID minting, audience targeting, and
renewal transparently. Use this in production.
SpiffeSvidAuth — the low-level class
For testing outside a pod (e.g. with a manually minted SVID):
from authsec_sdk import AgentIdentity, SpiffeSvidAuth
agent = AgentIdentity(ISSUER, SPIFFE_CLIENT_ID, auth=SpiffeSvidAuth(svid))
async with agent:
token = await agent.access_for(MCP_URL, requested_scopes=["my_mcp:read"])
Two hard-won rules:
- The SVID's audience must be the token endpoint
(
https://app.authsec.ai/oauth/token) — an SVID minted with just the issuer as audience is rejected with "token aud must include this token endpoint". - SVIDs live ~5 minutes — mint immediately before use.
SpiffeSvidAuthdoes not auto-renew (useSpiffeWorkloadIdentityfor that).