Skip to content

Digital signatures overview ​

This topic covers the general steps to sign and verify PDFs, related APIs, how to try signing with the built-in workflow, and HTTP signature services provided for testing only.

Foxit PDF SDK for Web 11.0.0 and later

Signing and verification steps ​

When signing and verifying PDFs, follow this model:

  • Sign a document
  1. Produce a file stream that includes the signature byteRange (see the PDF specification).
  2. Compute a digest over the byteRange and obtain signedData through PKI or a signing service.
    • For programmatic signing, implement the digest/sign callback in PDFDoc.sign(signInfo, digestSignHandler);
    • For the built-in signing UI (11.0+), register signing logic and appearance with SignatureWorkflowService addSignerInfo and addSignatureAPInfo.
  3. Write signedData into the positions defined by byteRange in the stream. The SDK handles most PDF structure; you provide signing implementation and optional appearance.
  • Verify a signature
  1. Obtain original file bytes, the signature byteRange, signedData, and metadata such as signer.
  2. When your app initiates verification, use PDFDoc.verifySignature(signatureField, verifyHandler) with an explicit verifyHandler.
  3. For verification triggered by the built-in UI or JavaScript actions, configure a global handler with pdfViewer.getSignatureService().setVerifyHandler(...) (see Signature service).

Tip: PDFDoc.verifySignature does not use that global handler automatically unless you wire it in your callback.

Digital signature APIs ​

Programmatic signing and verification: PDFDoc.sign and PDFDoc.verifySignature ​

Without relying on PDFUI helpers, this is the main way to sign and verify from application code.

PDFDoc.sign(signInfo, digestSignHandler) ​

Signs the document. Provide a digest/sign handler that returns signed data (usually from your backend).

js
/**
 * @returns {Blob} - File stream of the signed document.
 */
const signResult = await pdfdoc.sign(signInfo, (signInfo, plainContent) => {
  return Promise.resolve(getSignData(signInfo, plainContent)); // plainContent is a Blob
});

PDFDoc.verifySignature(signatureField, verifyHandler) ​

Verifies a signature. The callback receives the signature field, plain content, signed data, and whether content exists outside the signed range.

js
/**
 * @returns {number} - Signature status.
 */
const result = await signedPDF.verifySignature(
  pdfform.getField("Signature_0"),
  async (signatureField, plainBuffer, signedData, hasDataOutOfScope) => {
    const signInfo = {
      byteRange: await signatureField.getByteRange(),
      signer: await signatureField.getSigner(),
      filter: await signatureField.getFilter(),
      subfilter: await signatureField.getSubfilter(),
    };
    return verifySignData(signInfo, plainBuffer, signedData, hasDataOutOfScope);
  }
);

Built-in UI: SignatureWorkflowService (11.0+) ​

Use pdfui.getSignatureWorkflowService() to register signers (including the sign callback) and signature appearance entries for the default signing dialog.

Foxit PDF SDK for Web commonly supports two signature subfilter values: adbe.pkcs7.detached and adbe.pkcs7.sha1.

  • With adbe.pkcs7.detached, digest algorithms are often 'sha1', 'sha256', or 'sha384' (depends on your backend).
  • With adbe.pkcs7.sha1, the digest algorithm is 'sha1'.

Example: adbe.pkcs7.detached + SHA-256

js
const workflow = pdfui.getSignatureWorkflowService();
workflow.addSignerInfo({
  filter: "Adobe.PPKLite",
  subfilter: "adbe.pkcs7.detached",
  signer: "web sdk",
  sign: async (setting, plainContent) => {
    return requestData(
      "post",
      "http://localhost:7777/digest_and_sign",
      "arraybuffer",
      {
        subfilter: setting.subfilter,
        md: "sha256", // "sha1" | "sha256" | "sha384"
        plain: plainContent,
      }
    );
  },
});
workflow.addSignatureAPInfo({
  title: "Standard detached SHA256",
  distinguishName: "[email protected]",
  location: "FZ",
  reason: "Test",
  flag: 0x100,
  showTime: true,
});

Example: adbe.pkcs7.sha1

js
const workflow = pdfui.getSignatureWorkflowService();
workflow.addSignerInfo({
  filter: "Adobe.PPKLite",
  subfilter: "adbe.pkcs7.sha1",
  signer: "web sdk",
  sign: async (signInfo, plainContent) => {
    const digest = getDigest(plainContent);
    const signData = sign(digest);
    return signData;
  },
});
workflow.addSignatureAPInfo({
  title: "Standard SHA1",
  distinguishName: "[email protected]",
  location: "FZ",
  reason: "Test",
  flag: 0x100,
  showTime: true,
});

Tips:

  • In the current list, each addSignerInfo signer string and each addSignatureAPInfo title must be unique.
  • For overrideSigningWorkflow, overrideVerifyWorkflow, and signer display policy, see Signature workflow.

Global verification: SignatureService.setVerifyHandler (11.0+) ​

