npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@pagopa/io-wallet-oid4vp

v0.7.3

Published

This package provides functionalities to manage the **OpenID for Verifiable Presentations (OID4VP)** protocol flow, specifically tailored for the Italian Wallet ecosystem, simplifying QEAA credentials issuance and credentials presentations.

Downloads

769

Readme

@pagopa/io-wallet-oid4vp

This package provides functionalities to manage the OpenID for Verifiable Presentations (OID4VP) protocol flow, specifically tailored for the Italian Wallet ecosystem, simplifying QEAA credentials issuance and credentials presentations.

Installation

To install the package, use your preferred package manager:

# Using pnpm
pnpm add @pagopa/io-wallet-oid4vp

# Using yarn
yarn add @pagopa/io-wallet-oid4vp

Usage

Verifying a received Request object

The parseAuthorizeRequest function verifies a JWT containing a Request Object and determines the correct public key for signature verification based on the IT Wallet specifications.

Public Key Resolution Priority

The function follows this priority order to determine which public key to use for JWT verification:

  1. x509_hash# prefix in client_id - Uses x5c certificate chain from header
  2. openid_federation# prefix or no prefix in client_id (default method) - Extracts RP metadata from the trust_chain array in the JWT header

Important:

  • When the client_id uses the openid_federation# prefix or has no prefix, the trust_chain MUST be present in the JWT header
  • Any client_metadata present in the request object MUST be ignored when using openid_federation# prefix
  • The RP metadata is automatically extracted from the first JWT in the trust_chain array
import { parseAuthorizeRequest } from '@pagopa/io-wallet-oid4vp';
import { ItWalletCredentialVerifierMetadata } from '@pagopa/io-wallet-oid-federation';

// Request Object JWT containing the requested credentials obtained from the RP
const requestObjectJwt = "ey..." 

// Prepare the callbacks
const callbacks = {
    verifyJwt : async (signer, {header, payload, compact}) => {
        const result = //signature verification
        return {
            verified : result,
            signerJwk : signer.publicJwk //Mandatory only if signature is verified correctly
        }
    }
}

// Decode, verify and return the Request Object
// The RP metadata is automatically extracted from the trust_chain in the JWT header
// when client_id has openid_federation# prefix or no prefix
const parsedRequestObject = await parseAuthorizeRequest({
    requestObjectJwt,
    callbacks
});

Specific Scenarios

Scenario 1: x509_hash# prefix - Using client_metadata

When the client_id uses the x509_hash# prefix, the public key is obtained from the client_metadata.jwks field in the Request Object:

// Request Object with:
// - client_id = "x509_hash#abc123..."
// - x5c included jwt
const parsedRequestObject = await parseAuthorizeRequest({
    requestObjectJwt,
    callbacks,
});
Scenario 2: openid_federation# prefix - Using Trust Chain

When the client_id uses the openid_federation# prefix, the RP metadata is automatically extracted from the trust_chain array in the JWT header. Any client_metadata in the Request Object is ignored:

// Request Object with:
// - client_id = "openid_federation#https://rp.example.org"
// - header.trust_chain = ["<RP Entity Configuration JWT>", ...]
const parsedRequestObject = await parseAuthorizeRequest({
    requestObjectJwt,
    callbacks,
});
// RP metadata is automatically extracted from trust_chain[0]

Generating an Authorization Response

import { createAuthorizationResponse, AuthorizationRequestObject } from '@pagopa/io-wallet-oid4vp';
import { ItWalletCredentialVerifierMetadata } from "@pagopa/io-wallet-oid-federation";

//Obtain the RP's metadata
const rpMetadata : ItWalletCredentialVerifierMetadata = {
  ...
}

//Obtain a decoded Request Object from, e.g., parseAuthorizeRequest invocation
const requestObject: AuthorizationRequestObject = {
  ...
}

//Obtain the signer
const signer = {
    method : 'jwk',
    publicJwk : {/*... jwk details*/},
    alg : 'ES256'
}

//Obtain the vp_token
const vp_token = {
  ... //VP token containing the attributes to disclose
}

//Prepare the callbacks
const callbacks = {
    encryptJwe : async (jweEncryptor, data) => {
        const result = encrypt(data, jweEncryptor)
        return {
            verified : result,
            encryptionJwk : jweEncryptor
        }
    },
    fetch : async (input, init) => {
      ...//Fetch implementation
    },
    generateRandom : async (number) => new Uint8Array(number),
    signJwt : async (jwtSigner, {header, payload}) => {
      const str = `${b64url(JSON.stringify(header))}.${b64url(JSON.stringify(body))}`
      const sig = signJwt(jwtSigner, str)
      return `${str}.${sig}`
    }
}

