Certificate-based PDF signing as a set of npm packages
@signpdf is a set of npm packages that add a certificate-based digital signature to a PDF from Node.js. A helper first reserves a signature field in the document and fills it with zeros. @signpdf/signpdf then works out the byte range to sign, hands it to a signer, and writes the result over the zeros. The only published signer, @signpdf/signer-p12, uses node-forge to build a detached PKCS#7 signature from a P12 certificate. The README is upfront about the goal: show the signing flow "in a piece of readable code", under the MIT license.
@signpdf signs the file you give it and stops there. Sending the document to a person and recording their consent is the job of an application such as Documenso or DocuSeal. The comparison of open source e-signature tools looks at what each one puts into the PDF and what that is worth legally.
Pluggable signers, placeholder helpers per PDF source
- A helper for each way of getting the PDF:
placeholder-pdfkitandplaceholder-pdfkit010hook into PDFKit while the document is generated,placeholder-pdf-libworks on a document loaded with PDF-LIB, andplaceholder-plainon a file already written to disk. A PDF that already carries a signature field needs no helper. - Pluggable signers:
@signpdf/signpdfaccepts any class that extendsSignerand implementssign(). - PAdES behind one option:
subFilter: SUBFILTER_ETSI_CADES_DETACHEDreplaces the default Adobe value with the one the README names as the requirement for PAdES-compliant signatures. - Several signatures on one file: the
multiple-signatures.jsexample has a buyer, then a seller, sign the same contract, each with their own P12. - Predictable signature size: in detached mode the size depends on the certificate, not on the document. You measure it once to set
signatureLength, andsign()throws an explicit error when the placeholder is too small.
Exportable private keys only, and no timestamp authority
No support for the people signing. @signpdf has no UI, sends nothing, and records no consent. The signature belongs to whoever holds the P12, so two signers need two certificates. The P12 signer checks neither the issuer nor the expiry date of the certificate, and what the signature is worth comes down to who issued it.
No timestamp from an authority. The time stored in the signature is the signingTime attribute, read from the machine's clock. No package requests a token from a timestamping authority (TSA) or adds the OCSP responses that long-term validation (LTV) relies on. A 2021 request for timestamping (#124) was closed for inactivity. On LTV (#186), Daniel Hensby, who merges pull requests, describes an attempt whose signatures Acrobat would not validate.
The private key has to be exportable. @signpdf/signer-p12 signs in memory with the key stored in the P12 file. A key locked inside an HSM, Azure Key Vault or Google Cloud KMS means writing your own Signer, and it has to return a full CMS structure rather than the raw signature. Two issues on the subject (#270, #272) have been open since September 2024.
Signatures are invisible by default. All four helpers add a zero-size field (widgetRect defaults to [0, 0, 0, 0]). To show the signature on the page, you pass a rectangle and draw the box yourself, as the pdfkit010-with-visual.js example does with PDFKit. placeholder-plain, the most used helper according to the README, works through string searches: it is fragile, has no stream support and stops at PDF 1.3.
No release so far in 2026. Version 3.3.0 came out on December 29, 2025. Since then the develop branch has only received dependency bumps and one fix, and its engines field now requires Node 22, where the published release accepts Node 12. Valery Buchinsky, who owns the repository, authored 361 commits; the next contributor, bots aside, has 14. The old node-signpdf package, frozen at 3.0.0 since October 2023 and marked deprecated, was still downloaded 34,014 times in the week of September 28, 2026, against 308,893 for @signpdf/signpdf.
