Skip to content

alien-id/agent-id

Repository files navigation

Alien Agent ID

Alien Agent ID

Verifiable cryptographic identity for AI agents, linked to human owners
via Alien Network SSO.

When an AI agent has an Alien Agent ID, every git commit it makes is SSH-signed and carries trailers that trace back to the specific agent and the human who authorized it. The provenance chain is fully verifiable: commit → agent key → SSO id_token (with cnf.jkt) → verified AlienID holder.

💻 Watch the setup demo on X

Table of Contents


How It Works

sequenceDiagram
    participant Agent as AI Agent
    participant SSO as Alien SSO
    participant App as Alien App (Human)

    Agent->>SSO: 1. Start OIDC auth, get QR / deep link
    SSO->>App: 2. Human scans QR with Alien App
    App->>SSO: 3. Human approves, callback to SSO
    SSO->>Agent: 4. Exchange tokens, create cryptographic owner binding
    Note over Agent: Alien Agent ID bound → SSH-signed git commits with provenance trailers
Loading
  1. Agent starts OIDC auth, gets a QR code / deep link
  2. Human scans QR with Alien App
  3. Human approves, Alien App calls back to SSO
  4. Agent exchanges tokens, creates cryptographic owner binding

The agent now has an Ed25519 keypair with a signed binding proving a verified human authorized it.


Plugin Layout

Alien Agent ID ships as a Claude Code plugin marketplace with six focused plugins. Each plugin has a narrow responsibility and depends on agent-id-core for the shared library + bootstrap surface:

Plugin Skill What it does
agent-id-core /agent-id-core Bootstrap (init / auth / bind / bootstrap), session lifecycle (refresh, status, setup-owner-session), and universal operations (sign, verify, export-proof). Owns the shared library that every other plugin imports: crypto primitives, the v3 bundle format + universal verifier (verifyBundle), SignatureEngine, OIDC, state I/O.
agent-id-git /agent-id-git SSH-signed git commits with Agent-ID provenance trailers and v3 proof notes. setup, commit, verify. Verify calls into core's universal verifier and adds the SSH-signature + trailer checks on top — auditors and CI runners can verify any commit without a bound identity.
agent-id-vault /agent-id-vault Portable encrypted credential vault for external-service secrets. Single file (vault.enc) with LUKS-style slots — agent-key (HKDF), passphrase (scrypt), mobile (phone), owner-approval (Alien app). Two one-way modes: user (default; no passphrase, app/agent-key unlock) and dev (--dev; passphrase allowed) — a user-mode vault can never gain a passphrase. Typed, domain-scoped credential records, including sealed in-vault-generated wallet keys (solana-keypair, evm-keypair). exec injects credentials into a child process's environment for env-var-auth CLIs/SDKs the proxy can't reach. init, add, generate, show, list, remove, exec, rekey, export, import, migrate.
agent-id-proxy /agent-id-proxy Local credential-injecting HTTP proxy. Agent calls http://<proxy>/<credname>/<upstream-host>/<path>; proxy materializes the credential into the request by type and forwards over real HTTPS. Signs Solana/EVM transactions in-process for wallet credentials — the agent submits unsigned transactions. System CA bundle verifies upstream — no TLS interception, no local CA. Enforces per-credential host allowlist (default-deny). start, status, stop.
agent-id-auth /agent-id-auth RFC 9449 DPoP-signed calls to Alien-aware services. header emits the two-header pair for one request; call is a one-shot signed HTTP request. discover fetches and validates /.well-known/alien-agent-id.json; capabilities renders the manifest as actionable markdown; support probes for the meta-tag support signal.
agent-id-browser /agent-id-browser Universal browser the agent drives, with the logged-in profile sealed in the vault. One-time headed login establishes a session; afterwards the agent drives it headless — fine-grained control (accessibility snapshot + click/type/fill/select/press/navigate/screenshot/eval) plus one-shot read/fetch. For authenticated sites that block API/OAuth/cookie access (e.g. Gmail/Workspace). Bundles patchright (stealth Chrome); the agent never sees a credential. login, open, close, actions, read, fetch, status.

Repository layout:

