@gramota/verifier

Relying-party verifier — 12 named security checks, IETF SD-JWT-VC + KB-JWT + OID4VP-compliant.

Install: pnpm add @gramota/verifier

Source: github.com/gramota-org/gramota/tree/main/packages/verifier

Classes

VerifierError

Defined in: @gramota/verifier/dist/types.d.ts:167

Extends

  • GramotaError

Constructors

Constructor
new VerifierError(message: string, result: FailureResult): VerifierError;

Defined in: @gramota/verifier/dist/types.d.ts:173

Parameters
message

string

result

FailureResult

The full failure record — stable for logging.

Returns

VerifierError

Overrides
GramotaError.constructor

Properties

cause?
readonly optional cause?: unknown;

Defined in: .pnpm/@gramota+core@0.2.1/node_modules/@gramota/core/dist/error.d.ts:44

Optional original error that caused this one. Always set when the Gramota package is wrapping a thrown exception from a dependency (Web Crypto, JOSE, fetch). Survives JSON.stringify(err) only via the cause property — Node 16.9+ logs it natively.

Inherited from
GramotaError.cause
result
readonly result: FailureResult;

Defined in: @gramota/verifier/dist/types.d.ts:169

The full failure record — stable for logging.

code
readonly code: SecurityCheckName;

Defined in: @gramota/verifier/dist/types.d.ts:172

Equal to result.failedCheck — stable identifier for log filters, alerts, and dashboards. Same shape as the codes used by other packages.

Overrides
GramotaError.code
name
name: string;

Defined in: .pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es5.d.ts:1076

Inherited from
GramotaError.name
message
message: string;

Defined in: .pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es5.d.ts:1077

Inherited from
GramotaError.message
stack?
optional stack?: string;

Defined in: .pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es5.d.ts:1078

Inherited from
GramotaError.stack

Verifier

Defined in: @gramota/verifier/dist/verifier.d.ts:3

Constructors

Constructor
new Verifier(config: VerifierConfig): Verifier;

Defined in: @gramota/verifier/dist/verifier.d.ts:11

Parameters
config

VerifierConfig

Returns

Verifier

Properties

presentations
readonly presentations: {
  verify: Promise<VerifyResult<TClaims>>;
};

Defined in: @gramota/verifier/dist/verifier.d.ts:13

Verify a presentation token. Stripe-shaped surface.

verify()
verify<TClaims>(presentationToken: string, options: VerifyOptions<TClaims>): Promise<VerifyResult<TClaims>>;
Type Parameters
TClaims

TClaims = Record<string, unknown>

Parameters
presentationToken

string

options

VerifyOptions<TClaims>

Returns

Promise<VerifyResult<TClaims>>

responses
readonly responses: {
  verify: Promise<VerifyResponseResult<TClaims>>;
};

Defined in: @gramota/verifier/dist/verifier.d.ts:17

Verify an OID4VP authorization response body. Stripe-shaped surface.

verify()
verify<TClaims>(rawBody: string | URLSearchParams | Record<string, string>, options: VerifyResponseOptions<TClaims>): Promise<VerifyResponseResult<TClaims>>;
Type Parameters
TClaims

TClaims = Record<string, unknown>

Parameters
rawBody

string | URLSearchParams | Record<string, string>

options

VerifyResponseOptions<TClaims>

Returns

Promise<VerifyResponseResult<TClaims>>

requests
readonly requests: {
  create: PresentationRequest;
};

Defined in: @gramota/verifier/dist/verifier.d.ts:21

Build a signed presentation request for the wallet. Stripe-shaped surface.

create()
create(options: PresentationRequestOptions): PresentationRequest;
Parameters
options

PresentationRequestOptions

Returns

PresentationRequest

Interfaces

VerifierConfig

Defined in: @gramota/verifier/dist/types.d.ts:6

Configuration for a Verifier instance.

Properties

audience
audience: string;

Defined in: @gramota/verifier/dist/types.d.ts:10

The verifier's identifier. The KB-JWT's aud claim MUST equal this (or any of additionalAudiences). Cross-verifier replay protection — pick a stable, app-specific URL.

additionalAudiences?
optional additionalAudiences?: readonly string[];

Defined in: @gramota/verifier/dist/types.d.ts:16

