Skip to main content

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.

Dashboard walkthrough

For registering the trust domain and connecting the workload with screenshots, see Kubernetes / SPIFFE (dashboard guide).

New to SPIFFE?

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:

  1. SPIRE server + agents — the standard SPIRE quickstart
  2. 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
  3. The OIDC discovery endpoint exposed (spire-oidc-discovery-provider) — the public URL AuthSec fetches your trust domain's keys from
  4. 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):

ParameterWhat it doesWhere it comes from
mcp_server_urlThe target MCP server's Resource URI. The SDK requests tokens scoped to this audience.The Resource URI from registration
client_idThe 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_idThe 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
scopesThe OAuth scopes to request. Must exist on the target server's scope vocabulary.From the server's PRM or the Scopes tab
agent_socket_pathPath 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. SpiffeSvidAuth does not auto-renew (use SpiffeWorkloadIdentity for that).

Shared steps