plugins/
├── agent-id-core/
│   ├── .claude-plugin/plugin.json
│   ├── lib/                    # crypto, bundle, state, errors, oidc,
│   │                           # signature-engine, cli-runtime
│   ├── bin/cli.mjs             # 10 subcommands
│   ├── bin/qrcode.cjs          # zero-dep terminal QR renderer
│   └── skills/agent-id-core/SKILL.md
├── agent-id-git/
│   ├── .claude-plugin/plugin.json
│   ├── bin/cli.mjs             # setup, commit, verify
│   └── skills/agent-id-git/SKILL.md
├── agent-id-vault/
│   ├── .claude-plugin/plugin.json
│   ├── lib/format.mjs          # Portable vault format + slot crypto
│   ├── lib/store.mjs           # Typed credential schema + record CRUD
│   ├── lib/vault.mjs           # Facade: open, init, export, import
│   ├── lib/trusted-input.mjs   # /dev/tty channel for passphrases
│   ├── lib/legacy.mjs          # v4 migration helpers
│   ├── bin/cli.mjs             # init, add, show, list, remove, rekey,
│   │                           # export, import, migrate
│   └── skills/agent-id-vault/SKILL.md
├── agent-id-proxy/
│   ├── lib/proxy.mjs           # Server + URL-rewrite + stub injection
│   ├── lib/rewrite.mjs         # URL-rewrite path: parse + materialize
│   ├── lib/stub.mjs            # Legacy stub-injection helpers
│   ├── lib/totp.mjs            # RFC 6238 TOTP generator
│   ├── bin/cli.mjs             # start, status, stop
│   └── skills/agent-id-proxy/SKILL.md
├── agent-id-auth/
│   ├── .claude-plugin/plugin.json
│   ├── lib/manifest.mjs        # /.well-known parser + validator
│   ├── bin/cli.mjs             # header, call, discover, capabilities, support
│   └── skills/agent-id-auth/SKILL.md
└── agent-id-browser/
    ├── .claude-plugin/plugin.json
    ├── lib/launch.mjs          # hardened patchright launch (sandbox on)
    ├── lib/profile-store.mjs   # tar + AES-256-GCM seal of the profile (DEK in vault)
    ├── lib/session-server.mjs  # persistent session + a11y snapshot/refs + actions
    ├── lib/unlock.mjs          # owner-approval (Alien app) unlock
    ├── lib/session.mjs         # logout detection
    ├── bin/cli.mjs             # login, open/close, actions, read, fetch, status
    ├── package.json            # bundles patchright (stealth Chrome)
    └── skills/agent-id-browser/SKILL.md
.claude-plugin/marketplace.json # lists all six plugins
examples/                       # demo-service.mjs, dev-sso.mjs
tests/                          # unit + integration suites
docs/                           # AGENT-SSO.md, INTEGRATION.md

Every plugin is zero npm dependencies (Node.js built-ins only) — except agent-id-browser, which bundles patchright (a stealth Playwright) to drive a real browser.


Quick Start

1. Add the marketplace

/plugin marketplace add alien-id/agent-id

2. Install the plugins you need

/plugin install agent-id-core@alien-id-agent-id
/plugin install agent-id-git@alien-id-agent-id      # for signed commits
/plugin install agent-id-vault@alien-id-agent-id    # for credential storage
/plugin install agent-id-proxy@alien-id-agent-id    # for credential injection at runtime
/plugin install agent-id-auth@alien-id-agent-id     # for DPoP service calls
/plugin install agent-id-browser@alien-id-agent-id  # for driving a logged-in browser
/reload-plugins

agent-id-core is required by every other plugin. agent-id-proxy depends on agent-id-vault. Install only what you need — auditors who just want to verify commits can install agent-id-core + agent-id-git and skip the rest.

If /reload-plugins does not pick up the new plugins on first run, restarting Claude Code usually helps.

3. Bootstrap your Alien Agent ID

/agent-id-core

Follow the instructions — the agent will generate a keypair, show a QR code, and wait for you to approve in the Alien App. Once done, your Alien Agent ID is created and bound.

4. Configure git signing

/agent-id-git

The plugin writes the SSH key files and prints the public key. Add it to your GitHub account: GitHub → Settings → SSH and GPG keys → New SSH key → Key type: Signing Key. Commits will then show a "Verified" badge.

5. Use it

/agent-id-git stage, commit and push all files in the repo, follow the previous commits naming convention

Other agents

Any agent with shell access can use the plugin CLIs directly. Requirements: Node.js 18+, git 2.34+, and permission to run node plugins/agent-id-<X>/bin/cli.mjs ... commands.


What a Signed Commit Looks Like

✓ Verified  — This commit was signed with the committer's verified signature.

feat: implement auth flow

