keyward.broker console
control plane onlineonlinedev mode
Docs / SDK

@keyward/sdk

One client, one method. The SDK never holds an upstream secret — it asks the broker for a scoped, short-lived credential and caches it client-side until it nears expiry, so a tight tool-call loop hits the control plane once, not every call.

createClient(config)

OptionTypeWhat it does
controlPlaneUrlstringyour broker's base URL (required)
tokenstringthe END USER's identity token from your IdP (required)
agentstringthis agent's registered id (required)
cachebooleanclient-side credential cache; default true
cacheSkewMsnumberrefetch this many ms before expiry; default 10 000
environmentstringisolated secret/policy set: dev | staging | prod (default prod)
agentAssertionstring | () => stringworkload-identity token for attested agents (“secret zero”)
fetchtypeof fetchcustom transport (testing, proxies)

client.get(provider, scope, ttl?, opts?)

Returns a Credential: the signed token itself plus token_type, provider, scope, expires_at, and the delegation pair (user + agent). TTL defaults to 5 minutes; the broker enforces its own ceiling. Denials throw KeywardError with the broker's status and reason.

basic call
const cred = await kw.get("stripe", "charges:read", "5m");
await fetch("https://api.stripe.com/v1/charges", {
  headers: { authorization: `${cred.token_type} ${cred.credential}` },
});

Delegation chains

A sub-agent acting under an orchestrator passes the orchestrator's credential instead of a user token. The broker verifies it, keeps the original human sub, and extends the RFC 8693 actor chain — nested, splice-resistant, depth-capped at 5.

orchestrator → sub-agent
// orchestrator got `cred` the normal way; hands it to the sub-agent
const sub = createClient({ controlPlaneUrl, token: "", agent: "sub-agent" });
const delegated = await sub.get("stripe", "charges:read", "5m", {
  delegation: cred.credential,
});
// delegated.credential's chain: user → orchestrator → sub-agent

Attested agents (secret zero)

If an agent is registered with an attestation_issuer, the broker fails closed unless the request carries a verifiable workload-identity token (GitHub Actions OIDC, Kubernetes service account, cloud instance identity). Pass a function to mint a fresh one per request:

GitHub Actions example
const kw = createClient({
  controlPlaneUrl, token, agent: "ci-bot",
  agentAssertion: () => getGithubOidcToken(), // fresh per request
});

Verifying issued credentials

Credentials are RS256 JWTs with a kid header. Resource servers verify them against the broker's public JWKS at GET /v1/jwks — no shared secret needed.