@sphereon/pe-js

A Typescript implementation of the DIF Presentation Exchange specification.

Showing:

Popularity

Downloads/wk

79

GitHub Stars

10

Maintenance

Last Commit

10d ago

Contributors

11

Package

Dependencies

5

License

Apache-2.0

Type Definitions

Built-In

Tree-Shakeable

Yes?

Categories

Readme


Sphereon
PE-JS DIF Presentation Exchange JavaScript Library

CI codecov NPM Version

Active Development

IMPORTANT: This software still is in early development stage. As such you should expect breaking changes in APIs, we expect to keep that to a minimum though.

Background

The PE-JS Library is a general use presentation exchange library that implements the functionality described in the DIF Presentation Exchange v1.0.0 specification. It is written in Typescript and can be compiled to any target JavaScript version.

Sphereon's PE Library is useful for both verifier systems and holders (e.g. wallets) and can be used in client side browsers and mobile applications as well as on server side technology such as REST APIs (e.g. built with NodeJS). It allows anyone to add DIF Presentation Exchange logic to their existing wallets, or verifiers, without making any further assumptions about the technologies used in their products.

The presentation exchange operates generally as follows; The verifier creates a Presentation Definition asking for credentials from the holder. The definition for the credentials is sent to the holder, who returns a presentation as a response. Now the verifier will verify the presentation by checking the signature and other accompanying proofs.

The presentation exchange will ensure that the model used by the verifier, can be interpreted by the holder. It then ensures that the correct parts from the holders credentials are used to create the presentation. The PE contains all the logic to interpret the models, therefore removing the need for the verifier and holder to align their specific models.

The data objects (models) used in PE-JS are generated from Sphereon's DIF PE OpenAPI Spec component. The code for the component can be seen at PE-OpenAPI github repository. This allows the generation of the objects in many languages and frameworks consistently by configuring the maven plugin.

The PE Library supports the following actions:

  • Creating a presentation definition / request
  • Validating a presentation definition / request to be as per specification
  • Creating a presentation submission
  • Validating a presentation submission when received
  • Input evaluations: Verification of presentation submissions to be as per presentation definition
  • Utilities: to build and use different models compliant with the DIF Presentation Exchange v1.0.0 specification.

Stateful storage or credential management should be implemented in separate libraries/ modules that make use of the underlying DIF Presentation Exchange implementation. By keeping these separate, the library will stay platform agnostic.

For PE-JS developers

This project has been created using:

  • yarn version 1.22.5
  • node version 12.22.1

Install

yarn install

Build

yarn build

Test

The test command runs:

  • eslint
  • prettier
  • unit

You can also run only a single section of these tests, using for example yarn test:unit.

yarn test

Utility scripts

There are several other utility scripts that help with development.

  • yarn fix - runs eslint --fix as well as prettier to fix code style
  • yarn cov - generates code coverage report

For PE-JS Users

The library can be installed direction from npmjs via:

# install via yarn
yarn add @sphereon/pe-js

# install via npm
npm install @sphereon/pe-js

The core functionality of the DIF Presentation Exchange can be outlined as follows:

  • Input Evaluation
  • Credential Query
  • Utilities

Input Evaluation

Input evaluation is the primary mechanism by which a verifier determines whether a presentation submission from a holder matches the requested presentation definition from the request.

import pejs from '@sphereon/pe-js';

const presentationDefinition = {
  "id": "32f54163-7166-48f1-93d8-ff217bdb0653",
  "input_descriptors": [
    {
      "id": "wa_driver_license",
      "name": "Washington State Business License",
      "purpose": "We can only allow licensed Washington State business representatives into the WA Business Conference",
      "schema": [{
        "uri": "https://licenses.example.com/business-license.json"
      }]
    }
  ]
};

const verifiablePresentation = {
  '@context': [
    "https://www.w3.org/2018/credentials/v1",
    "https://identity.foundation/presentation-exchange/submission/v1"
  ],
  type: [
    "VerifiablePresentation",
    "PresentationSubmission"
  ],
  presentation_submission: {...},
  verifiableCredential: [...],
  proof: {...}
}

const {value, warnings, errors} = pejs.evaluate(presentationDefinition, verifiablePresentation);

Credential Query

A credential query allows holders to filter their set of credentials for matches to a given presentation definition.

import pejs from '@sphereon/pe-js';

// Definition from verifier request
const presentationDefinition = {
  ...
};

// Example for loading credentials
const credentials = await secureStore.getCredentials();

// Find matching credentials
const srMatches = pejs.selectFrom(presentationDefinition, credentials, holderDid);