Agent-ID-JKT: wEf6o2ux8sBAUG4oQYhP284gfpZwUJMTxXDPH5XxthY
Agent-ID-Owner: 00000003010000000000539c741e0df8

Anyone can trace: this codethis agent (JKT) → this human (id_token sub) → verified AlienID holder.

Each commit also attaches a v3 proof bundle as a git note (refs/notes/agent-id) containing the SSO-signed id_token and the agent's public JWK — everything a verifier needs to prove the provenance chain without access to the agent's local state.


Verifying Provenance

node plugins/agent-id-git/bin/cli.mjs verify --commit HEAD

Verification is self-contained: the v3 git-note bundle is { version: 3, id_token, agent_jwk }. Anyone who clones the repo and fetches the notes can verify the chain without access to the agent's machine.

# Fetch proof notes from remote
git fetch origin refs/notes/agent-id:refs/notes/agent-id

# Verify any commit
node plugins/agent-id-git/bin/cli.mjs verify --commit abc123

Verification chain (v3)

flowchart LR
    A[SSH commit signature] --> B[agent_jwk]
    B --> C["id_token cnf.jkt"]
    C --> D[SSO RS256 signature]
    D --> E[Trailer JKT match]
Loading
  1. id_token signature — RS256 verified against Alien SSO's JWKS (iss matches discovery)
  2. cnf.jkt anchor — id_token's RFC 7800 §3.1 confirmation claim binds the SSO-attested owner to a specific Ed25519 key thumbprint
  3. agent_jwk thumbprint — bundle's agent_jwk thumbprint (RFC 7638) must equal cnf.jkt and the Agent-ID-JKT trailer
  4. SSH commit signature — git's native SSH signature must verify against agent_jwk

Steps 1–3 are the universal verification — they live in agent-id-core/lib/bundle.mjs as verifyBundle() and run against the bundle alone, without any git knowledge. Step 4 is the git-specific layer that agent-id-git adds on top. The same universal verifier can be called on any future v3 bundle (signed tool calls, exported proofs, …) without growing a git dependency.

Pre-v3 (legacy Agent-ID-Fingerprint / Agent-ID-Binding) commits are intentionally not supported. Their id_tokens predate the RFC 7800 cnf.jkt binding and cannot anchor the chain; see CHANGELOG.md for the 3.0.0 cutover notes.


Service Authentication

