Add password protection and permission controls to your generated PDFs.
The HTML to PDF Generator supports PDF encryption and access control using jsPDF's built-in security features. You can:
- Password protect PDFs (user and owner passwords)
- Control document permissions (printing, copying, modifying, etc.)
- Restrict access to sensitive documents
jsPDF uses RC4 40-bit encryption, which is considered weak by modern security standards. While this provides basic protection against casual access, it should not be relied upon for highly sensitive documents.
For stronger encryption (AES 128/256), consider server-side solutions like:
- node-qpdf
- PDFtk
- Apache PDFBox
- User Password: Required to open the PDF
- Owner Password: Required to change permissions
If only the user password is set, the PDF can be opened but permissions cannot be modified. If both are set, the owner password allows full access and permission changes.
import { PDFGenerator } from '@encryptioner/html-to-pdf-generator';
const generator = new PDFGenerator({
securityOptions: {
enabled: true,
userPassword: 'my-secret-password',
ownerPassword: 'admin-password'
}
});
await generator.generatePDF(element, 'protected.pdf');const generator = new PDFGenerator({
securityOptions: {
enabled: true,
userPassword: 'view-only',
permissions: {
printing: 'none', // Disable printing
modifying: false, // Disable modifications
copying: false, // Disable text/content copying
annotating: false, // Disable annotations
fillingForms: false // Disable form filling
}
}
});const generator = new PDFGenerator({
securityOptions: {
enabled: true,
userPassword: 'print-only',
permissions: {
printing: 'highResolution', // Allow high-quality printing
modifying: false,
copying: false,
annotating: false
}
}
});import { usePDFGeneratorManual } from '@encryptioner/html-to-pdf-generator/react';
function SecureDocument() {
const { generatePDF, isGenerating } = usePDFGeneratorManual({
securityOptions: {
enabled: true,
userPassword: 'secret123',
ownerPassword: 'admin123',
permissions: {
printing: 'lowResolution',
modifying: false,
copying: true, // Allow copying
annotating: false
}
}
});
const handleDownload = async () => {
const element = document.getElementById('invoice');
if (element) {
await generatePDF(element as HTMLElement, 'secure-invoice.pdf');
}
};
return (
<div>
<div id="invoice">
{/* Your invoice content */}
</div>
<button onClick={handleDownload} disabled={isGenerating}>
Download Protected PDF
</button>
</div>
);
}<script setup lang="ts">
import { usePDFGeneratorManual } from '@encryptioner/html-to-pdf-generator/vue';
import { ref } from 'vue';
const contentRef = ref<HTMLElement | null>(null);
const { generatePDF, isGenerating } = usePDFGeneratorManual({
securityOptions: {
enabled: true,
userPassword: 'confidential',
permissions: {
printing: 'none',
copying: false,
modifying: false
}
}
});
async function downloadSecurePDF() {
if (contentRef.value) {
await generatePDF(contentRef.value, 'confidential-report.pdf');
}
}
</script>
<template>
<div>
<div ref="contentRef">
<!-- Your content -->
</div>
<button @click="downloadSecurePDF" :disabled="isGenerating">
Download Secure PDF
</button>
</div>
</template><script lang="ts">
import { PDFGeneratorStore } from '@encryptioner/html-to-pdf-generator/svelte';
let contentElement: HTMLElement;
const pdfStore = new PDFGeneratorStore({
securityOptions: {
enabled: true,
userPassword: 'secret',
ownerPassword: 'master',
permissions: {
printing: 'highResolution',
copying: false,
modifying: false,
annotating: false
}
}
});
async function download() {
await pdfStore.generatePDF(contentElement, 'secure-document.pdf');
}
</script>
<div bind:this={contentElement}>
<!-- Your content -->
</div>
<button on:click={download} disabled={$pdfStore.isGenerating}>
Download Protected PDF
</button>import { generatePDFFromURL } from '@encryptioner/html-to-pdf-generator/node';
const pdfBuffer = await generatePDFFromURL('https://example.com', {
securityOptions: {
enabled: true,
userPassword: 'secure123',
ownerPassword: 'admin456',
permissions: {
printing: 'lowResolution',
modifying: false,
copying: false,
annotating: false,
fillingForms: false
}
}
});
// Save to file
await fs.promises.writeFile('protected.pdf', pdfBuffer);interface PDFSecurityOptions {
/** Enable encryption (must be true to activate security) */
enabled?: boolean;
/** User password (required to open the PDF) */
userPassword?: string;
/** Owner password (required to modify permissions) */
ownerPassword?: string;
/** Document permissions */
permissions?: PDFSecurityPermissions;
/** Encryption strength (currently only RC4 40-bit supported by jsPDF) */
encryptionStrength?: 128 | 256;
}interface PDFSecurityPermissions {
/**
* Allow printing
* - 'none': No printing allowed
* - 'lowResolution': Low resolution printing only
* - 'highResolution': Full quality printing
*/
printing?: 'none' | 'lowResolution' | 'highResolution';
/** Allow modifying the document */
modifying?: boolean;
/** Allow copying text and graphics */
copying?: boolean;
/** Allow adding or modifying annotations */
annotating?: boolean;
/** Allow filling in form fields */
fillingForms?: boolean;
/** Allow content accessibility (for screen readers) */
contentAccessibility?: boolean;
/** Allow assembling document (inserting, rotating, deleting pages) */
documentAssembly?: boolean;
}securityOptions: {
enabled: true,
userPassword: 'readonly',
permissions: {
printing: 'none',
modifying: false,
copying: false,
annotating: false,
fillingForms: false
}
}securityOptions: {
enabled: true,
userPassword: 'printonly',
permissions: {
printing: 'highResolution',
modifying: false,
copying: false,
annotating: false
}
}securityOptions: {
enabled: true,
userPassword: 'review',
permissions: {
printing: 'lowResolution',
modifying: false,
copying: false,
annotating: true, // Can add comments
fillingForms: true // Can fill forms
}
}securityOptions: {
enabled: true,
userPassword: 'copy-ok',
permissions: {
printing: 'highResolution',
modifying: false,
copying: true, // Can copy text
annotating: false
}
}Protect invoices from modification while allowing printing:
securityOptions: {
enabled: true,
userPassword: 'invoice-' + Date.now(),
permissions: {
printing: 'highResolution',
modifying: false,
copying: true, // Allow copying invoice details
annotating: false
}
}Maximum protection for sensitive documents:
securityOptions: {
enabled: true,
userPassword: generateSecurePassword(),
ownerPassword: adminPassword,
permissions: {
printing: 'none',
modifying: false,
copying: false,
annotating: false,
fillingForms: false
}
}Allow users to fill forms but not modify structure:
securityOptions: {
enabled: true,
userPassword: 'form-access',
permissions: {
printing: 'highResolution',
modifying: false,
copying: false,
annotating: true,
fillingForms: true
}
}// Bad - weak password
userPassword: '1234'
// Good - strong password
userPassword: crypto.randomBytes(16).toString('hex')securityOptions: {
enabled: true,
userPassword: 'user-access-key', // For viewing
ownerPassword: 'admin-master-key', // For full control
permissions: { /* ... */ }
}If permissions are not specified, the library defaults to allowing print and copy:
// This allows print and copy by default
securityOptions: {
enabled: true,
userPassword: 'secret'
// No permissions specified - defaults to print + copy
}For public documents, don't use security. Only apply for sensitive content:
const securityOptions = isConfidential ? {
enabled: true,
userPassword: generatePassword(),
permissions: restrictedPermissions
} : undefined;
const generator = new PDFGenerator({ securityOptions });- Casual unauthorized access
- Accidental modifications
- Unauthorized printing/copying (enforced by PDF readers)
- Basic document protection
- Determined attackers with password cracking tools (RC4 40-bit is weak)
- Users with specialized PDF tools
- Screen capture / photography
- OCR of printed documents
For stronger security requirements:
Use stronger encryption libraries on the server:
// After generating PDF with this library
import { PDFDocument } from 'pdf-lib';
const pdfDoc = await PDFDocument.load(pdfBytes);
// Use pdf-lib for stronger encryption if needed- node-qpdf: Supports AES 128/256
- PDFtk: Command-line PDF toolkit
- Apache PDFBox: Java-based PDF library
Combine with application-level access control:
// Generate unique password per user
const userPassword = await hashUserCredentials(userId);
await generator.generatePDF(element, 'document.pdf', {
securityOptions: {
enabled: true,
userPassword,
permissions: getUserPermissions(userRole)
}
});Issue: PDF opens directly without asking for password.
Solution: Ensure enabled: true is set:
securityOptions: {
enabled: true, // Must be true!
userPassword: 'secret'
}Issue: User can still copy/print despite restrictions.
Solution: Permissions are enforced by the PDF reader. Some readers may ignore restrictions. This is a limitation of PDF security in general, not this library.
Issue: TypeScript errors with security options.
Solution: Import types:
import type { PDFSecurityOptions } from '@encryptioner/html-to-pdf-generator';
const security: PDFSecurityOptions = {
enabled: true,
userPassword: 'secret'
};- Metadata - Add author, title, and other metadata
- Watermarks - Add visible watermarks
- Headers & Footers - Add headers and footers
- Batch Generation - Generate multiple PDFs