Additional accepted aud values. Useful when wallets in the wild disagree about what the KB-JWT audience should be. The OID4VP x509_san_dns: client_id is a common alternate form some wallets (the EU reference wallet's eudi-app-android-wallet-ui) put in aud instead of the verifier audience URL.

issuerKey?
optional issuerKey?: JsonWebKey;

Defined in: @gramota/verifier/dist/types.d.ts:19

Exactly one of issuerKey (shorthand) OR trust (full resolver) is required.

trust?
optional trust?: TrustResolver;

Defined in: @gramota/verifier/dist/types.d.ts:23

Pluggable trust resolution. Use StaticTrustResolver for hard-coded keys, JwksUrlTrustResolver for runtime JWKS fetching, or any custom implementation of the TrustResolver interface.

statusResolver?
optional statusResolver?: StatusResolver;

Defined in: @gramota/verifier/dist/types.d.ts:34

Pluggable revocation/suspension resolution (Strategy pattern).

When set, the verifier runs a 10th security check ("status.check") after all crypto checks pass. Default: omitted — no status check.

Use StatusListResolver for IETF Token Status List (the typical EU choice). Custom resolvers (CRL, OCSP, EU Trusted Issuers Registry, deny-lists) implement the StatusResolver interface and plug in here.

algorithms?
optional algorithms?: readonly SupportedAlg[];

Defined in: @gramota/verifier/dist/types.d.ts:38

JWS algorithm allowlist for both issuer and KB-JWT signatures. Default: every IETF asymmetric algorithm we support. alg=none is never permitted, regardless of this list.

maxKbJwtAgeSeconds?
optional maxKbJwtAgeSeconds?: number;

Defined in: @gramota/verifier/dist/types.d.ts:40

Maximum acceptable age of the KB-JWT, in seconds. Default 60.

maxClockSkewSeconds?
optional maxClockSkewSeconds?: number;

Defined in: @gramota/verifier/dist/types.d.ts:43

Maximum acceptable clock skew (KB-JWT iat in the future), in seconds. Default 30.


RequireInput

Defined in: @gramota/verifier/dist/types.d.ts:46

Input passed to VerifyOptions.require predicates.

Type Parameters

TClaims

TClaims = Record<string, unknown>

Properties

claims
readonly claims: TClaims;

Defined in: @gramota/verifier/dist/types.d.ts:48

The disclosed claims — same shape as result.claims on success.

metadata
readonly metadata: VerificationMetadata;

Defined in: @gramota/verifier/dist/types.d.ts:50

Protocol metadata — same shape as result.metadata on success.


RequireResult

Defined in: @gramota/verifier/dist/types.d.ts:57

Return shape for VerifyOptions.require when the caller wants to attach a human-readable reason. Plain boolean is also accepted for the common case.

Properties

passed
readonly passed: boolean;

Defined in: @gramota/verifier/dist/types.d.ts:58

reason?
readonly optional reason?: string;

Defined in: @gramota/verifier/dist/types.d.ts:61

Shown in result.reason and the audit trail when passed: false. Default: "require predicate returned false".


VerifyOptions

Defined in: @gramota/verifier/dist/types.d.ts:64

Per-call options for verifier.verify(...).

Type Parameters

TClaims

TClaims = Record<string, unknown>

Properties

nonce
nonce: string;

Defined in: @gramota/verifier/dist/types.d.ts:67

The challenge the verifier sent to the wallet. The KB-JWT's nonce claim MUST equal this. Within-verifier replay protection.

now?
optional now?: () => number;

Defined in: @gramota/verifier/dist/types.d.ts:70

Override "now" — used for tests and time-frozen environments. Returns Unix seconds. Default: Math.floor(Date.now() / 1000).

Returns

number

requireStatus?
optional requireStatus?: boolean;

Defined in: @gramota/verifier/dist/types.d.ts:82

Status-check policy for THIS verification.

  • When false/omitted, the configured statusResolver (if any) is still consulted; "skipped" is acceptable.
  • When true, a credential with no resolvable status fails the "status.check" gate. Useful for high-assurance flows where non-revocable credentials are unacceptable.

Has no effect when no statusResolver is configured on the Verifier.

require?
optional require?: (input: RequireInput<TClaims>) => 
  | boolean
  | RequireResult
| Promise<boolean | RequireResult>;

Defined in: @gramota/verifier/dist/types.d.ts:109

Application-level predicate. Runs AFTER all crypto + status checks pass; receives the disclosed claims + protocol metadata; returns a boolean (or { passed, reason } for a custom failure reason).

If the predicate returns false (or { passed: false }), the verification fails with failedCheck: "require.predicate" and the predicate's reason (or a default) becomes result.reason. The require.predicate entry is appended to result.checks either way, so audit dashboards see the same shape as for any other check.

If the predicate throws, the throw propagates — the verifier does NOT silently treat exceptions as "passed: false". This is so caller bugs surface as crashes during dev, not as accepted presentations in production.

Parameters
input

RequireInput<TClaims>

Returns

| boolean | RequireResult | Promise<boolean | RequireResult>

Example
await verifier.verify(token, {
  nonce,
  require: ({ claims }) =>
    claims.age_over_18 === true &&
    EU_COUNTRIES.has(claims.nationality as string),
});

SecurityCheck

Defined in: @gramota/verifier/dist/types.d.ts:114

A single security check, recorded for observability. Every check is present in the result regardless of pass/fail, so customers can build audit dashboards.

Properties

name
name: SecurityCheckName;

Defined in: @gramota/verifier/dist/types.d.ts:116

Stable identifier — useful for logs and dashboards.

passed
passed: boolean;

Defined in: @gramota/verifier/dist/types.d.ts:117

message?
optional message?: string;

Defined in: @gramota/verifier/dist/types.d.ts:119

Human-readable detail when the check fails.


VerificationMetadata

Defined in: @gramota/verifier/dist/types.d.ts:129

Protocol metadata extracted alongside the user-facing claims.

Properties

issuer
issuer: string;

Defined in: @gramota/verifier/dist/types.d.ts:130

audience
audience: string;

Defined in: @gramota/verifier/dist/types.d.ts:131

issuedAt
issuedAt: number;

Defined in: @gramota/verifier/dist/types.d.ts:132

expiresAt
expiresAt: number;

Defined in: @gramota/verifier/dist/types.d.ts:133

holderKey
holderKey: Readonly<Record<string, unknown>>;

Defined in: @gramota/verifier/dist/types.d.ts:137

The holder's bound public JWK from cnf.jwk in the parent SD-JWT. After verification this is guaranteed to be a well-formed JWK that successfully verified the KB-JWT signature.


SuccessResult

Defined in: @gramota/verifier/dist/types.d.ts:140

Type Parameters

TClaims

TClaims = Record<string, unknown>

Properties

ok
ok: true;

Defined in: @gramota/verifier/dist/types.d.ts:141

claims
claims: TClaims;

Defined in: @gramota/verifier/dist/types.d.ts:144

The selectively-disclosed user claims with _sd / _sd_alg / cnf stripped — this is what the application actually consumes.

metadata
metadata: VerificationMetadata;

Defined in: @gramota/verifier/dist/types.d.ts:146

Protocol-level metadata that's not part of the user claims.

checks
checks: readonly SecurityCheck[];

Defined in: @gramota/verifier/dist/types.d.ts:148

Every check we ran, all passed. Useful for audit trails.

status?
optional status?: CredentialStatusResult | "skipped";

Defined in: @gramota/verifier/dist/types.d.ts:152

When options.status was supplied, the resolved status (or "skipped" if the credential carried no status reference). Absent when status checking wasn't requested.

Methods

unwrap()
unwrap(): TClaims;

Defined in: @gramota/verifier/dist/types.d.ts:154

Returns claims; never throws on success.

Returns

TClaims


FailureResult

Defined in: @gramota/verifier/dist/types.d.ts:156

Properties

ok
ok: false;

Defined in: @gramota/verifier/dist/types.d.ts:157

reason
reason: string;

Defined in: @gramota/verifier/dist/types.d.ts:159

Human-readable reason — surfaces the message from the failed check.

failedCheck
failedCheck: SecurityCheckName;

Defined in: @gramota/verifier/dist/types.d.ts:161

Stable identifier of the first check that failed.

checks
checks: readonly SecurityCheck[];

Defined in: @gramota/verifier/dist/types.d.ts:163

Every check up to and including the one that failed.

Methods

unwrap()
unwrap(): never;

Defined in: @gramota/verifier/dist/types.d.ts:165

Throws VerifierError carrying this result.

Returns

never


PresentationRequestOptions

Defined in: @gramota/verifier/dist/verifier.d.ts:56

Options for verifier.request().

Properties

baseUrl
baseUrl: string;

Defined in: @gramota/verifier/dist/verifier.d.ts:58

Base URL or scheme: openid4vp://authorize, https://wallet.example.com/...

nonce
nonce: string;

Defined in: @gramota/verifier/dist/verifier.d.ts:60

OID4VP nonce.

state?
optional state?: string;

Defined in: @gramota/verifier/dist/verifier.d.ts:62

Optional opaque CSRF state echoed back unchanged in the response.

responseUri?
optional responseUri?: string;

Defined in: @gramota/verifier/dist/verifier.d.ts:64

direct_post callback URL (required when response_mode=direct_post).

presentationDefinition?
optional presentationDefinition?: Readonly<Record<string, unknown>>;

Defined in: @gramota/verifier/dist/verifier.d.ts:66

Inline DIF Presentation Definition.

presentationDefinitionUri?
optional presentationDefinitionUri?: string;

Defined in: @gramota/verifier/dist/verifier.d.ts:68

Or a URL the wallet can fetch the PD from. Mutually exclusive with above.

responseMode?
optional responseMode?: "direct_post" | "direct_post.jwt" | "fragment" | "query";

Defined in: @gramota/verifier/dist/verifier.d.ts:71

Override response_mode (default: direct_post when responseUri is set, otherwise undefined).

clientIdScheme?
optional clientIdScheme?: string;

Defined in: @gramota/verifier/dist/verifier.d.ts:73

client_id_scheme (default: redirect_uri).

clientId?
optional clientId?: string;

Defined in: @gramota/verifier/dist/verifier.d.ts:75

Override the client_id (defaults to the verifier's audience).


PresentationRequest

Defined in: @gramota/verifier/dist/verifier.d.ts:78

Result of verifier.request().

Properties

url
url: string;

Defined in: @gramota/verifier/dist/verifier.d.ts:80

The full URL to share with the wallet (QR / deep link).

request
request: AuthorizationRequest;

Defined in: @gramota/verifier/dist/verifier.d.ts:82

The structured AuthorizationRequest, useful for storage and logging.

nonce
nonce: string;

Defined in: @gramota/verifier/dist/verifier.d.ts:84

Echoes the nonce so callers can persist it for later verification.

state
state: string;

Defined in: @gramota/verifier/dist/verifier.d.ts:86

Echoes the state if one was supplied.


VerifyResponseOptions

Defined in: @gramota/verifier/dist/verifier.d.ts:89

Options for verifier.response().

Type Parameters

TClaims

TClaims = Record<string, unknown>

Properties

expectedNonce
expectedNonce: string;

Defined in: @gramota/verifier/dist/verifier.d.ts:91

Required — the nonce used in the original request.

expectedState?
optional expectedState?: string;

Defined in: @gramota/verifier/dist/verifier.d.ts:93

Optional — when supplied, response.state MUST equal this.

now?
optional now?: () => number;

Defined in: @gramota/verifier/dist/verifier.d.ts:95

Override "now" — for tests.

Returns

number

requireStatus?
optional requireStatus?: boolean;

Defined in: @gramota/verifier/dist/verifier.d.ts:99

Forwarded to verify() — fail when credential has no resolvable status. Has effect only when the Verifier was constructed with a statusResolver.

require?
optional require?: (input: RequireInput<TClaims>) => 
  | boolean
  | RequireResult
| Promise<boolean | RequireResult>;

Defined in: @gramota/verifier/dist/verifier.d.ts:102

Forwarded to verify() — application-level predicate that runs after all crypto + status checks pass. See VerifyOptions.require.

Parameters
input

RequireInput<TClaims>

Returns

| boolean | RequireResult | Promise<boolean | RequireResult>

Type Aliases

SecurityCheckName

type SecurityCheckName = 
  | "structure.parse"
  | "trust.resolution"
  | "issuer.signature"
  | "hash-binding.disclosures"
  | "kb-jwt.present"
  | "kb-jwt.cnf-binding"
  | "kb-jwt.signature"
  | "kb-jwt.audience"
  | "kb-jwt.nonce"
  | "kb-jwt.time"
  | "kb-jwt.transcript"
  | "status.check"
  | "require.predicate";

Defined in: @gramota/verifier/dist/types.d.ts:122

Stable identifiers for the security checks we run, in execution order.


VerifyResult

type VerifyResult<TClaims> = 
  | SuccessResult<TClaims>
  | FailureResult;

Defined in: @gramota/verifier/dist/types.d.ts:139

Type Parameters

TClaims

TClaims = Record<string, unknown>


VerifyResponseResult

type VerifyResponseResult<TClaims> = VerifyResult<TClaims> & {
  response?: AuthorizationResponse;
};

Defined in: @gramota/verifier/dist/verifier.d.ts:52

Result of verifier.responses.verify() — same shape as VerifyResult plus the parsed OID4VP transport envelope.

Type Declaration

response?
optional response?: AuthorizationResponse;

Type Parameters

TClaims

TClaims = Record<string, unknown>

Functions

inspect()

function inspect(presentationToken: string): ParsedSdJwt;

Defined in: @gramota/verifier/dist/inspect.d.ts:7

Parse an SD-JWT-VC presentation token without verifying anything. Useful for debug UIs, CLI tools, and admin dashboards. Never use the output to make trust decisions — that's verifier.verify()'s job.

Parameters

presentationToken

string

Returns

ParsedSdJwt