@kashscript/identity-server
v0.1.1
Published
Server-side did:kash identity — server-issued guest DIDs, handshake challenge/response, self-certifying DID resolution, JWKS publishing, and the MCP-conformant agent-identity profile: OAuth 2.1 + PKCE (S256), RFC 8707 audience-bound, RFC 8693 agent→owner
Readme
@kashscript/identity-server — server identity + the agent-identity profile
Identity is free. Apache-2.0. The server-side half of the Passport, and the auth surface agents talk to MCP servers with.
Built in phase M2 of the protocol Manifestation
(ADR-0016). Where
@kashscript/identity-core is pure did:kash crypto with no I/O, this package
is the server perimeter — and it adds a did:kash-rooted, MCP-conformant token for agents.
Every server-identity API is derived from the @duedale/identity-kernel seed; the agent-identity
profile is derived from the MCP authorization spec + its RFC stack — never invented. Full contract:
specs/identity-server.md.
Two layers
1 · Server identity (ported from the kernel seed, refit onto injectable stores)
- Guest DIDs —
issueGuestDid(): server-generated Ed25519 keypair → self-certifyingdid:kash, private seed surrendered once, 7-day expiry cap. Never self-asserted. - Handshake —
buildHandshakeChallenge()(chal_…, 300 s) + one-timeconsumeHandshakeChallenge()+verifyHandshakeSignature()(DST-free raw Ed25519 / ECDSA-P256). - Resolution — self-certifying
resolveDidPubkey()(pubkey fromparseDid; store gatesNOT_FOUND/REVOKED) +revokeGuestDid(). - PDS contract —
writePdsRecord()/readPdsRecord()with content-addressed CIDs + optimistic revisions. The durable PDS is@kashscript/muffler(M3); this ships the contract- an in-memory reference.
createIdentityServer({ challengeStore, metadataStore, pdsStore })composes it into one instance. Prisma/Redis/muffler adapters stay venture-side — inject them via the store interfaces.
2 · The agent-identity profile (net-new, MCP-conformant)
A did:kash root ("owner") mints an OAuth 2.1 access token a delegated agent presents to an MCP
server:
const { token } = await mintAgentToken({
owner: { did: ownerDid, privateKey }, // sub + signer (did:kash root)
agent: agentDid, // act.sub — the agent→owner binding
audience: "https://mcp.example.com/mcp",// aud (RFC 8707)
issuer, clientId, scope, expiresInSeconds: 300,
});
const res = await verifyAgentToken(token, { expectedAudience: "https://mcp.example.com/mcp" });
// res.ok, res.audienceOk, res.ownerBinding = { owner, agent }- RFC 9068 JWT access token (
typ:"at+jwt",alg:"EdDSA"), signed raw-Ed25519 by the owner. - RFC 8707
audaudience binding — the MCP server MUST validate it is the audience (verifyAgentTokenenforces it; wrongaud→AUDIENCE_MISMATCH). - RFC 8693
act.subdelegation — the agent acting for the owner. - Signer key resolves via an explicit key, a JWKS
kid→x, or — by default — the ownerdid:kashself-certifying (no network). - PKCE S256 only (
pkce), JWKS publish/parse public-only (jwks), RFC 8414 + 9728 discovery metadata (metadata), RFC 8707 resource canonicalization (agent/resource).
Provider-neutral
Errors are KS_IDENTITY_* codes only — a consuming venture maps them to its own envelope at its
perimeter (e.g. Duedale's DD_*). That mapping, the durable store adapters, and issuance policy
(rate-limits, denylists, origin allow-lists) stay venture-side (ADR-0016 guard b).
Status
0.x — the API stays 0.x until the venture consumer (Duedale) swaps onto the published package
and stays green (consumer-as-acceptance, ADR-0016). Depends on
@kashscript/identity-core + @kashscript/attest.
Licensed Apache-2.0 — see LICENSE.
