How to Add Multiple Signatures on a PDF Document Using UniPDF Adding multiple signatures to a PDF document is essential for documents that require approval from multiple parties. Whether you need to sign a contract, an agreement, or any other official document, having multiple signatures on a PDF is a must for a seamless and legally binding process.

In this guide, we’ll show you how to add multiple signatures on a PDF using UniPDF, a powerful and flexible PDF processing library. The steps below explain how to append multiple signature fields to a PDF, including code samples to make the process clear and straightforward.

Why Add Multiple Signatures on a PDF?

Adding multiple signatures on a PDF is often necessary for documents that require multiple levels of approval or validation. This can include contracts, agreements, legal documents, or any paperwork that involves more than one signer.

Here’s why you might need to add multiple signatures:

  • Legal Compliance: Documents with multiple signers may be legally binding, ensuring that all involved parties agree to the terms.

  • Multi-Step Approval: Some documents go through several stages of review and approval, requiring different signers at each step.

  • Team Collaboration: Business documents may need to be signed by different team members across departments, ensuring proper collaboration.

If you’re wondering how to add multiple signature blocks to a PDF or get additional signatures on a document, the steps below will help you achieve that.

Setting Up Your Environment

Before diving into the process of adding multiple signatures, make sure you have the necessary environment set up. The following steps will guide you through the setup:

1. Get Your API Key

To use the UniPDF SDK, you need an API key from your UniCloud account. This key allows you to access the functionalities provided by the library. Make sure to sign up on the UniCloud website and get your API credentials.

2. Set Up a Local Development Environment

If this is your first time using UniPDF SDK, you’ll need to set up a local development environment. Follow the steps below to clone the project repository and configure the necessary environment variables.

3. Clone the Project Repository

In your terminal, run the following command to clone the UniPDF examples repository:

git clone https://github.com/unidoc/unipdf-examples.git

Navigate to the signatures folder within the cloned repository:

cd unipdf-examples/signatures

4. Configure Environment Variables

Set your license key using the following command. Replace UNIDOC_LICENSE_API_KEY with your actual API key:

For Linux/Mac:

export UNIDOC_LICENSE_API_KEY=PUT_YOUR_API_KEY_HERE

For Windows:

set UNIDOC_LICENSE_API_KEY=PUT_YOUR_API_KEY_HERE

How to Add Multiple Signatures on a PDF Using UniPDF

To add multiple signatures to a PDF document, we will use Go programming language along with UniPDF. Here, we provide a step-by-step guide to achieving this.

Step 1: Understand How the Code Works

The code provided below showcases how to append a new page with a signature to a PDF document. It utilizes a private/public key pair to sign the file.

Code Overview

package main

import (
    "bytes"
    "crypto/rand"
    "crypto/rsa"
    "crypto/x509"
    "crypto/x509/pkix"
    "fmt"
    "io/ioutil"
    "log"
    "math/big"
    "os"
    "time"

    "github.com/unidoc/unipdf/v3/common/license"
    "github.com/unidoc/unipdf/v3/annotator"
    "github.com/unidoc/unipdf/v3/core"
    "github.com/unidoc/unipdf/v3/model"
    "github.com/unidoc/unipdf/v3/model/sighandler"
)

The code snippet above imports the necessary packages for creating a signature and appending it to a PDF document.

Step 2: Initialize the UniPDF Library

The following function ensures that your API key is set up before using the UniPDF library:

func init() {
    err := license.SetMeteredKey(os.Getenv(`UNIDOC_LICENSE_API_KEY`))
    if err != nil {
        panic(err)
    }

}

This code authenticates the UniPDF library requests by loading the API key from the system environment.

Step 3: Add a Signature to the PDF Document

The main function handles the signing process:

func main() {
    args := os.Args
    if len(args) < 3 {
        log.Fatalln("Usage: go run pdf_sign_twice_visible_annotation INPUT_PDF_PATH OUTPUT_PDF_PATH")
    }

    inputPath := args[1]
    outputPath := args[2]

    f, err := os.Open(inputPath)
    if err != nil {
        log.Fatalf("Fail: %v\n", err)
    }

    defer f.Close()
    pdfReader, err := model.NewPdfReader(f)
    if err != nil {
        log.Fatalf("Fail: %v\n", err)
    }

    // Add the first signature
    buf, err := addSignature(pdfReader, 0)

    if err != nil {
        log.Fatalf("Fail: %v\n", err)
    }

    // Read the updated document
    pdfReader, err = model.NewPdfReader(bytes.NewReader(buf))
    if err != nil {
        log.Fatalf("Fail: %v\n", err)

    }

    // Add the second signature
    buf, err = addSignature(pdfReader, 1)
    if err != nil {
        log.Fatalf("Fail: %v\n", err)
    }

    // Save the signed PDF
    err = ioutil.WriteFile(outputPath, buf, 0666)
    if err != nil {
        log.Fatalf("Fail: %v\n", err)
    }

    log.Printf("PDF file successfully saved to output path: %s\n", outputPath)
}

