PDFs are among the most widely used formats for business documents, so properly securing them is a critical part of many workflows. If you’re building a web application that needs to open PDFs, you’ll probably run into a situation where you have to deal with password-protected documents. Building this functionality yourself will require a lot of time and maintenance costs that may not be on the roadmap for your team.
Foxit’s PDF SDK for Web makes it easy to display PDFs in a browser-based application. In this tutorial, you’ll set up a Node app that uses the Foxit SDK to open password-protected PDFs in the browser and let authorized users preview the document. This application is also available on GitHub if you’d like to jump straight to a working version.
Visit the Foxit PDF SDK Web Demo and see for yourself, by exploring the configurations and features.
Building a Web Application to Display Password-Protected PDFs
HTML comes with built-in file upload features that allow users to work with files from their local machine in the browser. Unfortunately, displaying PDFs in JavaScript is a bit more complicated, especially when you need to support password protection. In this tutorial, you’ll build a web application with a PDF upload form and an optional password field. When a password-protected PDF is uploaded, and the correct password entered, users will see a preview of the file. If an incorrect password is entered, they’ll be shown an error message and instructed to try again.
You’ll use the Express web framework, Pure CSS for styling, and Foxit’s PDF SDK to build this application.
Prerequisites
Creating a New Express App
The Express generator makes it easy to set up a new application. From your terminal, run the following:
npx express-generator --git --view=hbs
This command creates a new application with a .gitignore file and Handlebars template files.
Next, add the dotenv npm package (which you’ll use to access your Foxit license key and serial number) and install Express’ dependencies:
npm i dotenv && npm i
Assuming you’ve downloaded the Foxit PDF SDK for Web, you can find your license key and serial number in the examples/license-key.js file. Create a new file at the root directory of your web application called .env and add the two values:
LICENSE_SN="<YOUR FOXIT SERIAL NUMBER>"
LICENSE_KEY="<YOUR FOXIT LICENSE KEY>"
Next, copy the Foxit library into your web application so you can access it from the frontend. Copy the lib/ directory from the Foxit PDF SDK you downloaded and paste it into your web application’s public/ directory. Now the Foxit JavaScript library will be available in your web application.
Finally, you don’t want sensitive information or proprietary packages to end up in version control, so add the following to your .gitignore file:
...
public/lib/
.env
Your web application now has all the dependencies it needs, so in the next step, you’ll create the route that will display the PDF preview using Foxit.
Setting Up the Route
Every page in an Express application has a route, including the PDF upload page you’ll create in this demo. Update the routes/index.js file to pass the license key and serial number to the view:
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.render('index', {
licenseSN: process.env.LICENSE_SN,
licenseKey: process.env.LICENSE_KEY,
});
});
module.exports = router;
This allows you to easily update your credentials on the server without hard-coded credentials that require a code change. It also means you can restrict which users can see the Foxit credentials if you add an authentication layer to this application.
Before the process.env
variables are available, you need to include the dotenv
library which loads variables from your .env file. Open app.js and add the following to the top of the file:
require('dotenv').config();
...
Your LICENSE_SN
and LICENSE_KEY
are being securely stored and passed to the front end only when required. In the next step, you will address the display portion of the web application.
Try our SDK for Web Demo in your browser, no download or login required.
Uploading and Displaying PDFs
The Foxit SDK will handle most of the work to check the password and display the PDF to the user, but you’ll need to implement the user interface for file and password inputs. Before you get to that, you’ll also need to update the layout to include some base styles and scale the viewport
. This ensures that the PDF preview is sized to the user’s display.
Open the views/layout.hbs file and replace it with the following:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Foxit PDF Previewer</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
<link rel="stylesheet" href="https://unpkg.com/purecss@2.0.3/build/pure-min.css" integrity="sha384-cg6SkqEOCV1NbJoCu11+bm0NvBRc8IYLRGXkmNrqUBfTjmMYwNKPWBTIKyw9mHNJ" crossorigin="anonymous">
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<div class="container">
{{{body}}}
</div>
</body>
</html>
This loads the PureCSS styling library, but you can use any other frontend styling framework you’re comfortable with.
Next, open the views/index.hbs file and replace it with the following:
<h1>PDF Previewer</h1>
<p>Use the form below to preview any password-protected PDF file in this web application.</p>
<!--
<form class="pure-form">
<fieldset>
<input type="password" id="password" placeholder="Enter PDF Password" />
<input class="original-pdf-upload-button" type="file" name="file" id="file" accept=".pdf,.fdf,.xfdf" multiple="multiple" />
<label class="pure-button new-pdf-upload-button" for="file">Select a PDF file</label>
</fieldset>
</form>
<!--
<div id="pdf-viewer"></div>
<!--
<script src="/lib/PDFViewCtrl.full.js"></script>
<script>
var PDFViewer = PDFViewCtrl.PDFViewer;
var pdfViewer = new PDFViewer({
libPath: '/lib',
jr: {
licenseSN: "{{ licenseSN }}",
licenseKey: "{{ licenseKey }}",
},
});
pdfViewer.init('#pdf-viewer');
document.getElementById('file').onchange = function (e) {
if (!this.value) {
return;
}
var pdf,fdf;
for (var i = e.target.files.length; i--;) {
var file = e.target.files[i];
var filename = file.name;
if (/\.pdf$/i.test(filename)) {
pdf = file
} else if (/\.(x)?fdf$/i.test(filename)) {
fdf = file
}
}
var options = {password: '', fdf: {file: fdf}};
if (document.getElementById('password').value) {
options.password = document.getElementById('password').value;
document.getElementById('password').value = '';
}
pdfViewer.openPDFByFile(pdf, options);
this.value = '';
};
</script>
This file serves three purposes. First, it includes a PDF upload form with a password field. The file upload input element also has a <label>
, which acts as a nicely styled upload button. Next, the <div id="pdf-viewer">
tag wraps the Foxit PDF reader which is used in the pdfViewer.init
function in the custom JavaScript. The last section of this file loads Foxit’s PDFViewCtrl.PDFViewer
class and initializes it using the code inside the <script>
tags.
You application’s functionality is just about done, but before you test this, open up your public/stylesheets/style.css file and replace it with the following:
body {
background-color: #f7f7f7;
color: #333333;
}
.container {
background-color: #ffffff;
margin: 0 auto;
padding: 30px;
}
.original-pdf-upload-button {
width: 0.1px;
height: 0.1px;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: -1;
}
.new-pdf-upload-button {
top: -2px;
position: relative;
}
This will style the PDF upload button such that it’s consistent with the other PureCSS buttons and give your application a bit of padding.
To test the application, save your work and run npm start
from your terminal. Node will spin up a server, and your web app will be available at localhost:3000.
If you have a password-protected document on your computer, type the password into the input box, then upload the PDF file. If your password is correct, the file will be uploaded, and the password removed from the input box. This is a start, but what happens if a user types an incorrect password? You probably want to let them know so they can try again, and in the final step, you’ll address this.
Handling Errors
Foxit’s pdfViewer.openPDFByFile
method returns a promise, so if you want to know when it resolves, you need to add a callback to the then
or catch
methods.
In your views/index.hbs file, replace the pdfViewer.openPDFByFile...
line with the following:
...
pdfViewer.openPDFByFile(pdf, options)
.catch(error => {
console.error(error);
document.getElementById('wrong-password').style.display = 'block';
});
...
And add a new paragraph element to the top of the file with the id="wrong-password"
:
<p id="wrong-password" class="error"><strong>Whoops!</strong>
It looks like the password you entered was incorrect.
Please enter a password and try uploading your file again.
</p>
…
Finally, you’ll need some styling for that error message so that it’s only shown when the catch
method is called. In your public/stylesheets/style.css file, add the following:
...
#wrong-password {
display: none;
}
.error {
background-color: #f5c0c0;
color: #792525;
padding: 10px;
}
Now when you enter an incorrect password (or leave the field blank) and upload a password-protected PDF, you’ll see an error message letting you know that something went wrong:
Conclusion
In this tutorial, you’ve seen how to build a Node web application that allows users to preview password-protected PDFs in their browser securely. Using the Foxit PDF SDK will save you countless hours of development time, and their tools come with an array of other examples in the documentation. While this tutorial has focused on building a web application, Foxit provides SDKs for several platforms, including mobile and native apps.
Try Foxit PDF SDK’s advanced technology on your chosen platform(s): Web, Windows, Android, iOS, Linux, UWP, or Mac. Sign up for a free thirty-day trial today.