link-cli / agent-identity
AGENTS.md896 starsChanged 30 days agoMITView on GitHub
Use @stripe/agent-identity to verify Link bearer Agent Attestation Tokens (AATs) and SD-JWT-VC identity presentations. Read README.md for the API, integration examples, and limitations. The SDK checks credentials. It does not sign or verify HTTP requests, resolve agent key directories, or process Web Bot Auth (WBA) headers. Do not add HTTP Message Signature requirements, raw body parsing, or Content-Digest validation to an integration with this SDK. A bearer AAT proves issuance by Link. It does not identify the presenter or bind…
- Installs packages
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,439 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository9 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- create-payment-credentialSkill
- financial-insightsSkill
- check-link-walletSkill
- complete-link-purchaseSkill
- create-payment-credentialSkill
- financial-insightsSkill
- use-link-identitySkill
The file
We split this AGENTS.md into the rules it gives an agent
5 rules. About 1 is common, 0 are distinctive, and 4 are very specific to this project.
≈1
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 3
Use @stripe/agent-identity to verify Link bearer Agent Attestation Tokens (AATs) and SD-JWT-VC identity presentations.
- Very specific: line 16
Create one LinkVerifier per process.
- Very specific: line 19
Use isRejection to distinguish credential rejection (usually 401) from issuer_unavailable (usually 503).
- Common: line 35
Keep normal framework body parsing and size limits.
- Very specific: line 45
Use the shipped LinkFixture and CredentialFixture.
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Integrating Agent Identity
Use @stripe/agent-identity to verify Link bearer Agent Attestation Tokens (AATs) and SD-JWT-VC identity presentations. Read README.md for the API, integration examples, and limitations.
Scope
The SDK checks credentials. It does not sign or verify HTTP requests, resolve agent key directories, or process Web Bot Auth (WBA) headers. Do not add HTTP Message Signature requirements, raw body parsing, or Content-Digest validation to an integration with this SDK.
A bearer AAT proves issuance by Link. It does not identify the presenter or bind the token to your service or a particular request. Identity presentations require a holder-signed Key Binding JWT, audience, expiry, required-claims checks, and equality with the caller-provided expected nonce. These checks bind disclosures to the intended audience and expected interaction nonce.
Integration
For agents responding through Link Agent Wallet, require v0.27.0 or later in your setup instructions. Point them to wallet setup and the identity skill. The verifier validates proofs, not client versions.
- Install with
npm install @stripe/agent-identity. The package supports Node 22+, ESM and CommonJS. It uses Node built-ins andjose; runtimes without the required Node APIs are unsupported. For local SDK development, follow build and install from source, which requires Node 24+ and pnpm. - Create one
LinkVerifierper process. Setoriginfrom the service's configuration; it is the audience for identity claims. Use an explicit HTTP origin such ashttp://localhost:3000for local servers; bare authorities default to HTTPS. - Extract the
AuthorizationorIdentity-Presentationfield value and pass the string directly. Reject duplicate credential fields if your framework would otherwise discard them. In Node or Express, usereq.headersDistinct; the SDK cannot recover fields your framework dropped. - Inspect
result.valid, or use theOrThrowvariants and handleVerificationError. The result object itself is truthy even when verification fails. - Use
isRejectionto distinguish credential rejection (usually 401) fromissuer_unavailable(usually 503). Handle errors from challenge builders and optionalwarm()separately; they throw on failure. - Request identity claims only when the application needs them. Associate the challenge nonce with the application interaction. Pass that nonce and explicit
requiredClaimswhen verifying the presentation. - Apply the application's authorization and session policy after credential verification. Do not use
tokenKeyIdas a user or agent identity: it identifies an issuer signing key shared by many tokens.
import { LinkVerifier } from '@stripe/agent-identity';
const verifier = new LinkVerifier({ origin: 'https://shop.example' });
const attestation = await verifier.verifyAttestation(request.headers.get('Authorization'));
const claims = await verifier.verifyClaims(request.headers.get('Identity-Presentation'), {
nonce: nonceFromSession,
requiredClaims: ['email'],
});Keep normal framework body parsing and size limits. Verification does not consume or authenticate the request body. Serve credential-bearing endpoints over HTTPS; the SDK receives credential strings and cannot check transport security.
Claims and state
claimsChallenge() returns a nonce and advertised expiresAt value without storing either. The application associates the nonce with an interaction, enforces expiration, and atomically consumes or completes the interaction when its policy requires single use. verifyClaims() only checks that the holder-signed nonce equals the expected nonce supplied by the caller. Verification does not mutate application state, and the same valid presentation can verify again when passed the same expected nonce.
The holderKeyThumbprint returned by claims verification identifies the key in the credential's cnf.jwk. It does not authenticate the HTTP request or tie a separate anonymous AAT to that holder.
Tests
Use the shipped LinkFixture and CredentialFixture. They use real cryptography and expose controls for invalid signatures, wrong audiences, expired credentials, and unsupported challenge digests.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { LinkVerifier } from '@stripe/agent-identity';
import { LinkFixture } from '@stripe/agent-identity/testing';
test('verifies Link tokens without a request signature', async () => {
const link = await LinkFixture.create();
const verifier = new LinkVerifier({ origin: 'shop.example', fetchImpl: link.fetchImpl() });
const token = await link.mint();
assert.equal((await verifier.verifyAttestation(token.authorization)).valid, true);
const forged = await link.mint({ corruptAuthenticator: true });
assert.equal((await verifier.verifyAttestation(forged.authorization)).valid, false);
});For credential tests, use combineFetch to serve Link metadata and credential JWKS and call clearJwksCache() between fixtures using different signing keys at the same issuer URL. After installing workspace dependencies, run pnpm build, pnpm typecheck, and pnpm test from packages/agent-identity. Follow the development instructions for the HTTP example, package installation, and documentation checks that also run in CI.
After changing issuance formats or wallet commands, also run node --test test/wallet.test.mjs from this package after building the wallet client SDK and CLI. Follow the development instructions. This separate CI check uses the built wallet, a local issuer, and temporary storage to test issuance and presentation against the verifier and HTTP example.
Limits to preserve in documentation
- AAT single use is not enforced. A bearer token can be replayed wherever it is trusted. Its lifetime is tied to issuer key acceptance, not challenge
max-age. - Key-bound AATs are unsupported and must fail with
challenge_mismatch; this SDK does not establish possession of an agent signing key. - Credential verification does not authorize an HTTP operation or authenticate its method, URL, or body. The application owns authorization and replay policy.
- Credential signing keys are cached process-wide for one hour;
issuerOptions.maxKeyAgeSecondscontrols only token keys.
AAT and identity-presentation double-spend detection and replay prevention belong to adopters and must be implemented in their own stack if needed. The SDK provides no spent-token or nonce store and no replay enforcement.
Package maintenance
Keep the verifier independent of the wallet client: no runtime dependency on @stripe/link-sdk or @stripe/link-cli. Preserve ESM and CommonJS exports, the /testing entry point, Node 22 support for consumers, and the library declaration typecheck. Use Node built-ins and jose for standard byte and cryptography operations; retain identity-specific validation. Keep jose imports dynamic so the CommonJS build works on Node 22.0. Workspace development uses Node 24+. Examples use example/, matching the other integrations. Keep guidance in READMEs and examples; there is no documentation website. Preserve wire identifiers and published issuer paths when updating product names.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