For the viewer’s default verification path (for example user-initiated verify or script-triggered verify), get the service from PDFViewer and register a callback.

js
const pdfViewer = await pdfui.getPDFViewer();
const signatureService = pdfViewer.getSignatureService();
signatureService.setVerifyHandler(
  async (signatureField, plainContent, signedData, hasDataOutOfScope) => {
    const filter = await signatureField.getFilter();
    const subfilter = await signatureField.getSubfilter();
    const signer = await signatureField.getSigner();
    const digest = getDigest(plainContent);
    return verify(filter, subfilter, signer, digest, signedData, hasDataOutOfScope);
  }
);

Tips:

PDFSignature class ​

  • PDFSignature.isSigned() — Whether the signature field is signed.
  • PDFSignature.getByteRange() — File byte range covered by the signature.
  • PDFSignature.getFilter() / getSubfilter() — Signature filter and subfilter.

Depending on version and context, some getters may be async; use await in async callbacks.

Deprecated: PDFUI.registerSignHandler / PDFUI.setVerifyHandler ​

Since 11.0.0, these methods remain for compatibility and delegate to SignatureWorkflowService and SignatureService. Do not use them in new projects.

js
// Deprecated — equivalent to SignatureWorkflowService + addSignerInfo / addSignatureAPInfo
pdfui.registerSignHandler({ /* ... */ });

// Deprecated — equivalent to pdfViewer.getSignatureService().setVerifyHandler(...)
pdfui.setVerifyHandler(/* ... */);

Try digital signatures ​

Use the API or built-in UI. The package includes a Node.js sample backend at ./server/signature-server-for-win.

Method 1: Place a signature in the current document via code ​

  1. Open https://webviewer-demo.foxitsoftware.com/ and start the signature service.
  2. Run the sample below in the browser console; it creates a signature field and signs.
  3. Open the signed document and click the field to verify (configure verification per method 2 or global verify handler).
js
// Assume the local signature service listens on port 7777.
const pdfviewer = await pdfui.getPDFViewer();
const pdfdoc = await pdfviewer.getCurrentPDFDoc();
const signInfo = {
  filter: "Adobe.PPKLite",
  subfilter: "adbe.pkcs7.sha1",
  rect: { left: 10, bottom: 10, right: 300, top: 300 },
  pageIndex: 0,
  flag: 511,
  signer: "signer",
  reason: "reason",
  email: "email",
  distinguishName: "distinguishName",
  location: "loc",
  text: "text",
};
const signResult = await pdfdoc.sign(signInfo, (signInfo, plainContent) => {
  return requestData(
    "post",
    "http://127.0.0.1:7777/digest_and_sign",
    "arraybuffer",
    { plain: plainContent }
  );
});
const signedPDF = await pdfviewer.openPDFByFile(signResult);
const pdfform = signedPDF.getPDFForm();
const verify = async (signatureField, plainBuffer, signedData, hasDataOutOfScope) => {
  return requestData("post", "http://127.0.0.1:7777/verify", "text", {
    filter: await signatureField.getFilter(),
    subfilter: await signatureField.getSubfilter(),
    signer: await signatureField.getSigner(),
    plainContent: new Blob([plainBuffer]),
    signedData: new Blob([signedData]),
  });
};
await signedPDF.verifySignature(pdfform.getField("Signature_0"), verify);

Method 2: Place a signature with the built-in UI ​

Use https://webviewer-demo.foxitsoftware.com/:

  • Prepare: Open the online viewer in a browser.
  • Add and sign: On the Form tab, use the signature tool, drag a rectangle on the page, switch to the hand tool (or press Esc), and complete the dialog.
  • Verify: With the hand tool, click a signed signature field.

To connect the built-in UI to your backend, register with SignatureWorkflowService and SignatureService. Typical code (similar to requestData in index.html; replace origin with your service base URL):

js
const pdfViewer = await pdfui.getPDFViewer();
const signatureService = pdfViewer.getSignatureService();
signatureService.setVerifyHandler(async (signatureField, plainBuffer, signedData) => {
  return requestData("post", "origin", "text", {
    filter: await signatureField.getFilter(),
    subfilter: await signatureField.getSubfilter(),
    signer: await signatureField.getSigner(),
    plainContent: new Blob([plainBuffer]),
    signedData: new Blob([signedData]),
  });
});

const workflow = pdfui.getSignatureWorkflowService();
workflow.addSignerInfo({
  filter: "Adobe.PPKLite",
  subfilter: "adbe.pkcs7.sha1",
  signer: "web sdk",
  sign: async (setting, plainContent) => {
    return requestData("post", "origin", "arraybuffer", {
      plain: plainContent,
    });
  },
});
workflow.addSignatureAPInfo({
  title: "Demo appearance",
  distinguishName: "[email protected]",
  location: "FZ",
  reason: "Test",
  flag: 0x100,
  showTime: true,
});

HTTP signature services for testing ​

If you have no backend, use these addresses for testing only: