Blog Post

How to Add Digital Signatures to PDFs Using Angular

Hulya Karakaya
Illustration: How to Add Digital Signatures to PDFs Using Angular

In this blog post, you’ll learn how to sign PDF documents with Angular and PSPDFKit for Web, using digital signatures to make sure your documents stay safe and reliable, especially when they’re particularly important — like legal contracts and official records.

PSPDFKit Angular Digital Signature Library

PSPDFKit offers a range of essential capabilities for PDF signing. It streamlines the process of creating and validating electronic signatures, which encompass a range of signature types, such as hand-drawn, scanned, and typed signatures. While it’s important to note that electronic signature are, in essence, distinct from traditional digital signatures, their visual representations can serve as the appearance for a digital signature. An example illustrating this concept can be found in our demo.

The ability to store signatures locally or remotely enhances convenience, while automated workflows can be triggered based on signature actions. PSPDFKit allows for user interface (UI) customization, ensuring a seamless user experience, and it supports client-side signing, eliminating the need for a dedicated server. Additionally, it can be extended to include forms, annotations, and other PDF-related functionalities, making it a versatile tool for various document tasks.

Signature Support

PSPDFKit offers two types of signatures: electronic signatures and digital signatures.

  1. Electronic signatures allow users to create signatures with ink drawings, bitmap images, or text. Our Electronic Signatures component provides a user-friendly interface, supporting draw, image, and type signature modes, and it enables signature storage for reuse.

  2. Digital signatures, on the other hand, are signed with certificates, offering reliable proof of a document’s origin and protection against unauthorized changes. While distinct, these signature types can be used together for a comprehensive signing solution.

PSPDFKit’s Angular PDF Library

We offer a commercial Angular PDF viewer library that can easily be integrated into your web application. It comes with 30+ features that let you view, annotate, edit, and sign documents directly in your browser. Out of the box, it has a polished and flexible UI that you can extend or simplify based on your unique use case.

  • A prebuilt UI — Save time with a well-documented list of APIs when customizing the UI to meet your exact requirements.
  • Annotation tools — Draw, circle, highlight, comment, and add notes to documents with 15+ prebuilt annotation tools.
  • Multiple file types — Support client-side viewing of PDFs, MS Office documents, and image files.
  • 30+ features — Easily add features like PDF editing, digital signatures, form filling, real-time document collaboration, and more.
  • Dedicated support — Deploy faster by working 1-on-1 with our developers.

Requirements to Get Started

To get started, you’ll need:

Information

When you install Node.js, npm is installed by default.

Setup

Go to your terminal and install the Angular CLI. This will help you get up and running quickly with Angular:

npm install -g @angular/cli

Now, check the version of Angular:

ng version

Creating a New Angular Project

Now you’ll see how to integrate PSPDFKit into your Angular project.

First, create a new Angular project for PSPDFKit integration:

ng new pspdfkit-web-example-angular

This will ask some configuration questions. Choose No for routing and CSS for the stylesheet.

Now, change your directory to this project:

cd pspdfkit-web-example-angular

Adding PSPDFKit

Install pspdfkit as a dependency with npm or yarn:

npm install pspdfkit
yarn add pspdfkit

Now, add the following to your angular.json file. Angular will copy the PSPDFKit library assets to the assets directory before running your app:

"assets": [
 "src/favicon.ico",
	"src/assets",
+   {
+  	"glob": "**/*",
+		"input": "./node_modules/pspdfkit/dist/pspdfkit-lib/",
+		"output": "./assets/pspdfkit-lib/"
+	}
]

Displaying the PDF

Add the PDF document you want to display to the src/assets directory. You can use our demo document as an example.

  1. Replace the contents of app.component.html with:

<div class="app">
	<div class="toolbar">
		<img class="logo" src="/favicon.ico" height="32" />

		PSPDFKit Angular Application
	</div>

	<!-- We'll mount the PSPDFKit UI to this element. -->
	<div class="pspdfkit-container"></div>
</div>
  1. Replace the contents of app.component.ts with:

import { Component } from "@angular/core";
import PSPDFKit from "pspdfkit";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["app.component.css"],
})
export class AppComponent {
  title = "PSPDFKit for Web Angular Example";