// An example that selects the first 'count' credentials from
// the matches. in a real scenario, the user has to select what 
// to disclose
const selectedCredentials = srMatches.map(
  ({matches, count}) => matches.slice(0, count)
).flat();

// Construct presentation submission from selected credentials
const presentationSubmission = pejs.submissionFrom(presentationDefinition, selectedCredentials);

const presentation = {
  "@context": [
    "https://www.w3.org/2018/credentials/v1",
    "https://identity.foundation/presentation-exchange/submission/v1"
  ],
  "type": [
    "VerifiablePresentation",
    "PresentationSubmission"
  ],
  presentation_submission: presentationSubmission,
  verifiableCredential: selectedCredentials
};

// Presentation would be signed and sent to verifier

Utilities

In addition to the core functionality above, the underlying validation methods are exposed as low-level helper functions.

import pejs from '@sphereon/pe-js';

const presentationDefinition = {
  ...
};

const {warnings: pdWarnings, errors: pdErrors} = pejs.validateDefinition(presentationDefinition);

const presentationSubmission = {
  ...
};

const {warnings: psWarnings, errors: psErrors} = pejs.validateSubmission(presentationSubmission);

API

Evaluate

evaluate(presentationDefinition, verifiablePresentation)
Description

Evaluates whether a presentation submission meets the requested presentation definition

Parameters

nametypedescription
presentationDefinitionPresentationDefinitionthe presentation definition that initiated the request from the verifier
verifiablePresentationVerifiablePresentationthe VP containing the required credentials and a presentation_submission object mapping back to the presentation definition

Return value

If evaluation is successful, value will be a non-null PresentationSubmission mapping the submitted credentials to the requested inputs.

interface EvaluationResults {
  value?: PresentationSubmission;
  warnings?: string[];
  errors?: Error[];
}

SelectFrom

selectFrom(presentationDefinition, credentials, holderDid)
Description

Gathers the matching credentials that fit a given presentation definition

Parameters

nametypedescription
presentationDefinitionPresentationDefinitionthe presentation definition that initiated the request from the verifier
credentialsVerifiableCredential[]the array of verifiable credentials to select from
holderDidstringthe holder's did. this can be found in VerifiablePresentation's holder property

Return value

  • If the selection was successful or partially successful, the matches array will consist of SubmissionRequirementMatch object(s), representing the matching credentials for each SubmissionRequirement in the presentationDefinition input parameter.
  • If the selection was not successful, the errors array will consist of Checked object(s), representing what has failed in your selection process.
interface SelectResults {
  errors?: Checked[]
  matches?: SubmissionRequirementMatch[];
  warnings?: Checked[];
}

interface SubmissionRequirementMatch {
  name: string;
  rule: Rule;
  count: number;
  from?: string[];
  from_nested?: SubmissionRequirementMatch[];
  matches: string[]; // VerifiableCredential Address
}

SubmissionFrom

submissionFrom(presentationDefinition, selectedCredentials)
Description

Creates the corresponding Presentation Submission object to be included in the Verifiable Presentation response, which maps the submitted credentials to the requested inputs in the presentationDefinition input parameter.

Parameters

nametypedescription
presentationDefinitionPresentationDefinitionthe presentation definition that initiated the request from the verifier
selectedCredentialsVerifiableCredential[]the array of verifiable credentials that meet the submission requirements in the presentation definition

Return value

If the selected credentials successfully match the submission requirements in the presentation definition, the return value will be a non-null PresentationSubmission

interface PresentationSubmission {
  id?: string;
  definition_id: string;
  descriptor_map: Descriptor[]
}

Validation

validateDefinition(objToValidate)
validateSubmission(objToValidate)

Description

A validation utility function for PresentationDefinition and PresentationSubmission objects.

Parameters

nametypedescription
objToValidatePresentationDefinition | PresentationSubmissionthe presentation definition or presentation definition to be validated

Return value

The validate method returns a validated results array NonEmptyArray<Checked> , with structure:

interface Checked {
  tag: string;
  status: Status;
  message?: string;
}

status can have following values 'info' | 'warn' | 'error'

Further work:

  1. Based on the DIF documentation

    4.3.1- If the Input Descriptor schema object uri is a hashlink or similar value that points to immutable content, then the content of the retrieved schema must also match This hashlink validation is currently not included.

  2. In the DIF documentation some entries are addressing nested credentials and nested paths these are currently not fully support yet.

Rate & Review

Great Documentation0
Easy to Use0
Performant0
Highly Customizable0
Bleeding Edge0
Responsive Maintainers0
Poor Documentation0
Hard to Use0
Slow0
Buggy0
Abandoned0
Unwelcoming Community0
100