Sign PDF with Plain JavaScript

digitally sign pdf in browser

I think you should take a look at DigiSigner. It is a PDF viewer with digital signature functionality. It is implemented in java, so it can run also as an applet in the browser on the client's side. There are demos, which does exactly what you need.

Digitally Signing a PDF in Modern Firefox/Chrome/Edge Browsers

This answer aims at workarounds, rather than actual answers.

This is because there's no API in the browser at the moment you could use to obtain smart card certificate's private key and use it. This has been supposedly discussed in the Web Crypto API and as far as I remember - the consensus was this should not be supported for security reasons (which I stronly disagree!).

You, as hundreds or thousands other developers (us included), are out of luck.

First workaround involves a .NET ClickOnce desktop app that is deployed at the server and run from the server. The app gets the security context of the current user session in runtime arguments so that the session is shared between the browser and the app that runs beside the browser. In this sense, running this app independently (without the session in the browser) would cause authorization issues during the communication with the server.

The app uses server's APIs to first retrieve the document user is about to sign. Then then app uses the local certificate store with no restrictions (as it's a regular desktop app), encrypts the document and sends it back to the server.

Pros: ClickOnce apps can be invoked from within the browser.

Cons: this requires .NET runtime at the client.

Second workaround involves a Java desktop app that is installed independently at the client's machine. You provide install packages for selected OSes (say Windows, Linux, MacOS), the user downloads the install package and installs the app in their OS.

Then, when the browser is supposed to sign a document, you provide an instruction that tells the user to run the app in the background. The app, when run, exposes an HTTP listener on a localhost and fixed port with two services

  • a push service that accepts the document data to be signed
  • a pull service that exposes the signed document, when it's available

As you guess, it's the browser that does the request, the browser makes a request to the localhost:port and uploads the document data to the push service. The Java app switches from waiting for the document to signing the document state. The user is supposed to use the app - pick a cert from the store (no restrictions since is a regular Java desktop app) and sign the document. Your browser in the background pings the pull service of the app and when the data is ready, the browser downloads it. Then, the browser uploads the signed document to the actual server, using the actual authenticated session.

There's a potential security hole here, as any local app or any opened web page could ping the pull service and download the document (which of course you don't want). We are aware of two fixes to this.

First, you can have yet another service in the Java app that returns a one-time authentication token (a guid for example) that is meant to be read once and then supplied with every call to the pull service as an authentication token. If any other malicious app or webpage reads the token before your's app web page does, your page will get errors from the pull service (as the one-time token has been apparently stolen and was not available). The web page could signal a communication error here and warn the user of a potential security issue.

Second way to fix the hole involve an argument to the pull service call that is provided by the application server and put in the page's script as a value, a token signed by the server's certificate. Your Java app can have the public key of the server's certificate so that the Java app is able to verify the argument's signature. But no other app (and no other page) will be able to forge the token (as the token's signature's private key is only available at your server) and there's no easy way to steal the valid token from the page's body.

Pros: the Java app could possibly target multiple OSes
Cons: this still requires the Java runtime at the client

Both workarounds are tested in production and both work well for years. I hope this gives you one possible direction your final solution could be based on.

Digital Signature on PDF in laravel, Javascript

I would suggest to use any PDF Viewer Web library to display the PDF in client's browser. There user would be able to draw rectangle using his mouse or any image (If you want, you may put user's scanned signature there... or Text of Signature to be displayed...)

From this, you would have x and y coordiantes on the pdf and height and width of signature.

You may send this back to server where you are creating signature. If you also want to read signature from the client's USB token or smart card connected to his browser, you may use browser extension. For more details on this, please refer to my SO answer https://stackoverflow.com/a/55676351/9659885

Trying to submit PDF form with the image of the signature

According to the JavaScript™ for Acrobat® API Reference from the Adobe® Acrobat® DC SDK:

createDataObject |5.0|D||D|

setDataObjectContents |7.0|||D|

where the D in the fourth column is defined to mean:

The property or method is allowed in Acrobat Pro and Acrobat Standard. It can be accessed in Adobe Reader (version 5.1 or later) depending on additional usage rights that have been applied to the document:

...

● D — Requires file attachment rights

Thus, you apparently will have to Adobe-Reader-enable your PDF (apply usage rights) to make it work in Adobe Reader.



Related Topics



Leave a reply



Submit