Token Delivery at Scale
Use SatGate Mint with your identity provider to auto-issue tokens to agents — no manual minting.
The problem
Manually minting tokens works for 5 agents. It doesn't work for 500. When your platform team is deploying AI agents across Kubernetes clusters, CI pipelines, and multi-cloud environments, you need tokens issued automatically based on the agent's identity — not a human pasting secrets.
How Mint works
SatGate Mint is a token issuance service that maps workload identity to capability tokens. The flow:
- Agent starts up and presents its identity proof — a JWT from its identity provider (OIDC token, K8s service account token, AWS STS token)
- Mint verifies the identity against configured trust policies
- Mint issues a macaroon with caveats derived from the identity claims (tenant, department, budget, TTL)
- Agent uses the macaroon to connect through SatGate — no human in the loop
Agent (K8s Pod) SatGate Mint SatGate Proxy
│ │ │
├── Present SA token ────────────→ │ │
│ ├── Verify with K8s OIDC │
│ ├── Match trust policy │
│ ├── Mint macaroon (budget, TTL) │
│ ← Return capability token ────┤ │
│ │ │
├── Connect with macaroon ──────────────────────────────────────→ │
│ ├── Validate
│ ← Tools available ─────────────────────────────────────────────┤Supported identity providers
Kubernetes
Service account tokens (projected volume). Mint verifies via the cluster's OIDC discovery endpoint. Each namespace/SA maps to a trust policy.
AWS IAM
IAM role credentials via STS. Agents running on EC2, ECS, or Lambda present their role identity. Mint verifies via AWS STS GetCallerIdentity.
OIDC (Generic)
Any OIDC-compliant IdP — Azure AD, Google Workspace, Okta, Auth0. Mint verifies the JWT signature against the IdP's JWKS endpoint.
GitHub Actions
OIDC tokens from GitHub's token endpoint. CI/CD pipelines get scoped tokens per workflow run — no stored secrets.
Setting up a trust policy
Trust policies define which identities get which tokens. Configure them in the Mint dashboard or via API.
Example: Kubernetes service account
# Trust policy: issue tokens to agents in the "ai-agents" namespace
provider: kubernetes
issuer: "https://oidc.eks.us-east-1.amazonaws.com/id/ABCDEF"
audience: "satgate"
trust_rules:
- match:
namespace: "ai-agents"
service_account: "research-agent"
issue:
budget_credits: 1000
ttl: "8h"
caveats:
- "department = research"
- "cost_center = eng-ai"
- match:
namespace: "ai-agents"
service_account: "*"
issue:
budget_credits: 200
ttl: "4h"
caveats:
- "department = general"Example: GitHub Actions
# Trust policy: CI agents get limited tokens per workflow run
provider: oidc
issuer: "https://token.actions.githubusercontent.com"
audience: "satgate"
trust_rules:
- match:
claims:
repository: "acme-corp/ai-pipeline"
ref: "refs/heads/main"
issue:
budget_credits: 500
ttl: "1h"
label_template: "ci-{{ .Claims.run_id }}"
caveats:
- "department = ci-cd"Agent-side integration
From the agent's perspective, getting a token is one HTTP call:
import requests
# Get the workload identity token (K8s projected volume)
with open("/var/run/secrets/tokens/satgate-token") as f:
identity_token = f.read()
# Exchange for a SatGate capability token
resp = requests.post(
"https://cloud.satgate.io/api/mint/exchange",
headers={"Authorization": f"Bearer {identity_token}"},
json={"credentials": identity_token}
)
satgate_token = resp.json()["token"]
# Now connect through SatGate
from satgate import SatGateClient
client = SatGateClient(
url="https://mcp.your-tenant.satgate.io",
token=satgate_token
)Kubernetes pod spec
apiVersion: v1
kind: Pod
spec:
serviceAccountName: research-agent
containers:
- name: agent
image: acme/research-agent:latest
env:
- name: SATGATE_URL
value: "https://mcp.your-tenant.satgate.io"
- name: SATGATE_MINT_URL
value: "https://cloud.satgate.io/api/mint/exchange"
volumeMounts:
- name: satgate-token
mountPath: /var/run/secrets/tokens
readOnly: true
volumes:
- name: satgate-token
projected:
sources:
- serviceAccountToken:
audience: satgate
expirationSeconds: 3600
path: satgate-tokenProduction pattern: zero-touch agent provisioning
In production, agents never see credentials. The entire flow is automated by infrastructure:
1. Platform team configures trust policies
In the Mint dashboard, define which identities get which capabilities. Policies map identity claims (namespace, role, repository) to budgets, TTLs, and scopes.
2. Agent starts and auto-authenticates
When a pod starts, a CI job runs, or a Lambda fires — the agent reads its environment identity and exchanges it in one call:
# Init container or agent startup
import requests, os
# Identity is already in the environment — no secrets to manage
identity = open("/var/run/secrets/tokens/satgate-token").read()
# One call to get a capability token
token = requests.post(
os.environ["SATGATE_MINT_URL"],
json={"credentials": identity}
).json()["token"]
# Token has: tenant binding, budget, scope, TTL — all from policy
# Agent connects and starts calling tools
os.environ["SATGATE_TOKEN"] = token3. Scale to thousands
This pattern scales linearly. Each agent independently authenticates — no central secret store, no credential rotation pipeline, no shared API keys that one breach could compromise. When you add a new agent class, add a trust policy. When you decommission agents, revoke the policy. The identity provider handles the rest.
┌─────────────────────────────────────────────────────────────┐
│ Your Infrastructure │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Agent A │ │ Agent B │ │ Agent C │ │ Agent D │ │
│ │ (K8s SA) │ │ (IAM) │ │ (OIDC) │ │ (GitHub) │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │ │
│ └──────────────┴──────────────┴──────────────┘ │
│ │ │
│ POST /api/mint/exchange │
│ { credentials: <identity_token> } │
│ │ │
│ ┌──────┴──────┐ │
│ │ SatGate │ │
│ │ Mint │ │
│ │ │ │
│ │ Verify → │ │
│ │ Match → │ │
│ │ Issue → │ │
│ └──────┬──────┘ │
│ │ │
│ Macaroon (tenant + budget + scope) │
│ │ │
│ ┌──────┴──────┐ │
│ │ SatGate │ │
│ │ MCP Proxy │──→ Upstream Tools │
│ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘CI/CD integration (GitHub Actions)
# .github/workflows/agent-job.yml
jobs:
run-agent:
permissions:
id-token: write # Required for OIDC token
steps:
- name: Get SatGate token
run: |
# GitHub provides the OIDC token automatically
IDENTITY=$(curl -s -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=satgate" | jq -r '.value')
# Exchange for SatGate capability token
SATGATE_TOKEN=$(curl -s -X POST $SATGATE_MINT_URL \
-H "Content-Type: application/json" \
-d "{\"credentials\": \"$IDENTITY\"}" | jq -r '.token')
echo "SATGATE_TOKEN=$SATGATE_TOKEN" >> $GITHUB_ENV
- name: Run AI agent
run: |
# Agent uses the token — scoped to this workflow, this repo, this run
python agent.py --satgate-token $SATGATE_TOKENToken lifecycle
- Auto-rotation. Agents can re-exchange their identity token before the macaroon expires. The SDK handles this automatically with a refresh loop.
- Budget inheritance. Trust policies define the budget ceiling. Agents can't request more than the policy allows. Delegation from Mint-issued tokens still works — agents can create child tokens with lower budgets.
- Revocation. Revoke individual tokens or invalidate an entire trust policy. Policy revocation immediately stops new issuance; existing tokens expire at their TTL.
- Audit trail. Every Mint exchange is logged — which identity, which policy matched, what caveats were applied. Visible in the Audit Log dashboard.
Why this matters
The shift: Traditional API gateways authenticate with static API keys or OAuth client credentials. Both require secrets management infrastructure. With Mint, your agents authenticate with the identity they already have — their K8s service account, their IAM role, their OIDC token. No secrets to rotate. No credentials to leak. The identity is the credential.