How to Secure and Sign PDF Documents in TypeScript
This guide shows how to encrypt, certify, sign, and verify PDF documents
with Aspose.PDF FOSS for TypeScript. Document.Save() and Document.Open()
handle public-key encryption to recipient certificates, while
Document.Certify(), Document.Sign(), and Document.VerifySignatures()
handle PAdES-style digital signatures. It requires Node.js 22 or later.
Step-by-Step Guide
Step 1: Install the Package
asposefoss/pdf is not yet published — build from source until it ships. See the project README for build instructions.
Verify the installation by importing the Document class in a new
TypeScript file — this line should resolve without error once the package
is installed:
import { Document } from '@asposefoss/pdf';Step 2: Import Required Classes
Import Document to open, save, sign, and verify the file; the signing
and encryption steps below pass plain option objects, so no further
imports are needed:
import { Document } from '@asposefoss/pdf';Step 3: Encrypt a Document to Recipient Certificates
Document.Save() accepts an encrypt option carrying one or more
recipients, each identified by a certificate (PEM string or DER bytes),
an algorithm, and shared permissions:
const doc = Document.OpenFile('report.pdf');
const bytes = doc.Save({
encrypt: {
recipients: [{ certificate: recipientCertPem }],
algorithm: 'aes256', // 'aes256' (default) | 'aes128' | 'rc4'
permissions: { copying: false }, // shared across all recipients
},
});Step 4: Open an Encrypted Document
Pass a recipient option to Document.Open() with either the matching
private key and certificate, or a PKCS#12 bundle:
const opened = Document.Open(bytes, {
recipient: { privateKey, certificate: recipientCertPem },
// or: recipient: { pkcs12: p12Bytes, passphrase: '…' },
});
console.log(opened.Permissions); // recovered permission flags (not enforced)
Step 5: Certify and Sign a Document
Document.Certify() and Document.Sign() are both asynchronous and take
an identity (certificate + privateKey) plus options describing the
signature field, appearance, and reason. Certifying should happen first,
over the whole file; further approval signatures are appended
incrementally afterward:
async function certifyAndSign(sourcePath: string, signaturePageIndex: number): Promise<void> {
const certifying = Document.OpenFile(sourcePath);
await certifying.Certify(
{ certificate: authorCert, privateKey: authorKey },
{
permissions: 'form-fill',
reason: 'Certifying the document',
fieldName: 'Certification',
appearance: { page: signaturePageIndex, rect: [400, 100, 550, 140] },
},
);
const certifiedBytes = certifying.Save();
const approving = Document.Open(certifiedBytes);
await approving.Sign(
{ certificate: approverCert, privateKey: approverKey },
{ reason: 'Approved for publication', fieldName: 'Approval', subFilter: 'PAdES' },
);
approving.WriteTo('signed.pdf');
}Step 6: Verify Signatures
Document.VerifySignatures() is asynchronous and returns one
SignatureReport per signature field, each reporting cryptographic
integrity, signature validity, and whether it coversWholeFile:
async function verify(path: string): Promise<void> {
const doc = Document.OpenFile(path);
const reports = await doc.VerifySignatures();
for (const r of reports) {
console.log(`${r.name}: integrity=${r.integrity} signature=${r.signature} `
+ `coversWholeFile=${r.coversWholeFile} docMDP=${r.docMDP}`);
}
}Common Issues and Fixes
Document.Sign() / Document.Certify() throw or hang. Both are
asynchronous — await the call. Forgetting await leaves the returned
promise unresolved and the write happens before signing completes.
A later approval signature invalidates the certification. Sign
incrementally: save the certified bytes first
(certifying.Save()), reopen them with Document.Open(), then call
Sign() on that reopened document — writing a full rewrite instead of an
incremental append breaks the certification’s /ByteRange digest.
VerifySignatures() reports coversWholeFile: false for the first
signature but true for the last. This is expected for a certify-then-
sign chain: the certification was signed before the approval was
appended, so only the most recent signature’s /ByteRange extends to the
end of the file.
Decryption fails with the right private key. Confirm the certificate
passed to recipient matches the exact certificate the document was
encrypted to in Document.Save()’s recipients list — a certificate
reissued with a new key pair will not decrypt data encrypted under the
old one.
Frequently Asked Questions
Can a document be encrypted to more than one recipient?
Yes — recipients in Document.Save()’s encrypt option accepts an
array; any recipient’s matching private key can open the resulting file.
What signature format does Document.Sign() produce?
Passing subFilter: 'PAdES' in the sign options produces a PAdES-compatible
signature; omitting it uses the library’s default signature subfilter.
How do I check whether a document is certified versus just signed?
Inspect the docMDP field on the SignatureReport returned by
Document.VerifySignatures() — a certification signature reports a
DocMDP permission verdict; an approval-only signature does not.
Are recovered Permissions after Document.Open() enforced by the library?
No — opened.Permissions reports the permission flags recorded in the
encrypted file for inspection; enforcing them in an application is the
caller’s responsibility.