Skip to main content Skip to footer

How to Sign PDF Documents in JavaScript Using a Client-Side API

PDF documents are a thing of past, present, and future based on all the significant features offered by this document format. Digital signatures are one feature that lets users add this document format to the legal process. Adding a digital signature to a document validates the document by an authorized signatory.

Usually, a UI tool is required to apply signatures to PDF documents like Adobe Acrobat. GrapeCity Documents PDF Viewer supports signing a PDF document using a UI and a client-side API. You can add graphical signatures using the Signature tool as depicted here or digital signatures using client-side API.

This blog will describe signing a PDF document using client-side API.

Ready to Test it Out? Download GrapeCity Documents PDF Viewer Today!

Let’s start by understanding a basic scenario to be considered in the blog ahead. The image below depicts an employee’s timesheet in PDF format. This document must be signed by both the employee and supervisor to be considered valid. Because this can be a weekly or monthly task, it would be very convenient if the process could be automated and the signatures could be applied through API.

Sign PDF JavaScript

Here is a quick view of the signed version of the timesheet, wherein the signatures have been applied using GcPdfViewer client-side API:

Sign PDF JavaScript

How to sign PDF documents using client-side API

Grapecity Documents PDF Viewer client-side API enhances the functionality the Save method offers to apply a digital signature. This method now includes an optional save settings parameter of type SaveSettingswhich can be used to specify signature settings for saving a document with a signature.

The SaveSettings type has a Sign property of type SignatureInfo which lets you specify the signature settings. The sample code snippet below depicts the same:

viewer.save("test.pdf", { sign: { signatureField: "field1", signerName: "John Doe" } } );

When invoking this method, it sends a request to the server to apply the digital signature and send back the signed document, which is then loaded in GcPdfViewer.

Now, let's move on to understanding how to implement the scenario described using the Save method. The steps below will guide you ahead.

Step 1: Configure Application

1. Open Visual Studio 2022 and create a new ASP. NET Core Web Application, choosing the appropriate project template.

Sign PDF JavaScript

2. Choose .NET Core 6.0 as the project's target framework.

Sign PDF JavaScript

3. Open Package Manager Console choosing Tools → NuGet Package Manager → Package Manager Console. Run the following command to install GcDocs PDF Viewer. Ensure that the directory location in the command prompt is set to the lib folder in the project.

npm install @grapecity/gcpdfviewer

The GcDocs PDF Viewer will be installed in _<app_name>\<app_name>\wwwroot\lib\node_modules_ folder.

Sign PDF JavaScript

Step 2: Add SupportApi to the Project

The SupportApi package, when configured for the project, provides the edit features for GcPdfViewer. Hence, it must be configured to add digital signatures too.

The steps ahead will provide the details.

1. To add SupportApi to the project, install GrapeCity.Documents.Pdf.ViewerSupportApi package using NuGet Package Manager.

Sign PDF JavaScript

GrapeCity.Documents.Pdf.ViewerSupportApi package is added to your project dependencies under the DependenciesPackages folder and can be observed in your project’s solution explorer window as depicted below.

Sign PDF JavaScript

2. Create a 'Controllers' folder in the project folder and add a class file 'SupportApiController.cs' to it as shown below:

Sign PDF JavaScript

3. Replace the code in 'SupportApiController.cs' with the following code snippet:

using GrapeCity.Documents.Pdf.ViewerSupportApi.Controllers;
using Microsoft.AspNetCore.Mvc;

namespace SignPDF.Controllers
{
	[Route("api/pdf-viewer")]
	[ApiController]
	public class SupportApiController : GcPdfViewerController
	{

	}
}

4. Modify the default content of <app_name>\<app_name>\Pages\Index.cshtml with the following code, which connects the server-side SupportApi to the client-side viewer using the SupportApi property.

The code also defines a method to configure the viewer UI to add two buttons, one for applying the employee's signature and another for applying the supervisor's signature. When clicked, these buttons invoke the save method of GcPdfViewer to apply and save the PDF file with the specified signatures. The sign property has multiple fields to define the signature, including signatureField, signerName, and location, as used in the example code below:

@page
@model IndexModel
@{
	ViewData["Title"] = "Home page";
}

<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Sign document using digital signature</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<link rel="stylesheet" href="./src/styles.css">
<style>
	#viewer {
		height: 600px;
		width: 100%;
	}
</style>
<script src="~/lib/node_modules/@@grapecity/gcpdfviewer/gcpdfviewer.js"></script>
<script>
	window.onload = function () {
		//Initialize GcPdfViewer
		var viewer = new GcPdfViewer("#viewer", getViewerOptions());
		
		//Invoke method to configure viewer UI
		configureViewerUI(viewer);
		
		//Load the sample PDF file containing signature fields
		viewer.open("pdf/sign-with-digital-signature.pdf");
	}

	//Define GcPdfViewer options
	function getViewerOptions() {
		return {
			workerSrc: "//node_modules/@@grapecity/gcpdfviewer/gcpdfviewer.worker.js",
			supportApi: {
				apiUrl: "api/pdf-viewer",
				token: "support-api-demo-net-core-token-2023",
				webSocketUrl: false
			},
			restoreViewStateOnLoad: false
		};
	}

	//Define method to configure viewer UI
	//It defines the buttons used to sign PDF document and add them to viewer toolbar 
	function configureViewerUI(viewer) {
		viewer.toggleSidebar(false);
		viewer.toolbar.addItem({
			text: "Apply employee signature", key: 'employee-signature',
			title: 'Apply employee signature', enabled: false,
			action: function () {
				const locationName = location.hostname || "Unknown";
				viewer.save(undefined, { sign: { signatureField: "Employee", signerName: "Employee Name", location: locationName }, reload: true });
			},
			onUpdate: function () {
				return {
					enabled: viewer.hasDocument,
					title: 'Apply employee signature'
				};
			}
		});
		viewer.toolbar.addItem({
			text: "Apply supervisor signature", key: 'supervisor-signature',
			title: 'Apply supervisor signature', enabled: false,
			action: function () {
				const locationName = location.hostname || "Unknown";
				viewer.save(undefined, { sign: { signatureField: "Supervisor", signerName: "Supervisor Name", location: locationName }, reload: true });
			},
			onUpdate: function () {
				return {
					enabled: viewer.hasDocument,
					title: 'Apply supervisor signature'
				};
			}
		});
		viewer.toolbarLayout.viewer.default.mobile = viewer.toolbarLayout.viewer.default = ["employee-signature", "supervisor-signature", "$split", "download", "zoom", "$split", "about"];
	}
</script>

<body>
	<div id="viewer" style="height:700px;"></div>
</body>

Step 3: Server-side Signing Implementation

In this step, we will learn how to implement server-side signing using the steps described below:

1. Modify Program.cs by adding the following lines of code to the default code available on the page. The code below also binds the VerifyToken and Sign events to their respective event handlers::

using GrapeCity.Documents.Pdf.ViewerSupportApi.Connection;
using GrapeCity.Documents.Pdf.ViewerSupportApi.Controllers;
using GrapeCity.Documents.Pdf.ViewerSupportApi.Models;
using ProtoBuf.Meta;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddCors();
GcPdfViewerHub.ConfigureServices(builder.Services);

//Server side signing implementation
var app = builder.Build();
app.UseCors("WebCorsPolicy");
GcPdfViewerController.Settings.VerifyToken += VerifyAuthToken;
GcPdfViewerController.Settings.Sign += OnSign;

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();

#pragma warning disable ASP0014 // Suggest using top level route registrations
IApplicationBuilder applicationBuilder = app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

#pragma warning restore ASP0014 // Suggest using top level route registrations
app.MapRazorPages();
app.Run();

2. Download and place the signing certificate in the project folder → assets folder.

3. Define event handlers for VerifyToken and Sign events:

//Event handler for VerifyToken event
private void VerifyAuthToken(object sender, VerifyTokenEventArgs e)
{
	// Here is an example of how you can validate the authentication token
	// provided during viewer initialization - new GcPdfViewer(selector, { supportApi: { token: "support-api-demo" }});.
	string token = e.Token;
	if (string.IsNullOrEmpty(token) || !token.StartsWith("support-api-demo"))
	{
		e.Reject = true;
	}
}

//Event handler for Sign event
private void OnSign(object sender, SignEventArgs e)
{
	// Example: Implement PDF document signing
    var signatureProperties = e.SignatureProperties;

	string projectRootPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
	string certificatePath = Path.Combine(projectRootPath, "assets/GcPdfTest.pfx");
	byte[] certificateBytes = File.ReadAllBytes(certificatePath);
	if (certificateBytes == null)
	{
		e.Reject = true;
		return;
	}
	X509Certificate2 certificate = new X509Certificate2(
	   certificateBytes, "qq", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
	   signatureProperties.SignatureBuilder = new GrapeCity.Documents.Pdf.Pkcs7SignatureBuilder()
	    {
		   CertificateChain = new X509Certificate2[] { certificate },
		   HashAlgorithm = GrapeCity.Documents.Pdf.Security.OID.HashAlgorithms.SHA512,
		   Format = GrapeCity.Documents.Pdf.Pkcs7SignatureBuilder.SignatureFormat.adbe_pkcs7_detached
		};
}

Step 4: Build and Run the Application

In this final step, we add the sample PDF file to the project folder and execute the application to see the implementation in action.

1. Download and place the sample PDF file in the wwwroot → pdf folder.

2. Build and run the application to view GcDocs PDF Viewer in your browser, which contains the options to apply digital signatures to PDF documents on the client side.

The GIF below depicts the implementation in action:

Sign PDF JavaScript

Download the sample to explore the implementation in detail.

Refer to the demo to explore the same implementation in a pure javascript application.

Ready to Test it Out? Download GrapeCity Documents PDF Viewer Today!

Tags:

comments powered by Disqus