Agents authenticate to Alien-aware services with RFC 9449 DPoP. The agent presents the SSO-issued access_token in the Authorization header and a fresh per-request proof JWT (signed by the agent's Ed25519 key) in the DPoP header.

The one-shot path: let the CLI sign and send the request for you.

node plugins/agent-id-auth/bin/cli.mjs call --url https://service.example.com/api/whoami
node plugins/agent-id-auth/bin/cli.mjs call --url https://service.example.com/api/posts \
  --method POST --body-file ./body.json

The two-header path: emit the headers and drive the HTTP yourself.

node plugins/agent-id-auth/bin/cli.mjs header \
  --url https://service.example.com/api/whoami --method GET --raw
# → Authorization: DPoP <access_token>
# → DPoP: <proof JWT>

Each DPoP proof is single-use and request-bound: a fresh jti, current iat, and the htm/htu/ath claims bind the proof to one specific (method, URL, access_token) tuple. Reusing a proof on a different URL or with a different access token will be rejected.

Owner ↔ agent binding lives entirely in standard claims: the access_token carries sub (owner), aud, iss, and cnf.jkt (the agent key thumbprint, RFC 7800 §3.1). The DPoP proof binds the request to that same key per RFC 9449 §6.1. Services verify with @alien-id/sso-agent-id's verifyDPoPRequest — no custom envelope, no key registration.


Service Discovery

Alien-aware services publish a JSON manifest at https://<host>/.well-known/alien-agent-id.json. Agents fetch and validate it before talking to the service.

node plugins/agent-id-auth/bin/cli.mjs discover --url https://example.com

The CLI enforces an 8 KiB body cap, rejects redirects, requires application/json, and validates against a closed schema (version, auth.header, auth.scheme, api.base, optional api.specUrl, optional service.name/service.url, optional api.operations[] for v2). Every URL in the manifest must share the same authority as the service URL the user gave the agent — see plugins/agent-id-auth/skills/agent-id-auth/SKILL.md for the full trust boundary. Same authority means host[:port] exactly, or a subdomain of it; no public-suffix-list expansion.

Services that publish an OpenAPI / JSON Schema document can declare it via api.specUrl, or can inline a closed-schema operations list via api.operations[] (manifest v2). To render the operations as actionable markdown:

node plugins/agent-id-auth/bin/cli.mjs capabilities --url https://example.com

Replaces ALIEN-SKILL.md. Earlier 2.2.0 docs proposed a Markdown file (ALIEN-SKILL.md) at the service root for the same purpose. That format is removed: free-form Markdown is too permissive a channel for a third-party server to feed an LLM. The well-known JSON manifest is the only supported discovery mechanism.

Optional support signal

Services may also publish a closed-enum HTML meta tag advertising agent-id support:

<meta name="alien-agent-id" content="v1">

The tag's content is a closed enum (v1, future versions) — no URLs, no prose. It exists so agents and crawlers can detect support without probing every host's /.well-known/. The manifest path is fixed; the meta tag never tells the agent where to go, only whether a service claims support. Probe it with:

node plugins/agent-id-auth/bin/cli.mjs support --url https://example.com
# → {"ok": true, "supported": true, "version": "v1"}

Credential Vault

The vault holds external-service credentials (GitHub PATs, OpenAI keys, Stripe secrets, cookies, TOTP seeds, …) in a single encrypted file at ~/.agent-id/vault.enc with a LUKS-style slot construction. The vault pairs with agent-id-proxy so the agent uses credentials by name without ever seeing the value.

Full details + architecture diagram: docs/VAULT-PROXY.md.

# 1. Initialize. Passphrase typed on /dev/tty — never enters the agent transcript.
node plugins/agent-id-vault/bin/cli.mjs init

# 2. Add credentials. Each one is typed and host-scoped (default-deny).
node plugins/agent-id-vault/bin/cli.mjs add --name github-pat --type bearer \
  --domains '*.github.com,api.github.com' --value-file /tmp/tok

node plugins/agent-id-vault/bin/cli.mjs add --name openai-key --type header \
  --header-name X-Api-Key --domains api.openai.com --value-env OPENAI_KEY

# 3. List metadata. Plaintext never appears.
node plugins/agent-id-vault/bin/cli.mjs list

# 4. Remove
node plugins/agent-id-vault/bin/cli.mjs remove --name github-pat

Supported credential types: bearer, basic, header, query, cookie, cookie-jar, totp, oauth2, solana-keypair, evm-keypair. Value-input channels — pick the smallest attack surface: --<field>-file, --<field>-env, piped stdin, raw --<field> arg (visible in ps; avoid). Never paste a secret into chat; transcripts persist.

Blockchain wallets — keys born in the vault

For Solana and EVM (Ethereum, Polygon, Base, …) wallets the vault goes one step further than storing a secret: it creates the private key itself and seals it. The key never crosses a process boundary — generate prints only the public address, show redacts, add refuses the type. The only way to use the key is transaction signing inside the proxy, scoped to the credential's RPC-host allowlist.

# Create wallets — output is the address, nothing else:
node plugins/agent-id-vault/bin/cli.mjs generate --name sol-hot \
  --type solana-keypair --domains api.mainnet-beta.solana.com
node plugins/agent-id-vault/bin/cli.mjs generate --name polygon-hot \
  --type evm-keypair --domains polygon-bor-rpc.publicnode.com

# The agent submits an UNSIGNED transaction through the proxy; the proxy signs:
curl http://localhost:48771/sol-hot/api.mainnet-beta.solana.com/ \
  -d '{"jsonrpc":"2.0","id":1,"method":"sendTransaction",
       "params":["<unsigned tx, base64>",{"encoding":"base64"}]}'

# EVM: eth_sendTransaction is rewritten to a signed eth_sendRawTransaction:
curl http://localhost:48771/polygon-hot/polygon-bor-rpc.publicnode.com/ \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_sendTransaction","params":[{
       "to":"0x…","value":"0x38d7ea4c68000","chainId":137,"nonce":"0x0",
       "gas":21000,"maxFeePerGas":120000000000,"maxPriorityFeePerGas":30000000000}]}'

Solana signing handles legacy + v0 messages and preserves co-signatures (partial signing — e.g. an x402 facilitator fee-payer). EVM signing produces EIP-1559 transactions with RFC 6979 deterministic ECDSA. Both paths are zero-dependency and verified end-to-end on Solana and Polygon mainnet — the agent-side flow lives in examples/solana-transfer-via-proxy.mjs.

Portability

The vault file is encrypted at rest — copy it to a second machine and import:

