Getting started
The fastest path from "I just heard about EUDIW" to a working verifier that returns parsed claims is about five minutes. Here it is.
Install
pnpm add @gramota/verifier @gramota/trust
# or: npm install @gramota/verifier @gramota/trust
# or: yarn add @gramota/verifier @gramota/trust
You need Node.js 20+. The packages are pure ESM and ship signed provenance attestations.
Verify a presentation
import { Verifier } from "@gramota/verifier";
import { StaticTrustResolver } from "@gramota/trust";
const verifier = new Verifier({
audience: "https://my-bank.com",
trust: new StaticTrustResolver([issuerJwk]),
});
const result = await verifier.presentations.verify(presentationToken, {
nonce: "n-12345",
});
if (result.ok) {
console.log(result.claims); // { given_name: "Greta", ... }
console.log(result.metadata); // { issuer, audience, issuedAt, ... }
} else {
console.log(result.failedCheck); // e.g. "kb-jwt.audience"
console.log(result.reason);
}
That's it. Twelve named security checks run in order — parse, trust,
issuer signature, hash binding, KB-JWT presence/cnf/sig/aud/nonce/time/transcript,
status. If anything fails, result.failedCheck tells you which one.
The
Verifierexposes Stripe-shaped resource namespaces:verifier.presentations.verify,verifier.responses.verify,verifier.requests.create. The flat methods (verifier.verify,.response,.request) still work in 0.x and are marked@deprecated; they'll be removed in 1.0.
Or use the top-level facade
If you want one import + one config object instead of wiring each package separately:
pnpm add @gramota/sdk @gramota/trust
import { Gramota } from "@gramota/sdk";
import { StaticTrustResolver } from "@gramota/trust";
const gramota = new Gramota({
verifier: {
audience: "https://my-bank.com",
trust: new StaticTrustResolver([issuerJwk]),
},
});
await gramota.verifier.presentations.verify(token, { nonce });
const code = gramota.qr.fromAuthorizationRequest(req); // QR for the wallet
The facade is additive — pick whichever style fits.
What's in the box
The high-level packages:
@gramota/sdk— top-level Stripe-shaped facade. One import, one config.@gramota/verifier— relying-party verifier (banks, telcos, age-gated commerce).@gramota/issuer— issuer for SD-JWT-VC, including batch issuance for one-time-use credential pools.@gramota/holder— headless wallet (when you need one programmatically).@gramota/qr— QR-code rendering for the deep links you hand to wallets.
And the building blocks underneath, in case you need finer control:
@gramota/oid4vp— request + response wire format, signed JAR, x509_san_dns cert helpers.@gramota/oid4vci— pre-auth + auth-code, PAR, DPoP both sides.@gramota/sd-jwt— SD-JWT-VC parser, hash binding, KB-JWT.@gramota/jose— JWS sign + verify, x5c chain validation, pluggable Signer Strategy.@gramota/trust—TrustResolver: Static, JwksUrl, SdJwtVcIssuer, custom.@gramota/status-list— IETF Token Status List + StatusResolver Strategy.@gramota/core— foundation:Fetchertransport interface,GramotaErrorbase class. Re-exported by every other package.
Where to next
- SD-JWT-VC explained — the credential format the EU is settling on, demystified for web devs.
- The GitHub repo — clone it,
run
pnpm demo:self-loop, watch a credential flow through Issuer → Holder → Verifier in 1.5 seconds. - The
@gramota/verifierpackage README — full API surface, error codes, configuration knobs.