//Create the response

const resp = createAuthorizationResponse({
  callbacks,
  client_id : "JWK Thumbprint",
  requestObject,
  rpMetadata,
  signer,
  vp_token
})

API Reference

AuthorizationRequestObject type and Zod parser

export const zVpFormatsSupported = z.record(
  z.string(),
  z
    .object({
      alg_values_supported: z.optional(z.array(z.string())),
    })
    .passthrough(),
);

export type VpFormatsSupported = z.infer<typeof zVpFormatsSupported>;

export const zClientMetadata = z
  .object({
    client_name: z.string().optional(),
    encrypted_response_enc_values_supported: z.array(z.string()).optional(),
    jwks: z.object({ keys: z.array(zJwk) }).passthrough(),
    logo_uri: z.string().url().optional(),
    vp_formats_supported: zVpFormatsSupported,
  })
  .passthrough();

export type ClientMetadata = z.infer<typeof zClientMetadata>;

export const zOpenid4vpAuthorizationRequestPayload = z
  .object({
    response_type: z.literal('vp_token'),
    client_id: z.string(),
    client_metadata: zClientMetadata.optional(),
    response_uri: z.string().url().optional(),
    request_uri: z.string().url().optional(),
    request_uri_method: z.optional(z.string()),
    response_mode: z.literal("direct_post.jwt"),
    nonce: z.string(),
    wallet_nonce: z.string().optional(),
    scope: z.string().optional(),
    dcql_query: z.record(z.string(), z.any()).optional(),
    state: z.string().optional(),
    transaction_data_hashes_alg: z.array(z.string()).optional(),
  })
  .passthrough().and(zJwtPayload)

export type AuthorizationRequestObject = z.infer<typeof zOpenid4vpAuthorizationRequestPayload>

parseAuthorizeRequest

export interface ParseAuthorizeRequestOptions {
    /**
     * The Authorization Request Object JWT.
     */
    requestObjectJwt : string ;

    /**
     * Callback context for signature verification.
     */
    callbacks : Pick<CallbackContext, 'verifyJwt'>

    /**
     * DPoP options
     */
    dpop: RequestDpopOptions
}

export async function parseAuthorizeRequest(options: ParseAuthorizeRequestOptions) : Promise<AuthorizationRequestObject> {
    ...
}

This method receives a Request Object in JWT format, verifies the signature and returns the decoded Request Object.

createAuthorizationResponse

export interface CreateAuthorizationResponseOptions {
  /**
   * Callbacks for authorization response generation
   */
  callbacks: Pick<
    CallbackContext,
    "encryptJwe" | "fetch" | "generateRandom" | "signJwt"
  >;

  /**
   * Thumbprint of the JWK in the cnf Wallet Attestation
   */
  client_id: string;

  /**
   * Optional expiration of the Authorization Response JWT, defaults to 10 minutes
   */
  exp?: number;

  /**
   * Presentation's Request Object
   */
  requestObject: AuthorizationRequestObject;

  /**
   * OpenID Federation Relying Party metadata
   */
  rpMetadata: ItWalletCredentialVerifierMetadata;

  /**
   * Signer created from the Wallet Instance's private key
   */
  signer: JwtSigner;

  /**
   * Array containing the vp_tokens of the credentials
   * to present
   */
  vp_token: VpToken;
}

export async function createAuthorizationResponse(
  options: CreateAuthorizationResponseOptions,
) {
  ...
}

This method receives the RequestObject, its resolved VP Tokens and other necessary cryptographic and configuration data and returns a signed Authorization Response

Errors

export class Oid4vpError extends Error {
  constructor(
    message: string,
    public readonly statusCode?: number,
  ) {
    super(message);
    this.name = "Oid4vpError";
  }
}

Generic package level error class which every other package error should extend.

export class ParseAuthorizeRequestError extends Oid4vpError {
  constructor(
    message: string,
    public readonly statusCode?: number,
  ) {
    super(message);
    this.name = "ParseAuthorizeRequestError";
  }
}

Error thrown by parseAuthorizeRequest when the passed request object has an invalid signature or unexpected errors are thrown.

export class CreateAuthorizationResponseError extends Oid4vpError {
  constructor(
    message: string,
    public readonly statusCode?: number,
  ) {
    super(message);
    this.name = "CreateAuthorizationResponseError";
  }
}

Error thrown by createAuthorizationResponse in case there are unexpected errors.