DEV Community

Allen Yang
Allen Yang

Posted on

How to Add a Digital Signature to a PDF File Using Python

How to Add a Digital Signature to a PDF File Using Python

When contracts, invoices, reports, and other documents are being circulated, a common concern arises: how can you confirm that a document was indeed issued by a specific signer and that its content has not been tampered with after signing? Digital signatures are the mechanism designed for exactly this purpose. Built on PKI (Public Key Infrastructure) technology, a digital signature binds the signer's identity to the document content — if the document is modified in any way after signing, signature verification will fail.

Compared to manually signing documents one by one in tools like Adobe Acrobat, programmatically processing signatures is far better suited for automated scenarios — for example, system-generated contracts, daily settlement reports, or workflow documents that need to be stamped upon approval. This article will walk you through adding visible signatures, invisible signatures, and timestamped signatures to PDF documents using Python, as well as verifying already-signed documents.

Problems Digital Signatures Solve

Programmatically handling digital signatures is typically driven by the following considerations:

  • Integrity verification: Once a signed document is altered in any way, verification immediately fails, allowing you to detect tampering.
  • Identity authentication: Signatures are based on the holder's certificate (PFX/PKCS#12 file), proving that the document was signed by a specific entity.
  • Batch automation: Approval systems and settlement systems can automatically sign documents at the time of generation, with no manual intervention required.
  • Long-term verifiability: When combined with a timestamp service, it can be proven that the signing occurred while the certificate was still valid, even if the certificate has since expired.

Environment Setup

For working with PDF signatures in Python, you can use Spire.PDF for Python, which can be installed via pip:

pip install Spire.Pdf
Enter fullscreen mode Exit fullscreen mode

In addition to the library itself, you will need a digital certificate file for signing, typically in .pfx (or .p12) format, along with its corresponding password. Certificates can be issued by a Certificate Authority (CA), or you can use self-signed certificates during the testing phase.

Adding a Visible Digital Signature

A visible signature renders a signature field on the page, displaying information such as the signer, reason, location, and more. This is ideal for scenarios where readers need to clearly see that the document has been signed.

The core object is PdfOrdinarySignatureMaker: it takes the PDF document, the certificate file path, and the certificate password, and performs the signing operation. The visual appearance of the signature is configured separately through PdfSignatureAppearance.

from spire.pdf import *

# Load the PDF document
doc = PdfDocument()
doc.LoadFromFile("SampleB_1.pdf")

# Create a signature maker using the certificate file and password
signatureMaker = PdfOrdinarySignatureMaker(doc, "Jerry.pfx", "e-iceblue")

# Configure signature metadata
signature = signatureMaker.Signature
signature.Name = "Jerry"
signature.ContactInfo = "555-123-4567"
signature.Location = "New York"
signature.Reason = "Signed by the document owner"

# Configure signature appearance
appearance = PdfSignatureAppearance(signature)
appearance.NameLabel = "Signer: "
appearance.ContactInfoLabel = "Contact: "
appearance.LocationLabel = "Location: "
appearance.ReasonLabel = "Reason: "
appearance.SignatureImage = PdfImage.FromFile("logo.png")
appearance.GraphicMode = GraphicMode.SignImageAndSignDetail

# Draw the signature field at the specified position on the first page: x, y, width, height
signatureMaker.MakeSignature("Signer:", doc.Pages.get_Item(0), 90.0, 550.0, 270.0, 90.0, appearance)

doc.SaveToFile("DigitalSignature.pdf")
doc.Dispose()
Enter fullscreen mode Exit fullscreen mode

There are a few key points worth noting:

  • The Name, Reason, Location, and other properties set on the Signature object are written into the signature object itself. PDF readers read these values when displaying signature details.
  • GraphicMode determines what the signature field displays. SignImageAndSignDetail means both an image (such as a company logo) and text information are shown; you can also choose to display only the image or only the text.
  • The coordinate parameters in MakeSignature are measured in points, with the origin at the bottom-left corner of the page. The last four numbers correspond to the left boundary, bottom boundary, width, and height of the signature field, respectively.

Adding an Invisible Signature

In some scenarios, you may not want a visible signature field on the page — you only need to sign the document at the document level to ensure integrity. In such cases, you can create an invisible signature without appearance parameters.