  ngAfterViewInit(): void {
    PSPDFKit.load({
		// Use the assets directory URL as a base URL. PSPDFKit will download its library assets from here.
      baseUrl: location.protocol + "//" + location.host + "/assets/",
      document: "/assets/example.pdf",
      container: ".pspdfkit-container",
      licenseKey: "YOUR_LICENSE_KEY_GOES_HERE", // Optional license key.
    }).then((instance) => {
      // For the sake of this demo, store the PSPDFKit for Web instance
      // on the global object so that you can open the dev tools and
      // play with the PSPDFKit API.

      (<any>window).instance = instance;
    });
  }
}

The license key is optional; however, you may see a watermark on your PDF files without a key. To get a key, contact Sales.

If you try to run your project, you may get an error stating the mounting container has no height. To fix this issue, add the following styles to the src/app/app.component.css file:

:host {
	height: 100%;
}

.app {
	position: fixed;
	width: 100%;
	height: 100%;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
}

.toolbar {
	position: relative;
	display: flex;
	align-items: center;
	height: 64px;
	width: 100%;
	padding: 0 24px;
	box-shadow: 0 1px 0 rgba(0, 0, 0, 0.1);
	font-family: sans-serif;
	font-size: 20px;
	font-weight: 500;
	color: rgba(0, 0, 0, 0.8);
}

.logo {
	margin-right: 20px;
}

.pspdfkit-container {
	height: calc(100% - 64px);
}
Information

You can access the project on GitHub.

  1. Start the app and open it in your default browser:

npm start
yarn start

Adding a Digital Signature to a PDF Using PSPDFKit

PSPDFKit requires an X.509 certificate and a private key pair for adding a digital signature to a PDF document. The steps below outline how to do this.

Step 1 — Generating a Self-Signed Certificate and Private Key

You can generate a self-signed certificate and private key using OpenSSL, which is a widely used tool for working with certificates and keys.

  1. Open your terminal in the project directory.

  2. Run the following OpenSSL command to generate a self-signed certificate and private key:

openssl req -x509 -sha256 -nodes -newkey rsa:2048 -keyout private-key.pem -out cert.pem
  • -x509 — Tells OpenSSL to create a self-signed certificate.

  • -sha256 — Specifies the hash function to use for the certificate.

  • -nodes — Prevents encryption of the private key. You can remove this option for production keys if encryption is desired.

  • -newkey rsa:2048 — Generates a new RSA private key with a key size of 2,048 bits.

  • -keyout private-key.pem — Specifies the name of the private key file.

  • -out cert.pem — Specifies the name of the certificate file.

Follow the prompts to provide information for the certificate, such as the Common Name (CN), organization, and location. These details will be embedded in the certificate.

Information

Self-signed certificates should only be used for development and testing purposes. In production environments, it’s crucial to obtain a certificate from a trusted Certificate Authority (CA) to ensure the security and authenticity of your application.

Step 2 — Verifying Your Certificate

After generating the certificate and private key, you can verify if the certificate is correctly PEM-encoded using the following command:

openssl pkcs7 -noout -text -print_certs -in cert.pem

This command will display certificate details and shouldn’t produce any errors. It confirms that “cert.pem” is a PEM-encoded X.509 certificate.

Alternatively, if you want to verify DER-encoded certificates, you can use the following command:

openssl pkcs7 -inform der -noout -text -print_certs -in cert.pem

This command checks if “cert.pem” is a DER-encoded PKCS#7 certificate.

With these steps, you’ll have generated the required X.509 certificate and private key pair for adding digital signatures to your PDF documents. Be certain to store these files securely, as they’re essential for signing documents.

For more information on adding a digital signature to a PDF using PSPDFKit, refer to our digital signatures guide.

Signing a PDF Document Using PSPDFKit

To add a digital signature to your PDF document using PSPDFKit, follow the steps outlined below.

Step 1 — Installing the Forge Library

  1. Install the Forge library using npm. Open your terminal, navigate to the project directory, and run the following command:

npm install node-forge
npm i --save-dev @types/node-forge
  1. Import the Forge library in your app.component.ts file:

import * as forge from 'node-forge';

Step 2 — Generating the PKCS#7 Signature

PSPDFKit utilizes the cryptographic Distinguished Encoding Rules (DER) PKCS#7 format for digital signatures. You’ll need to create a valid PKCS#7 signature containing your certificate and other relevant information.

Define a function, generatePKCS7, to generate the digital signature for your PDF. This function will perform the necessary cryptographic operations:

function generatePKCS7({
	fileContents,
}: {
	fileContents: ArrayBuffer | null,
}): Promise<ArrayBuffer> {
	// Fetch the certificate and private key.
	const certificatePromise = fetch('cert.pem').then((response) =>
		response.text(),
	);
	const privateKeyPromise = fetch('private-key.pem').then((response) =>
		response.text(),
	);

	return new Promise((resolve, reject) => {
		Promise.all([certificatePromise, privateKeyPromise])
			.then(([certificatePem, privateKeyPem]) => {
				// Parse the certificate and private key using Forge.js.
				const certificate = forge.pki.certificateFromPem(
					certificatePem,
				);
				const privateKey = forge.pki.privateKeyFromPem(
					privateKeyPem,
				);

				// Create a PKCS7 signature.
				const p7 = forge.pkcs7.createSignedData();
				if (!fileContents) {
					throw new Error('No file contents provided.');
				}
				const buffer = forge.util.createBuffer(fileContents);
				p7.content = buffer.getBytes();
				p7.addCertificate(certificate);

				// Add the signer information.
				p7.addSigner({
					key: privateKey,
					certificate: certificate,
					digestAlgorithm: forge.pki.oids['sha256'],
					authenticatedAttributes: [
						{
							type: forge.pki.oids['contentType'],
							value: forge.pki.oids['data'],
						},
						{
							type: forge.pki.oids['messageDigest'],
						},
						{
							type: forge.pki.oids['signingTime'],
							value: new Date().toISOString(),
						},
					],
				});

				// Sign the data.
				p7.sign({ detached: true });

				// Convert the result to an `ArrayBuffer`.
				const result = stringToArrayBuffer(
					forge.asn1.toDer(p7.toAsn1()).getBytes(),
				);

				resolve(result);
			})
			.catch(reject);
	});
}

This function fetches your certificate and private key, and it then uses Forge to create a PKCS#7 signed data structure.

Information

In professional settings, it’s essential to prioritize the security of your private key. While this example simplifies the process by fetching the private key from a file, in practice, you should consider more robust security measures. This includes storing the private key in a secure hardware device and potentially encrypting it. Also, please be aware that the `.pem` file generated with OpenSSL in this example isn’t encrypted, and in production, you should ensure the private key’s protection accordingly.

Step 3 — Converting a String to an Array Buffer

You’ll need a utility function, stringToArrayBuffer, to convert a binary string into an ArrayBuffer:

function stringToArrayBuffer(binaryString: string): ArrayBuffer {
	const buffer = new ArrayBuffer(binaryString.length);
	let bufferView = new Uint8Array(buffer);

	for (let i = 0, len = binaryString.length; i < len; i++) {
		bufferView[i] = binaryString.charCodeAt(i);
	}

	return buffer;
}

Step 4 — Initializing PSPDFKit and Signing the Document

Now, you can initialize PSPDFKit and invoke the PSPDFKit.Instance#signDocument method. This method takes two arguments.

  • Argument 1 — You can use this argument to fine-tune the signing process by providing essential data, such as certificates and private keys. If you don’t have specific signing requirements, you can pass null.

  • Argument 2 — In the second argument, supply fileContents. This parameter is used as a callback object containing an ArrayBuffer housing the document’s content. The method returns a promise that resolves to the ArrayBuffer or is rejected if an error arises:

export class AppComponent {
  title = 'PSPDFKit for Web Angular Example';

  ngAfterViewInit(): void {
    PSPDFKit.load({
      // Use the assets directory URL as a base URL. PSPDFKit will download its library assets from here.
      baseUrl: location.protocol + '//' + location.host + '/assets/',
      document: '/assets/example.pdf',
      container: '.pspdfkit-container',
    })
      .then((instance) => {
        // Store the PSPDFKit instance in a global variable for later use.
        (window as any).instance = instance;

        // Sign the document when PSPDFKit is loaded.
        instance.signDocument(null, generatePKCS7)
          .then(() => {
            console.log('Document signed.');
          })
          .catch((error) => {
            console.error('The document could not be signed.', error);
          });
      })
      .catch((error) => {
        console.error(error.message);
      });
  }
}

This code initiates the signing process. Upon successful completion, you’ll see the message ‘Document signed.’ in the console. In case of errors during the signing process, an error message will be logged.

After successfully building and implementing this code, the signing process will run automatically, and the document will reload with the freshly added digital signature.

