Verifying PDF Signatures in JavaScript: A Library Comparison
If you have searched npm for a way to verify a signed PDF, you have probably noticed how confusing the landscape is. Dozens of libraries mention "signatures," but they mean very different things. Some create signatures, some only render the visual stamp, and a handful actually verify the cryptography — but even those stop well short of the verdict Adobe Reader gives you.
This is an honest, sourced comparison of the JavaScript and Node.js options for verifying existing PDF digital signatures, and where VerifyKit — a commercial SDK — fits among them.
First, three things that get conflated
Before comparing libraries, separate the four jobs people lump together:
- Manipulate — create or edit PDFs (add pages, fill forms). pdf-lib.
- Sign — apply a new digital signature. @signpdf/signpdf.
- Render — paint the PDF, including a signature's visual appearance. PDF.js.
- Verify — cryptographically check that an existing signature is intact and trusted. A small group, covered below.
A library that is excellent at one of these usually does nothing for the others. Rendering a signature's appearance, in particular, is not verification — a tampered document can still display a signature stamp.
What full verification actually requires
A faithful verifier is a pipeline, not a single check:
- Integrity — recompute the hash over the signed
ByteRangeand confirm nothing changed after signing. - Signature — validate the CMS/PKCS#7
SignedDataagainst the signer's public key. - Certificate chain — build a path from the signer certificate up to a root.
- Trust — decide whether that root is trusted for document signing (the Adobe AATL, the EU EUTL, or your own CA set) — not just any web/TLS CA.
- Expiry — confirm the certificate was valid at signing time.
- Timestamp — validate any RFC 3161 timestamp token.
- Revocation — consult CRL / OCSP data (embedded for LTV, or fetched online).
- Algorithm & key usage — enforce a policy on weak algorithms and check Extended Key Usage.
Keep points 4 and 7 in mind — trust and revocation are where almost every JavaScript option falls short.
The libraries, honestly
pdf-lib
A PDF create/modify library. It does not sign and does not verify — the terms PKCS#7, X.509, OCSP, and PAdES do not appear in its documentation, and native signing has been an open request for years. Great for generating and editing PDFs; not a signature tool at all.
node-signpdf / @signpdf/signpdf
A Node.js signing library (node-signpdf is deprecated in favor of @signpdf/signpdf). There is no verification API. Its extractSignature helper only pulls the ByteRange and PKCS#7 bytes out of a PDF — its own source calls this "really basic," and it performs no digest comparison or cryptographic validation. If you need to apply signatures in Node, it is a solid choice; it is simply not a verifier.
PDF.js (pdfjs-dist)
Mozilla's renderer. It displays a signature field's appearance but performs no cryptographic verification in any released version (v6.1.200 and earlier, as of July 2026) — a position the maintainers held for years. An off-by-default verification path recently landed on master, but it delegates all cryptography to Firefox's NSS, returns no verifier in the generic pdfjs-dist / Node build, uses Mozilla's trust store rather than AATL/EUTL, and defers revocation. For a product decision today, the accurate statement is: no signature verification out of the box.
The verify-pdf family (pdf-signature-reader, @ninja-labs/verify-pdf, @qlever-llc/verify-pdf, node-pdf-verifier)
These are the npm libraries that genuinely do verify — but partially. They confirm integrity (byte-range digest) and validate the PKCS#7/CMS signature. Where they stop matters:
- Trust is web-PKI, not document-signing. They match the certificate against the general TLS/web CA bundle, not the Adobe AATL or EU EUTL document-signing trust lists. An
authenticity: trueresult means "chained to a TLS root," not "trusted to sign documents." - Chain checks are often name-only. Several (pdf-signature-reader, @ninja-labs, @jonz94) rely on node-forge's
issued(), which its own source documents as doing no signature check — it compares issuer/subject names. Only@qlever-llc/verify-pdfv3 (Dec 2025) does a real cryptographic chain verification. - No revocation (OCSP/CRL) and no PAdES level detection in any of them.
- Most are stale (last meaningful releases 2021–2024); only
@qlever-llc/verify-pdfis currently maintained.
These are useful for a quick integrity + basic-cert check in a free, open-source package. They are not built to answer "do we trust this signer, and has the certificate been revoked?"
PKI.js and node-forge
Excellent cryptographic primitives — CMS validation, chain verification, OCSP/CRL building blocks — but they are not PDF-aware. They know nothing about byte ranges, PAdES, or trust lists; you would be building the PDF orchestration and the trust model yourself. (node-forge's own docs note CRLs are not supported.)
The full validators: EU DSS, Apryse, Nutrient
The tools that do the complete job — integrity + chain + AATL/EUTL trust + OCSP/CRL + PAdES B/T/LT/LTA — are not pure-JS open source. EU DSS (the eIDAS/PAdES reference validator) is Java. Apryse WebViewer and Nutrient do full client-side validation but are proprietary commercial SDKs built on C++/PDFium WASM cores.
The gap
Put the findings together and a clear gap appears: no mainstream pure-JS/WASM open-source library performs full PAdES validation. Your options are (1) crypto primitives with no PDF orchestration, (2) shallow verifiers that stop at integrity plus a basic, web-PKI chain check, or (3) a Java stack or a commercial native SDK.
Where VerifyKit fits
VerifyKit is a commercial, licensed SDK built specifically to close that gap in the JavaScript ecosystem. Its Rust/WASM engine runs the full 8-point pipeline above — including a built-in AATL trust store, CRL/OCSP revocation, and PAdES B-B / B-T / B-LT / B-LTA detection — entirely client-side (the PDF is never uploaded), and the same engine runs headless in Node.js. It deliberately mirrors Adobe's valid / unknown / invalid verdict semantics, so an intact document from an untrusted signer reads as "unknown," not "invalid" (see Why Adobe Says "Signature Validity Is Unknown").
It is not free the way an npm package is — access is licensed — but you can try it on your own signed PDFs in the live demo before talking to anyone.
At a glance
| Library | Primary job | Verifies? | Integrity + PKCS#7 | Chain | AATL/EUTL trust | Revocation (OCSP/CRL) | PAdES levels | Runtime |
|---|---|---|---|---|---|---|---|---|
| pdf-lib | Manipulate | No | – | – | – | – | – | Node + Browser |
| @signpdf/signpdf | Sign | No | extract only | – | – | – | – | Node |
| PDF.js | Render | No (released) | – | – | – | – | – | Node + Browser |
| verify-pdf family | Verify | Partial | Yes | Name-only¹ | No (web-PKI) | No | No | Node (+Browser²) |
| PKI.js / node-forge | Crypto primitives | n/a | Partial | Supply anchors | No | Primitives only | No | Pure JS |
| EU DSS | Full validator | Yes | Yes | Yes | Yes (EUTL) | Yes | Yes | Java |
| Apryse / Nutrient | Full validator | Yes | Yes | Yes | Yes | Yes | Yes | Commercial WASM |
| VerifyKit | Verify | Yes | Yes | Yes | Yes (AATL) | Yes | Yes | Browser + Node (WASM) |
¹ Cryptographic chain verification only in @qlever-llc/verify-pdf v3. ² Browser support varies by package.
How to choose
- Just displaying a PDF? PDF.js is perfect on its own.
- Applying signatures in Node? @signpdf/signpdf.
- A quick integrity + basic-cert check, free and open source? The verify-pdf family — knowing it does not establish document-signing trust or check revocation.
- A real verdict — trust, revocation, and PAdES levels — in the browser or Node? That is a full cryptographic verification problem. In the JS ecosystem that means VerifyKit; otherwise a Java stack (EU DSS) or another commercial SDK.
See Core Concepts for the verification model, the Quick Start to integrate it, and the Revocation Checking guide for CRL/OCSP. Or try it on your own signed PDF in the live demo — everything runs in your browser.
References
- pdf-lib — docs · signing request #172
- @signpdf/signpdf — npm;
extractSignaturesource lives in the@signpdf/utilspackage - PDF.js — verification tracking issue #13351 · master-only feature PR #21247
- verify-pdf family — pdf-signature-reader · @qlever-llc/verify-pdf · node-forge
issued()"no signature check" - Primitives & full validators — PKI.js · EU DSS · Apryse · Nutrient
Need PDF signature verification in production?
VerifyKit is a commercial SDK — try the live demo, then get in touch for a license.