node plugins/agent-id-vault/bin/cli.mjs export --out vault.enc
# (copy vault.enc to machine B)
node plugins/agent-id-vault/bin/cli.mjs import --in vault.enc      # asks for passphrase
node plugins/agent-id-vault/bin/cli.mjs rekey add-agent-key        # bind B's agent for fast unlock

Using a credential at runtime — the proxy

Once a credential is in the vault, the agent uses it through agent-id-proxy. The agent calls a local URL that names the credential and the upstream host; the proxy materializes the credential and forwards over real HTTPS:

# Start the proxy (default port 48771; tries agent-key unlock first, falls back to passphrase)
node plugins/agent-id-proxy/bin/cli.mjs start

# Agent calls a local URL — credname picks the credential, host validated by its allowlist
curl http://localhost:48771/github-pat/api.github.com/user
# → upstream sees `Authorization: Bearer ghp_xxx...`, agent transcript never saw the value

After --idle-timeout (default 12 h) the proxy zeroes the master key in memory; restart to re-unlock. See docs/VAULT-PROXY.md for the full request flow, threat model, and per-type materialization rules.

Migration from v4 vaults

node plugins/agent-id-vault/bin/cli.mjs migrate --passphrase-file /tmp/pass

One-shot: the old ~/.agent-id/vault/ directory is renamed to vault.bak/. Migrated records get the placeholder allowlist ["UNCONFIGURED.invalid"] — the proxy refuses to inject them until you attach real domains via agent-id-vault add.


Session Refresh

After bootstrap, the agent receives SSO tokens including a refresh_token. The refresh command renews the access_token without requiring human interaction.

# Explicit refresh
node plugins/agent-id-core/bin/cli.mjs refresh

# Transparent — every per-plugin CLI internally calls SignatureEngine.ensureValidSession()
# before signing, so most consumers do not need to refresh explicitly.
node plugins/agent-id-auth/bin/cli.mjs header --url https://example.com/api/x

If the human revokes the agent's authorization via the Alien App, refresh surfaces auth-revoked and the agent will need to re-bootstrap.


Prerequisites

  • Node.js 18+ — uses built-in crypto, fetch, fs (zero npm dependencies)
  • git 2.34+ — SSH commit signing support (only needed for agent-id-git)
  • Alien App with a verified AlienID
  • Provider address — registered in the Developer Portal (optional)

Agent State

All state is stored in ~/.agent-id/ (configurable via --state-dir or AGENT_ID_STATE_DIR). The layout is the same regardless of which plugins you have installed — every plugin reads and writes through agent-id-core/lib/state.mjs.

~/.agent-id/
├── keys/main.json           # Ed25519 keypair (mode 0600)
├── ssh/
│   ├── agent-id             # SSH private key (mode 0600)
│   ├── agent-id.pub         # SSH public key
│   └── allowed_signers      # For git signature verification
├── vault.enc                # Portable encrypted vault (mode 0600)
├── vault.bak/               # Legacy v4 per-credential dir, post-migration
├── proxy.json               # Running-proxy state (pid, port, idleTimeoutMs)
├── proxy.log                # JSONL access log — names only, never values or bodies
├── owner-session.json       # SSO tokens — id_token IS the chain attestation (mode 0600)
├── nonces.json              # Per-agent nonce tracking
├── sequence.json            # Operation sequence counter
└── audit/operations.jsonl   # Hash-chained signed operation log

CLI Reference

Each plugin has its own CLI under plugins/agent-id-<NAME>/bin/cli.mjs. The common --state-dir <path> flag is accepted by every subcommand and defaults to AGENT_ID_STATE_DIR then ~/.agent-id.

agent-id-core — bootstrap + lifecycle + universal operations

Command Purpose
bootstrap One-shot setup: init + auth + bind. Blocks ≤5 min while waiting for Alien App approval.
init Generate the Ed25519 agent keypair.
auth --provider-address <addr> Start OIDC authorization (emits deep-link + QR).
bind [--timeout-sec N] Poll for approval, exchange tokens, verify cnf.jkt, persist owner-session.json.
setup-owner-session Force a fresh OAuth flow against the existing keypair (used to migrate pre-v3 bindings).
status Check whether an identity exists and is bound.
refresh Refresh the SSO access_token + id_token (DPoP-bound).
sign --type T --action A --payload JSON Sign an arbitrary operation into the audit trail.
verify Chain-integrity check on the local audit trail.
export-proof Emit the owner session + complete audit trail as JSON.

agent-id-git — SSH-signed commits with provenance