Here’s the full code for app.component.ts for your reference:

import { Component } from '@angular/core';
import PSPDFKit from 'pspdfkit';
import * as forge from 'node-forge';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  title = 'PSPDFKit for Web Angular Example';

  ngAfterViewInit(): void {
    PSPDFKit.load({
      // Use the assets directory URL as a base URL. PSPDFKit will download its library assets from here.
      baseUrl: location.protocol + '//' + location.host + '/assets/',
      document: '/assets/example.pdf',
      container: '.pspdfkit-container',
    })
      .then((instance) => {
        // Store the PSPDFKit instance in a global variable for later use.
        (window as any).instance = instance;

        // Sign the document when PSPDFKit is loaded.
        instance.signDocument(null, generatePKCS7)
          .then(() => {
            console.log('Document signed.');
          })
          .catch((error) => {
            console.error('The document could not be signed.', error);
          });
      })
      .catch((error) => {
        console.error(error.message);
      });
  }
}

function generatePKCS7({
  fileContents,
}: {
  fileContents: ArrayBuffer | null;
}): Promise<ArrayBuffer> {
  // Fetch the certificate and private key.
  const certificatePromise = fetch('cert.pem').then((response) =>
    response.text()
  );
  const privateKeyPromise = fetch('private-key.pem').then((response) =>
    response.text()
  );

  return new Promise((resolve, reject) => {
    Promise.all([certificatePromise, privateKeyPromise])
      .then(([certificatePem, privateKeyPem]) => {
        // Parse the certificate and private key using Forge.js.
        const certificate = forge.pki.certificateFromPem(certificatePem);
        const privateKey = forge.pki.privateKeyFromPem(privateKeyPem);

        // Create a PKCS7 signature.
        const p7 = forge.pkcs7.createSignedData();
        if (!fileContents) {
          throw new Error('No file contents provided.');
        }
        const buffer = forge.util.createBuffer(fileContents);
        p7.content = buffer.getBytes();
        p7.addCertificate(certificate);

        // Add the signer information.
        p7.addSigner({
          key: privateKey,
          certificate: certificate,
          digestAlgorithm: forge.pki.oids['sha256'],
          authenticatedAttributes: [
            {
              type: forge.pki.oids['contentType'],
              value: forge.pki.oids['data'],
            },
            {
              type: forge.pki.oids['messageDigest'],
            },
            {
              type: forge.pki.oids['signingTime'],
              value: new Date().toISOString(),
            },
          ],
        });

        // Sign the data.
        p7.sign({ detached: true });

        // Convert the result to an `ArrayBuffer`.
        const result = stringToArrayBuffer(
          forge.asn1.toDer(p7.toAsn1()).getBytes()
        );

        resolve(result);
      })
      .catch(reject);
  });
}

function stringToArrayBuffer(binaryString: string): ArrayBuffer {
  const buffer = new ArrayBuffer(binaryString.length);
  let bufferView = new Uint8Array(buffer);

  for (let i = 0, len = binaryString.length; i < len; i++) {
    bufferView[i] = binaryString.charCodeAt(i);
  }

  return buffer;
}
Information

Interact with the sandbox by clicking the left rectangle icon and selecting Editor > Show Default Layout. To edit, sign in with GitHub — click the rectangle icon again and choose Sign in. To preview the result, click the rectangle icon once more and choose Editor > Embed Preview. For the full example, click the Open Editor button. Enjoy experimenting with the project!

Information

We recently added support for CAdES-based signatures, which are advanced digital signatures. To learn more about them, check out our guide.

Conclusion

In this blog post, you learned how to add digital signatures to PDF documents using Angular and PSPDFKit for Web. If you’re interested in exploring PSPDFKit further, you can request a free trial of our SDK or visit our demo page to experience the capabilities of our product firsthand.

Related Products
Share Post
Free 60-Day Trial Try PSPDFKit in your app today.
Free Trial

Related Articles

Explore more
PRODUCTS  |  Web • Releases • Components

PSPDFKit for Web 2024.3 Features New Stamps and Signing UI, Export to Office Formats, and More

PRODUCTS  |  Web • Releases • Components

PSPDFKit for Web 2024.2 Features New Unified UI Icons, Shadow DOM, and Tab Ordering

PRODUCTS  |  Web

Now Available for Public Preview: New Document Authoring Experience Provides Glimpse into the Future of Editing