The code above adds two signatures to the PDF document by calling the addSignature function twice, which signs the document and then saves it.

Step 4: Adding the Signature Using addSignature

The addSignature function adds a signature field to the PDF:

func addSignature(pdfReader \*model.PdfReader, signNumber int) ([]byte, error) {
    totalPage, err := pdfReader.GetNumPages()
    if err != nil {
        log.Fatalf("Fail: %v\n", err)
    }

    appender, err := model.NewPdfAppender(pdfReader)
    if err != nil {
        return nil, err
    }

    priv, cert, err := generateSigKeys()
    if err != nil {
        return nil, err
    }

    handler, err := sighandler.NewAdobePKCS7Detached(priv, cert)
    if err != nil {
        return nil, err
    }

    signature := model.NewPdfSignature(handler)
    signature.SetName("Test Signature Appearance Name")
    signature.SetReason("TestSignatureAppearance Reason")
    signature.SetDate(time.Now(), "")
    if err := signature.Initialize(); err != nil {
        return nil, err
    }

    opts := annotator.NewSignatureFieldOpts()
    opts.FontSize = 8
    opts.Rect = []float64{float64(50 + signNumber*100), 250, float64(150 + signNumber*100), 300}
    opts.TextColor = model.NewPdfColorDeviceRGB(255, 0, 0)

    sigField, err := annotator.NewSignatureField(
        signature,
        []\*annotator.SignatureLine{
            annotator.NewSignatureLine("Name", "John Doe"),
            annotator.NewSignatureLine("Date", "2024.10.15"),
            annotator.NewSignatureLine("Reason", fmt.Sprintf("Test sign #%d", signNumber)),
            annotator.NewSignatureLine("Location", "London"),
        },
        opts,
    )

    if err != nil {
        return nil, err
    }

    sigField.T = core.MakeString(fmt.Sprintf("New Page Signature %d", signNumber))
    if err = appender.Sign(totalPage, sigField); err != nil {
        log.Fatalf("Fail: %v\n", err)
    }

    buf := &bytes.Buffer{}
    if err = appender.Write(buf); err != nil {
        return nil, err
    }

    return buf.Bytes(), nil
}

Step 5: Generating Signature Keys

The generateSigKeys function creates a private/public key pair:

func generateSigKeys() (*rsa.PrivateKey, *x509.Certificate, error) {
    var now = time.Now()
    priv, err := rsa.GenerateKey(rand.Reader, 2048)
    if err != nil {
        return nil, nil, err
    }

    template := x509.Certificate{
        SerialNumber: big.NewInt(1),
        Subject: pkix.Name{
            CommonName:   "any",
            Organization: []string{"Test Company"},
        },
        NotBefore: now.Add(-time.Hour),
        NotAfter:  now.Add(time.Hour _ 24 _ 365),
        KeyUsage:              x509.KeyUsageDigitalSignature,
        ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
        BasicConstraintsValid: true,
    }

    certData, err := x509.CreateCertificate(rand.Reader, &template, &template, priv.Public(), priv)
    if err != nil {
        return nil, nil, err
    }

    cert, err := x509.ParseCertificate(certData)
    if err != nil {
        return nil, nil, err
    }

    return priv, cert, nil
}

Step 6: Run the Code

To run the code and add multiple signatures to a PDF, use the command below:

go run pdf_sign_twice_visible_annotation.go sample.pdf signed_sample.pdf

Replace sample.pdf with the path of your input file and signed_sample.pdf with the desired output file name.

Conclusion

Adding multiple signatures to a PDF using UniPDF and Go language is straightforward. By following the steps above, you can successfully implement a solution that allows for multiple levels of approval in your PDF documents. This method ensures legal compliance, ease of collaboration, and proper document management.