Command Purpose
setup Write the agent keypair into SSH-format files; print the public key to add to your git host.
commit --message <M> [--push] [--remote R] [--allow-empty] Signed commit with Agent-ID-JKT / Agent-ID-Owner trailers + v3 proof note + audit-log entry.
verify [--commit HASH] [--sso-url URL] Verify a commit's v3 attestation chain (universal verifyBundle + trailer + SSH-sig).

agent-id-vault — portable encrypted credential vault

See docs/VAULT-PROXY.md for the format + threat model. Full per-type flag reference is in the vault skill.

Command Purpose
init [--passphrase-file F | --passphrase-env V] [--no-agent-key] Create the portable vault. Slot 0 = passphrase, slot 1 = agent-key (auto-added if a main key exists).
add --name N --type T --domains H[,H…] [type-specific value flags] Add or replace a credential. Types: bearer, basic, header, query, cookie, cookie-jar, totp. Value-input flags: --<field>-file, --<field>-env, stdin, or raw --<field>.
show --name N Retrieve plaintext. Prefer the proxy for runtime use — show is for manual export.
list List metadata + slots (no plaintext).
remove --name N Delete a record.
exec --env VAR=cred.field [--env …] -- <cmd> Run <cmd> with credential fields injected into its environment (for env-var-auth CLIs/SDKs the proxy can't help with). Secret never touches disk, argv, or stdout; inherited stdio keeps interactive TTYs.
rekey add-passphrase [--new-passphrase-file F] Append a passphrase slot.
rekey add-agent-key Append an agent-key slot for fast unattended unlock on this machine.
rekey remove-slot --id N Remove a slot (refuses to remove the last one).
export --out PATH Copy the encrypted vault file.
import --in PATH [--overwrite] Install an encrypted vault file.
migrate [--passphrase-file F] [--default-domains H[,H…]] Convert legacy ~/.agent-id/vault/*.jsonvault.enc.

agent-id-proxy — local credential-injecting HTTP proxy

See docs/VAULT-PROXY.md for the URL-rewrite request flow and per-type materialization table.

Command Purpose
start [--port N] [--host H] [--passphrase-file F | --passphrase-env V] [--no-agent-key] [--idle-timeout 12h|30m|never] Unlock the vault and listen on localhost. Default port 48771, default idle-lock 12h. Foreground (Ctrl-C exits).
status JSON: running, pid, port, uptime, configured idleTimeout.
stop SIGTERM the running proxy.

Use it by calling http://<proxy>/<credname>/<upstream-host>/<path>. Legacy HTTP_PROXY + AgentVault <name> stub mode also works for plain-HTTP upstream.

agent-id-auth — DPoP-signed service calls

Command Purpose
header --url <U> [--method M] [--raw] Emit Authorization + DPoP headers for one request.
call --url <U> [--method M] [--body S | --body-file F] [--content-type T] One-shot signed HTTP request (preferred).
discover --url <U> Fetch + validate /.well-known/alien-agent-id.json.
capabilities --url <U> Render a manifest's api.operations[] as actionable markdown.
support --url <U> Probe a page for the <meta name="alien-agent-id"> support signal.

Run any plugin's CLI with --help for the full flag list.


Security

  • Private keys stored with 0600 permissions; state directories created with 0700.
  • PKCE (S256) prevents authorization code interception (RFC 7636).
  • SSO id_token (RS256) commits the agent key thumbprint via cnf.jkt — the human ↔ agent binding lives inside the SSO-signed claim, not a separate self-signed envelope (RFC 7800 §3.1).
  • DPoP proof-of-possession (RFC 9449) — every service request carries a fresh Ed25519-signed proof bound to the URL, method, and cnf.jkt; a leaked access_token is useless without the matching private key.
  • Hash-chained audit log — any tampering breaks the chain. agent-id-core verify walks it end-to-end.
  • Vault encryption — AES-256-GCM with HKDF-SHA256-derived key from agent's private key. Credentials are only readable on the same machine as the bound agent.
  • JWT alg: none rejected — unsigned tokens are refused at parse level.
  • Subject validation — token refresh verifies the subject claim still matches the bound owner (SubjectMismatchError on mismatch).
  • Refresh tokens are sticky — bound to the original cnf.jkt, no rotation needed.
  • Manifest validation — third-party manifests are parsed against a closed schema; same-authority guard refuses any URL that points outside the service's host or subdomain.
  • owner-session.json contains tokens — never commit or share it.

Additional Resources

About

Cryptographic identity for AI agents

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors