
Product
Socket for Jira Is Now Available
Socket for Jira lets teams turn alerts into Jira tickets with manual creation, automated ticketing rules, and two-way sync.
@govtechsg/oa-verify
Advanced tools
Using the [OpenAttestation (Verify)](https://github.com/Open-Attestation/oa-verify) repository as the codebase for the `npm` module, you can verify [wrapped documents](https://www.openattestation.com/docs/lib-section/remote-files/open-attestation#wrapping
Using the OpenAttestation (Verify) repository as the codebase for the npm module, you can verify wrapped documents programmatically. This is useful if you are building your own API or web components. The following are common use cases where you will need this module:
This module does not provide the following functionalities:
In brief, the verification flow runs three checks on the document:
Only when it passes all three checks, will it count as a valid OA document.
The diagram below shows the verification flow on OA documents issued using the Ethereum method:
The diagram below shows the verification flow on OA documents issued using the DID method:
To install OpenAttestation (Verify) on your machine, run the command below:
npm i @govtechsg/oa-verify
A verification happens on a wrapped document, which performs the following checks:
The verification requires a wrapped document created using OpenAttestation. The following shows an example of a wrapped document, which is valid and has been issued on the Sepolia network.
{
"version": "https://schema.openattestation.com/2.0/schema.json",
"data": {
"billFrom": {},
"billTo": { "company": {} },
"$template": {
"type": "f76f4d39-8d23-455b-96ba-5889e0233641:string:EMBEDDED_RENDERER",
"name": "575f0624-7f43-484c-9285-edd1ae96ebc6:string:INVOICE",
"url": "fb61f072-64e9-4c2f-83bf-ae68fd911414:string:https://generic-templates.tradetrust.io"
},
"issuers": [
{
"name": "ed121e9e-8f70-4a01-a422-4509d837c13f:string:Demo Issuer",
"documentStore": "08948d61-9392-459f-b476-e3c51961f04b:string:0x49b2969bF0E4aa822023a9eA2293b24E4518C1DD",
"identityProof": {
"type": "61c13b84-181a-43aa-85f5-dfe89e4b6963:string:DNS-TXT",
"location": "d7ba5e33-cf5f-4fcc-a4b7-3e6e17324966:string:demo-tradetrust.openattestation.com"
},
"revocation": {
"type": "23d47c6b-4384-4c31-90ca-8284602f6b3e:string:NONE"
}
}
],
"links": {
"self": {
"href": "121c55c0-864d-4e54-a1f0-86bec4b9a050:string:https://action.openattestation.com?q=%7B%22type%22%3A%22DOCUMENT%22%2C%22payload%22%3A%7B%22uri%22%3A%22https%3A%2F%2Ftradetrust-functions.netlify.app%2F.netlify%2Ffunctions%2Fstorage%2Faea9cb1a-816a-4fd7-b3a9-84924dc9a9e9%22%2C%22key%22%3A%22d80b453e53bb26d3b36efe65f18f0482f52d97cffad6f6c9c195d10e165b9a83%22%2C%22permittedActions%22%3A%5B%22STORE%22%5D%2C%22redirect%22%3A%22https%3A%2F%2Fdev.tradetrust.io%2F%22%2C%22chainId%22%3A%225%22%7D%7D"
}
},
"network": {
"chain": "05eb1707-5426-41d8-8fde-bc48ff0f2182:string:ETH",
"chainId": "ae505425-2df7-4597-87d2-037418d7bcbf:string:5"
}
},
"signature": {
"type": "SHA3MerkleProof",
"targetHash": "f292056ed5e5535400cec63b78a84ec384d2d77117e1606a17644e7b97a03cac",
"proof": [],
"merkleRoot": "f292056ed5e5535400cec63b78a84ec384d2d77117e1606a17644e7b97a03cac"
}
}
To perform the verification checks on the document, use the following code:
// index.ts
import { isValid, verify } from "@govtechsg/oa-verify";
import * as document from "./document.json";
const fragments = await verify(document as any);
console.log(isValid(fragments)); // output true
By default, the provided verify method performs multiple checks on a document.
The type DOCUMENT_STATUS runs these verifiers:
OpenAttestationEthereumDocumentStoreStatusOpenAttestationEthereumTokenRegistryStatusDidSignedDocumentStatusThe type DOCUMENT_INTEGRITY runs this verifier:
OpenAttestationHashThe type ISSUER_IDENTITY runs these verifiers:
OpenAttestationDnsTxtDnsDidProofAll those verifiers are exported as openAttestationVerifiers
You can build your own verification method based on the default exported verifiers:
// creating your own verification method using default exported verifiers
import { verificationBuilder, openAttestationVerifiers } from "@govtechsg/oa-verify";
const verify1 = verificationBuilder(openAttestationVerifiers, { network: "sepolia" }); // this verification is equivalent to the one exported by the library
const verify2 = verificationBuilder([openAttestationVerifiers[0], openAttestationVerifiers[1]], {
network: "sepolia",
}); // this verification only runs 2 verifiers
You can also build your own verification method based on the custom verifiers:
// creating your own verification using custom verifier
import { verificationBuilder, openAttestationVerifiers, Verifier } from "@govtechsg/oa-verify";
const customVerifier: Verifier<any> = {
skip: () => {
// returns a SkippedVerificationFragment if the verifier should be skipped or throws an error if it should always run
},
test: () => {
// returns true or false
},
verify: async (document) => {
// performs checks and returns a fragment
},
};
// creates your own verify function with all verifiers and your custom one
const verify = verificationBuilder([...openAttestationVerifiers, customVerifier], { network: "sepolia" });
Refer to the Extending custom verification section to find out more on how to create your own custom verifier.
Fragments will be produced after verifying a document. Each fragment will determine if the individual type mentioned here is valid or not, and will collectively prove the validity of the document.
The isValid function will execute over fragments and determine if the fragments produced a valid result. By default, the function will return true if a document fulfils all the following conditions:
In the function, a list of types also checks for as a second parameter.
// index.ts
import { isValid, openAttestationVerifiers, verificationBuilder } from "@govtechsg/oa-verify";
import * as document from "./document.json";
const verify = verificationBuilder(openAttestationVerifiers, {
network: "mainnet",
});
const fragments = await verify(document as any);
console.log(isValid(fragments, ["DOCUMENT_INTEGRITY"])); // output true
console.log(isValid(fragments, ["DOCUMENT_STATUS"])); // output false
console.log(isValid(fragments, ["ISSUER_IDENTITY"])); // output false
console.log(isValid(fragments)); // output false
The following explains what the functions return with reasons:
isValid(fragments, ["DOCUMENT_INTEGRITY"]) returns true because the integrity of the document is not dependent on the network where it has been published.isValid(fragments, ["DOCUMENT_STATUS"]) returns false because the document has not been published on the Ethereum main network.isValid(fragments, ["ISSUER_IDENTITY"]) returns false because there is no DNS TXT record associated with the Ethereum main network's document store.isValid(fragments) returns false because at least one of the above returns false.The verify function provides an option that listens to individual verification methods. It can be useful if you want, for instance, to provide individual loaders on your UI.
The following is a code example with that option:
// index.ts
import { isValid, openAttestationVerifiers, verificationBuilder } from "@govtechsg/oa-verify";
import * as document from "./document.json";
const verify = verificationBuilder(openAttestationVerifiers, {
network: "sepolia",
});
const promisesCallback = (verificationMethods: any) => {
for (const verificationMethod of verificationMethods) {
verificationMethod.then((fragment: any) => {
console.log(`${fragment.name} has been resolved with status ${fragment.status}`);
});
}
};
const fragments = await verify(document as any, promisesCallBack);
console.log(isValid(fragments)); // output true
Extending from the Custom verification section, you will learn how to write custom verification methods and how to distribute your own verifier.
You will write a verification method with the following rules:
It must run only on documents with their version equal to https://schema.openattestation.com/2.0/schema.json
It must return a valid fragment, only if the document data hold a name property with the value Certificate of Completion
This is where skip and test methods are needed. You will use the test method to return when the verification method was running and the skip method to explain why it wasn't:
// index.ts
import { verificationBuilder, openAttestationVerifiers, Verifier, isValid } from "@govtechsg/oa-verify";
import { getData } from "@govtechsg/open-attestation";
import * as document from "./document.json";
const customVerifier: Verifier<any> = {
skip: async () => {
return {
status: "SKIPPED",
type: "DOCUMENT_INTEGRITY",
name: "CustomVerifier",
reason: {
code: 0,
codeString: "SKIPPED",
message: `Document doesn't have version equal to 'https://schema.openattestation.com/2.0/schema.json'`,
},
};
},
test: () => document.version === "https://schema.openattestation.com/2.0/schema.json",
};
Note: Use the
DOCUMENT_INTEGRITYtype to check the document content.
name propertyOnce you have decided when the verification method will run, you need to write the logic of the verifier in the verify method. You will use the getData utility to access the document data and return the appropriate fragment depending on the content:
// index.ts
import { verificationBuilder, openAttestationVerifiers, Verifier, isValid } from "@govtechsg/oa-verify";
import { getData } from "@govtechsg/open-attestation";
import * as document from "./document.json";
const customVerifier: Verifier<any> = {
skip: async () => {
/* content has been defined in the section above */
},
test: () => /* content has been defined in the section above */,
verify: async (document: any) => {
const documentData = getData(document);
if (documentData.name !== "Certificate of Completion") {
return {
type: "DOCUMENT_INTEGRITY",
name: "CustomVerifier",
data: documentData.name,
reason: {
code: 1,
codeString: "INVALID_NAME",
message: `Document name is ${documentData.name}`,
},
status: "INVALID",
};
}
return {
type: "DOCUMENT_INTEGRITY",
name: "CustomVerifier",
data: documentData.name,
status: "VALID",
};
},
};
The verify function is built to run a list of verification methods. Each verifier will produce a fragment that determines if the document is valid. OpenAttestation has its own set of verification methods in openAttestationVerifiers.
Using the verificationBuilder function, you can create custom verification methods and reuse the default method exported from the library.
Extending from the Custom verification section, you will build a new verifier using the custom verification method below:
// index.ts
import { verificationBuilder, openAttestationVerifiers, Verifier, isValid } from "@govtechsg/oa-verify";
import { getData } from "@govtechsg/open-attestation";
import document from "./document.json";
// based on the test condition specified below, your custom verifier will only check documentData.name if document.version is equal to https://schema.openattestation.com/2.0/schema.json
const customVerifier: Verifier<any> = {
skip: async () => {
return {
status: "SKIPPED",
type: "DOCUMENT_INTEGRITY",
name: "CustomVerifier",
reason: {
code: 0,
codeString: "SKIPPED",
message: `Document doesn't have version equal to 'https://schema.openattestation.com/2.0/schema.json'`,
},
};
},
test: () => document.version === "https://schema.openattestation.com/2.0/schema.json",
verify: async (document: any) => {
const documentData = getData(document);
if (documentData.name !== "Certificate of Completion") {
return {
type: "DOCUMENT_INTEGRITY",
name: "CustomVerifier",
data: documentData.name,
reason: {
code: 1,
codeString: "INVALID_NAME",
message: `Document name is ${documentData.name}`,
},
status: "INVALID",
};
}
return {
type: "DOCUMENT_INTEGRITY",
name: "CustomVerifier",
data: documentData.name,
status: "VALID",
};
},
};
// create your own verify function with all verifiers and your custom one
const verify = verificationBuilder([...openAttestationVerifiers, customVerifier], { network: "sepolia" });
const fragments = await verify(document);
console.log(isValid(fragments)); // return false
console.log(fragments.find((fragment: any) => fragment.name === "CustomVerifier")); // display the details on our specific verifier
The document you created is not valid according to your own verifier, because the name property does not exist. Test again with the following document:
{
"version": "https://schema.openattestation.com/2.0/schema.json",
"data": {
"name": "66e35a92-9e97-4ffc-b94e-769773dd7535:string:Certificate of Completion",
"issuers": [
{
"documentStore": "375a13f9-ca3d-4a1f-a0c9-1fa92e43a3ec:string:0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3",
"name": "448c7f62-3a93-4792-a157-fabcbf15b91a:string:University of Blockchain",
"identityProof": {
"type": "dcfc17e0-a178-4bb8-b0fb-6a2cfddb8f2f:string:DNS-TXT",
"location": "e3f54dbf-bb51-41bb-9511-e01a5c07ea86:string:example.openattestation.com"
}
}
]
},
"privacy": { "obfuscatedData": [] },
"signature": {
"type": "SHA3MerkleProof",
"targetHash": "975887a864e11fbe27e90f4759c44db90193abc237dede81cd3cd7ca45c46522",
"proof": [],
"merkleRoot": "975887a864e11fbe27e90f4759c44db90193abc237dede81cd3cd7ca45c46522"
}
}
PROVIDER_API_KEY: You can provide your own PROVIDER API key.
PROVIDER_ENDPOINT_URL: You can provide your preferred JSON-RPC HTTP API URL.
PROVIDER_NETWORK: You can specify the network to use, i.e. "homestead", "mainnet", or "sepolia".
PROVIDER_ENDPOINT_TYPE: You can specify the provider to use, i.e. "infura", "alchemy", or "jsonrpc".
You may build the verifier to check against a custom network with either way:
Providing your own Web3 provider
Specifying the network name
In this way, the provider will be using the default one.
The following code example shows how you can specify a custom provider:
const verify = verificationBuilder(openAttestationVerifiers, { provider: customProvider });
The following code example shows how you can specify the network:
const verify = verificationBuilder(openAttestationVerifiers, { network: "sepolia" });
Using the exposed createResolver method, you can easily create custom resolvers to resolve DIDs:
import { createResolver, verificationBuilder, openAttestationVerifiers } from "@govtechsg/oa-verify";
const resolver = createResolver({
networks: [{ name: "my-network", rpcUrl: "https://my-private-chain/besu", registry: "0xaE5a9b9..." }],
});
const verify = verificationBuilder(openAttestationVerifiers, { resolver });
At the moment, oa-verify supports two DID resolvers:
You can generate a provider using the provider generator, which supports these providers:
INFURAALCHEMYETHERSCANJsonRPCIt requires a set of options:
network: Specified as a string for a common network name, i.e. "homestead", "mainnet", or "sepolia"provider: Specified as a string, i.e. "infura", "alchemy", or "jsonrpc"url: Specified as a string, which is being used to connect to a JSON-RPC HTTP APIapiKey: Specified as a string to be used together with the provider. If no value is provided, a default shared API key will be used, which may result in reduced performance and throttled requests.The following shows a basic use case of provider:
import { utils } from "@govtechsg/oa-verify";
const provider = utils.generateProvider();
// This will generate an infura provider using the default values.
This method uses the environment variables:
// environment file
PROVIDER_NETWORK = "sepolia";
PROVIDER_ENDPOINT_TYPE = "infura";
PROVIDER_ENDPOINT_URL = "http://jsonrpc.com";
PROVIDER_API_KEY = "ajdh1j23";
// provider file
import { utils } from "@govtechsg/oa-verify";
const provider = utils.generateProvider();
// This will use the environment variables declared in the files automatically.
This method passes in the values as parameters:
import { utils } from "@govtechsg/oa-verify";
const providerOptions = {
network: "sepolia",
providerType: "infura",
apiKey: "abdfddsfe23232",
};
const provider = utils.generateProvider(providerOptions);
// This will generate a provider based on the options provided.
// Note: Using this declaration will override all environment variables and default values.
Various utilities and types are available to assert the correctness of fragments. Each verification method exports types for the fragment and the data associated with the fragment.
VALID, INVALID, SKIPPED, and ERROR.VALID and INVALID fragment data are available in two flavors most of the time, one for each version of OpenAttestation (V2 or V3).This library provides types and utilities to:
verify method.The following code example shows the usage:
import { utils } from "@govtechsg/oa-verify";
const fragments = verify(documentValidWithCertificateStore, { network: "sepolia" });
// return the correct fragment, correctly typed
const fragment = utils.getOpenAttestationEthereumTokenRegistryStatusFragment(fragments);
if (utils.isValidFragment(fragment)) {
// guard to narrow to the valid fragment type
const { data } = fragment;
if (ValidTokenRegistryDataV2.guard(data)) {
// data is correctly typed here
}
}
Note: In the example above, it may be unnecessary to use
utils.isValidFragment, as it's possible to useValidTokenRegistryDataV2.guarddirectly over the data.
getOpenAttestationHashFragmentgetOpenAttestationDidSignedDocumentStatusFragmentgetOpenAttestationEthereumDocumentStoreStatusFragmentgetOpenAttestationEthereumTokenRegistryStatusFragmentgetOpenAttestationDidIdentityProofFragmentgetOpenAttestationDnsDidIdentityProofFragmentgetOpenAttestationDnsTxtIdentityProofFragmentgetDocumentIntegrityFragmentsgetDocumentStatusFragmentsgetIssuerIdentityFragmentsisValidFragment: Type guard to filter only the VALID fragment typeisInvalidFragment: Type guard to filter only the INVALID fragment typeisErrorFragment: Type guard to filter only the ERROR fragment typeisSkippedFragment: Type guard to filter only the SKIPPED fragment type| Name | Type | Description | Present in default verifier? |
|---|---|---|---|
| OpenAttestationHash | DOCUMENT_INTEGRITY | Verify that merkle root and target hash matches the certificate | Yes |
| OpenAttestationDidSignedDocumentStatus | DOCUMENT_STATUS | Verify the validity of the signature of a DID signed certificate | Yes |
| OpenAttestationEthereumDocumentStoreStatus | DOCUMENT_STATUS | Verify the certificate has been issued to the document store and not revoked | Yes |
| OpenAttestationEthereumTokenRegistryStatus | DOCUMENT_STATUS | Verify the certificate has been issued to the token registry and not revoked | Yes |
| OpenAttestationDidIdentityProof | ISSUER_IDENTITY | Verify identity of DID (similar to OpenAttestationDidSignedDocumentStatus) | No |
| OpenAttestationDnsDidIdentityProof | ISSUER_IDENTITY | Verify identify of DID certificate using DNS-TXT | Yes |
| OpenAttestationDnsTxtIdentityProof | ISSUER_IDENTITY | Verify identify of document store certificate using DNS-TXT | Yes |
To run tests, use the following command:
npm run test
To generate test documents (for V3), use the script at scripts/generate.v3.ts and run the following command:
npm run generate:v3
OpenAttestation (Verify) is under the Apache license, version 2.0.
FAQs
Using the [OpenAttestation (Verify)](https://github.com/Open-Attestation/oa-verify) repository as the codebase for the `npm` module, you can verify [wrapped documents](https://www.openattestation.com/docs/lib-section/remote-files/open-attestation#wrapping
The npm package @govtechsg/oa-verify receives a total of 453 weekly downloads. As such, @govtechsg/oa-verify popularity was classified as not popular.
We found that @govtechsg/oa-verify demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 11 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Socket for Jira lets teams turn alerts into Jira tickets with manual creation, automated ticketing rules, and two-way sync.

Company News
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.

Security News
NIST will stop enriching most CVEs under a new risk-based model, narrowing the NVD's scope as vulnerability submissions continue to surge.