from spire.pdf import *

doc = PdfDocument()
doc.LoadFromFile("SampleB_1.pdf")

# Create a signature maker
signatureMaker = PdfOrdinarySignatureMaker(doc, "Jerry.pfx", "e-iceblue")

# Pass only the signature field name without setting appearance — this creates an invisible signature
signatureMaker.MakeSignature("signName")

doc.SaveToFile("AddInvisibleSignature.pdf")
doc.Dispose()
Enter fullscreen mode Exit fullscreen mode

Invisible signatures provide the same tamper-proof capabilities. PDF readers can still detect them in the signature panel; they simply do not display any visible marker on the page.

Adding a Timestamped Signature

All digital certificates have an expiration date. If you need to prove that "the signing occurred while the certificate was still valid," you need to integrate a trusted Timestamp Authority (TSA). The Security_PdfSignature class provides the ConfigureTimestamp method for specifying the TSA service URL.

from spire.pdf import *

doc = PdfDocument()
doc.LoadFromFile("SampleB_1.pdf")

# Create a signature object with a page reference
signature = Security_PdfSignature(doc, doc.Pages.get_Item(0), "Jerry.pfx", "e-iceblue", "signature")

# Set the position and size of the signature field
signature.Bounds = RectangleF(PointF(90.0, 550.0), SizeF(180.0, 90.0))
signature.NameLabel = "Digitally signed by: Jerry"
signature.Reason = "Ensuring document authenticity"

# Restrict post-signing operations: allow form filling only, forbid other modifications
signature.DocumentPermissions = PdfCertificationFlags.AllowFormFill.value | PdfCertificationFlags.ForbidChanges.value

# Configure the trusted timestamp service
signature.ConfigureTimestamp("https://freetsa.org/tsr")

doc.SaveToFile("SignedByTimestamp.pdf")
doc.Dispose()
Enter fullscreen mode Exit fullscreen mode

DocumentPermissions is a practical property here — it restricts post-signing operations through a certification signature. The combination in this example means "allow continued form field filling, but forbid any other changes," making it suitable for form-type documents that still need to collect information after approval while preventing content from being tampered with.

Verifying Signed Documents

Once you have a signed document, you can iterate through the signature fields in its form and verify each signature individually.

from spire.pdf import *

doc = PdfDocument()
doc.LoadFromFile("SignedDocument.pdf")

# Access the document form
formWidget = PdfFormWidget(doc.Form)

if formWidget.FieldsWidget.Count > 0:
    for i in range(formWidget.FieldsWidget.Count):
        field = formWidget.FieldsWidget.get_Item(i)
        if isinstance(field, PdfField):
            signatureField = PdfSignatureFieldWidget(field)
            # Verify the corresponding signature using the field's full name
            valid = doc.VerifySignature(signatureField.FullName)
            print("Signature is valid" if valid else "Signature is invalid")

doc.Dispose()
Enter fullscreen mode Exit fullscreen mode

VerifySignature recalculates the document content digest and compares it against the value recorded in the signature — if the document has been modified after signing, the result will be invalid. This is the final step that fulfills the "tamper-proof" promise of digital signatures.

Practical Tips

  • Do not hardcode certificate passwords: In the examples, passwords are written directly in the code for demonstration purposes. In production, they should be read from environment variables or a key management service.
  • Coordinate system: Signature field coordinates use the bottom-left corner of the page as the origin, with the y-axis increasing upward — the opposite of typical screen coordinates. Keep this in mind when positioning signature fields.
  • Signing order: A document can contain multiple signatures. Each subsequent signature incorporates all previous signatures into its verification scope, so the signing order affects the verification logic.
  • Release resources promptly: After processing, call Dispose() to release file handles held by the document, preventing file-locking issues in batch tasks.

Conclusion

This article covered four common operations related to PDF digital signatures: visible signatures, invisible signatures, timestamped signatures, and signature verification. All of them are built on the binding between a certificate file and the document content — PdfOrdinarySignatureMaker handles standard signing, Security_PdfSignature extends it with timestamping and permission control, and VerifySignature completes the verification loop.

Building on this foundation, you can further integrate form fields, document permissions, and Long-Term Validation (LTV) capabilities to create automated signing solutions tailored for contract management, approval workflows, and similar scenarios.

Top comments (0)