DEV Community

sunshey
sunshey

Posted on

How to Password Protect PDFs in the Browser Using JavaScript (No Server)

 A client sent me a contract last month. Before forwarding it to my accountant, I wanted to password-protect it. The usual options? Adobe Acrobat ($20/month) or some "free" online tool that uploads my file to a server first.

Neither worked for me. So I built client-side encryption into my PDF toolkit.

Here's how to do it entirely in the browser using pdf-lib.


Why Client-Side?

Most online PDF encryption works like this:

  1. Upload your PDF to their server
  2. They encrypt it
  3. You download the encrypted version

The problem: your sensitive document — contract, tax form, medical record — just sat on someone else's computer. Even if they delete it after processing, you have no guarantee.

Client-side encryption solves this. The PDF never leaves the user's device. The browser loads the encryption library, processes the file locally, and downloads the result.


The Stack: pdf-lib

pdf-lib supports PDF encryption natively as of v1.17.0. It runs entirely in the browser, no backend required.

npm install pdf-lib
Enter fullscreen mode Exit fullscreen mode

Basic Encryption: Add a Password

Here's the simplest flow: load a PDF, encrypt it with a password, save.

import { PDFDocument } from 'pdf-lib';

async function encryptPdf(pdfFile, password) {
  // Read PDF as bytes
  const pdfBytes = await pdfFile.arrayBuffer();

  // Load the PDF
  const pdfDoc = await PDFDocument.load(pdfBytes);

  // Encrypt with password
  pdfDoc.encrypt({
    userPassword: password,
    ownerPassword: password,
  });

  // Save encrypted PDF
  const encryptedBytes = await pdfDoc.save();
  return encryptedBytes;
}

// Usage
const input = document.getElementById('fileInput');
input.addEventListener('change', async (e) => {
  const file = e.target.files[0];
  const encrypted = await encryptPdf(file, 'my-secret-password');

  // Download
  const blob = new Blob([encrypted], { type: 'application/pdf' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'encrypted-document.pdf';
  a.click();
});
Enter fullscreen mode Exit fullscreen mode

What's happening:

  1. Read the PDF file into memory
  2. Load it into pdf-lib
  3. Apply encryption with the provided password
  4. Save and trigger download

The resulting PDF requires the password to open.


User Password vs Owner Password

PDF encryption supports two passwords:

  • User password: Required to open and view the document
  • Owner password: Required to change permissions (printing, copying, etc.)

For most use cases, you can set them to the same value:

pdfDoc.encrypt({
  userPassword: 'open-me',
  ownerPassword: 'open-me',
});
Enter fullscreen mode Exit fullscreen mode

If you want stricter control, set different passwords:

pdfDoc.encrypt({
  userPassword: 'shared-with-client',      // Client needs this to open
  ownerPassword: 'admin-only-password',    // Only you can change permissions
});
Enter fullscreen mode Exit fullscreen mode

Encryption Strength: 128-bit vs 256-bit AES

PDF supports multiple encryption algorithms:

Algorithm Security Compatibility
RC4 (40-bit) Weak Universal
128-bit AES Strong Acrobat 7+
256-bit AES Strongest Acrobat X+

pdf-lib defaults to strong encryption. For maximum compatibility with older readers, you can explicitly request 128-bit AES. For best security, use 256-bit AES.

Most modern PDF readers (Adobe Acrobat, Preview, Chrome/Firefox built-in viewers, mobile apps) handle 128-bit and 256-bit AES without issues. Only very old software (pre-2010) might struggle.


Setting Permissions (Optional)

Beyond just password-protection, you can restrict what users can do:

pdfDoc.encrypt({
  userPassword: 'view-only',
  ownerPassword: 'admin-password',
  permissions: {
    printing: 'highResolution',  // or 'lowResolution' or false
    modifying: false,
    copying: false,
    annotating: false,
    fillingForms: false,
    documentAssembly: false,
  },
});
Enter fullscreen mode Exit fullscreen mode

This creates a PDF that opens with "view-only" but restricts printing, copying, and editing unless you have the owner password.


Password Best Practices

Since there's no "forgot password" feature for encrypted PDFs:

  • Use a memorable but strong password. I use 3-4 random words + a number + a symbol: Blue-Desk-7-Tiger!
  • Share the password separately. Email the PDF, text the password. Don't send both through the same channel.
  • Test before sending. Always open the encrypted PDF yourself to verify the password works.

Complete Working Example

Here's a minimal HTML page that encrypts PDFs in the browser:

<!DOCTYPE html>
<html>
<head>
  <title>PDF Encryptor</title>
  <script type="module">
    import { PDFDocument } from 'https://cdn.jsdelivr.net/npm/pdf-lib@1.17.1/+esm';

    document.getElementById('encryptBtn').addEventListener('click', async () => {
      const fileInput = document.getElementById('pdfFile');
      const password = document.getElementById('password').value;

      if (!fileInput.files[0] || !password) return;

      const pdfBytes = await fileInput.files[0].arrayBuffer();
      const pdfDoc = await PDFDocument.load(pdfBytes);

      pdfDoc.encrypt({
        userPassword: password,
        ownerPassword: password,
      });

      const encrypted = await pdfDoc.save();
      const blob = new Blob([encrypted], { type: 'application/pdf' });
      const url = URL.createObjectURL(blob);

      const a = document.createElement('a');
      a.href = url;
      a.download = 'encrypted.pdf';
      a.click();
    });
  </script>
</head>
<body>
  <input type="file" id="pdfFile" accept=".pdf">
  <input type="password" id="password" placeholder="Enter password">
  <button id="encryptBtn">Encrypt PDF</button>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

No build step, no server, no upload.


Try the Live Tool

If you want to encrypt PDFs without writing code:

👉 en.sotool.top/encrypt

Free, no signup, browser-based. Your file never leaves your device.

The source code is open source if you want to see the full Vue 3 + pdf-lib integration with 128-bit and 256-bit AES options.


Have you implemented client-side document security? What trade-offs do you consider between security and usability?

Top comments (0)