How to Password-Protect PDF in Google Drive with Google Apps Script and PDF.co

In this tutorial, we’ll be learning how to add passwords to PDF files in Google Drive. For this, we’ll be using Google Apps Script and PDF.co. Before diving into the source code, let’s analyze what we’re trying to build here.

Output

For this demo purpose, I have created a Google spreadsheet document. In addition to it, There are some PDF documents in the same directory.

PDF Documents

We’ll be creating an Apps Script project to write source code. That is achieved by going through the “Extensions” => “Apps Script” menu.

Apps Script

It’ll open the Apps Script project window in the new browser tab. There we need to write source code.

Source Code

Once the code is ready and executed, It’ll create a new Menu named “PDF.co” in Google Spreadsheet.

PDF.co Menu

Upon clicking this, all PDF documents in the current folder will be processed and their password-protected version will be created.

Passwords Added

As we can observe in the screenshot below, the Google Drive folder now contains password-protected PDFs.

Password-Protected PDFs

Okay, now if we open any password-protected PDF, it’s asking for a password before opening. Working as expected!

Prompted to Enter Password

Now that we’ve seen the output demo, let’s see the source code. We’ll analyze important pieces of source code later.

Source Code

Following is the full source for this sample.

/**
 * IMPORTANT: Add Service reference for "Drive". Go to Services > Locate "Drive (drive API)" > Add Reference of it 
 */

// Add Your PDF.co API Key here
const pdfCoAPIKey = 'ADD_YOUR_PDFCo_API_KEY_HERE';

// Password
const pdfPassword = "Hello12345";

// Get the active spreadsheet and the active sheet
ss = SpreadsheetApp.getActiveSpreadsheet();
ssid = ss.getId();

// Look in the same folder the sheet exists in. For example, if this template is in
// My Drive, it will return all of the files in My Drive.
var ssparents = DriveApp.getFileById(ssid).getParents();

// Store File-Ids/PermissionIds used for merging
let filePermissions = [];

/**
 * Note: Here, we're getting current folder where spreadsheet is residing.
 * But we can certainly pick any folder of our like by using Folder related functions.
 * For example:
  var allFolders = DriveApp.getFoldersByName("Folder_Containing_PDF_Files");
  while (allFolders.hasNext()) {
    var folder = allFolders.next();
    Logger.log(folder.getName());
  }
 */
// Loop through all the files and add the values to the spreadsheet.
var folder = ssparents.next();

/**
 * Add PDF.co Menus in Google Spreadsheet
 */
function onOpen() {
  var menuItems = [
    {name: 'Add Password to All PDF Files Of Current Folder', functionName: 'addPasswordToCurrentFolderPDFs'} 
  ];
  ss.addMenu('PDF.co', menuItems);
}

function addPasswordToCurrentFolderPDFs(){
  var allFileNameUrls = getPDFFilesFromCurFolder();
  var allResp = [];

  if(allFileNameUrls && allFileNameUrls.length > 0){
    for(let i = 0; i < allFileNameUrls.length; i++){
      const elmCurFileNameUrl = allFileNameUrls[i];

      var oResp = addPasswordToPDF(elmCurFileNameUrl.url, elmCurFileNameUrl.fileName);
      allResp.push(oResp);
    }
  }

  // Write all resp
  let resultUrlCell =  ss.getRange("A1");
  
  // Update Cell with result
  resultUrlCell.setValue(allResp.join("\n\r"));    
}

/**
 * Get all PDF files from current folder
 */
function getPDFFilesFromCurFolder() {
  var files = folder.getFiles();
  var allFileNameUrls = [];

  while (files.hasNext()) {
    var file = files.next();

    var fileName = file.getName();
    if(fileName.endsWith(".pdf") && !fileName.includes("_protected")){
      // Create Pre-Signed URL from PDF.co
      var respPresignedUrl = getPDFcoPreSignedURL(fileName)

      if(!respPresignedUrl.error){
        var fileData = file.getBlob();
        if(uploadFileToPresignedURL(respPresignedUrl.presignedUrl, fileData)){
          // Add Url
          allFileNameUrls.push({url: respPresignedUrl.url, fileName: fileName});
        }
      }
    }
  }

  return allFileNameUrls;
}

/**
 * Password Protecting file with PDF.co and Save to drive
 */
function addPasswordToPDF(pdfUrl, pdfFileName) {
  // Output File Name
  let outputFileName = `${pdfFileName.replace('.pdf','')}_protected.pdf`;
  
  // Prepare Payload
  var data = {
    "url": pdfUrl,
    "ownerPassword": pdfPassword,
    "userPassword": pdfPassword,
    "EncryptionAlgorithm": "AES_128bit",
    "AllowPrintDocument": false,
    "AllowFillForms": false,
    "AllowModifyDocument": false,
    "AllowContentExtraction": false,
    "AllowModifyAnnotations": false,
    "PrintQuality": "LowResolution",
    "encrypt": false,
    "async": false,
    "name": outputFileName
  };

  // Prepare Request Options
  var options = {
    'method' : 'post',
    'contentType': 'application/json',
    'headers': {
      "x-api-key": pdfCoAPIKey
    },
    // Convert the JavaScript object to a JSON string.
    'payload' : JSON.stringify(data)
  };
  
  // Get Response
  // https://developers.google.com/apps-script/reference/url-fetch
  var pdfCoResponse = UrlFetchApp.fetch('https://api.pdf.co/v1/pdf/security/add', options);

  var pdfCoRespContent = pdfCoResponse.getContentText();
  var pdfCoRespJson = JSON.parse(pdfCoRespContent);

  // Display Result
  if(!pdfCoRespJson.error){
    // Upload file to Google Drive
    uploadFile(pdfCoRespJson.url);

    return `Added Password to ${pdfFileName} and Saved as ${outputFileName}`;
  }
  else{
    return `Error Protecting ${pdfFileName}`;
  }
}

/**
 * Gets PDF.co Presigned URL
 */
function getPDFcoPreSignedURL(fileName){
  // Prepare Request Options
  var options = {
    'method' : 'GET',
    'contentType': 'application/json',
    'headers': {
      "x-api-key": pdfCoAPIKey
    }
  };

  var apiUrl = `https://api.pdf.co/v1/file/upload/get-presigned-url?name=${fileName}`;
  
  // Get Response
  // https://developers.google.com/apps-script/reference/url-fetch
  var pdfCoResponse = UrlFetchApp.fetch(apiUrl, options);

  var pdfCoRespContent = pdfCoResponse.getContentText();
  var pdfCoRespJson = JSON.parse(pdfCoRespContent);

  return pdfCoRespJson;
}

/**
 * Uploads File to PDF.co PreSigned URL
 */
function uploadFileToPresignedURL(presignedUrl, fileContent){
  // Prepare Request Options
  var options = {
    'method' : 'PUT',
    'contentType': 'application/octet-stream',
    'headers': {
      "x-api-key": pdfCoAPIKey
    },
    // Convert the JavaScript object to a JSON string.
    'payload' : fileContent
  };
  
  // Get Response
  // https://developers.google.com/apps-script/reference/url-fetch
  var pdfCoResponse = UrlFetchApp.fetch(presignedUrl, options);

  if(pdfCoResponse.getResponseCode() === 200){
    return true;
  }
  else{
    return false;
  }
}

/**
 * Save file URL to specific location
 */
function uploadFile(fileUrl) {
  var fileContent = UrlFetchApp.fetch(fileUrl).getBlob();
  folder.createFile(fileContent);
}

Analysis

Let’s review key source code snippets.

Adding Reference to Drive

The objective of this source code is to read files from Google Drive and save back the protected version. Hence, we need to give service reference to Drive. This can be done via going to “Services”, then locating “Drive (drive API)”, and adding a reference to that.

Reference to Drive

Adding PDF.co Menu

“onOpen” is being called whenever Google Spreadsheet is opened. Here, we’re adding code to set PDF.co with a nested menu item named “Add Password to All PDF Files Of Current Folder”

var menuItems = [
    {name: 'Add Password to All PDF Files Of Current Folder', functionName: 'addPasswordToCurrentFolderPDFs'} 
  ];
  ss.addMenu('PDF.co', menuItems);

Whenever this submenu is clicked, it’ll invoke the function “addPasswordToCurrentFolderPDFs”. This is the starting function of our code execution.

Uploading Files to PDF.co Cloud

We’re getting all files from the current folder, and then iterating through it. The below code is doing just that.

var files = folder.getFiles();
  var allFileNameUrls = [];

  while (files.hasNext()) {
    var file = files.next();

For each file we’re getting PDF.co presigned URL using function ‘getPDFcoPreSignedURL’. This function is calling PDF.co Endpoint ‘https://api.pdf.co/v1/file/upload/get-presigned-url’, and returning PDF.co pre-signed URL.

/**
 * Gets PDF.co Presigned URL
 */
function getPDFcoPreSignedURL(fileName){
  // Prepare Request Options
  var options = {
    'method' : 'GET',
    'contentType': 'application/json',
    'headers': {
      "x-api-key": pdfCoAPIKey
    }
  };

  var apiUrl = `https://api.pdf.co/v1/file/upload/get-presigned-url?name=${fileName}`;
  
  // Get Response
  // https://developers.google.com/apps-script/reference/url-fetch
  var pdfCoResponse = UrlFetchApp.fetch(apiUrl, options);

  var pdfCoRespContent = pdfCoResponse.getContentText();
  var pdfCoRespJson = JSON.parse(pdfCoRespContent);

  return pdfCoRespJson;
}

This presigned URL is used to upload an actual file to it. The following code demonstrates how to do that.

/**
 * Uploads File to PDF.co PreSigned URL
 */
function uploadFileToPresignedURL(presignedUrl, fileContent){
  // Prepare Request Options
  var options = {
    'method' : 'PUT',
    'contentType': 'application/octet-stream',
    'headers': {
      "x-api-key": pdfCoAPIKey
    },
    // Convert the JavaScript object to a JSON string.
    'payload' : fileContent
  };
  
  // Get Response
  // https://developers.google.com/apps-script/reference/url-fetch
  var pdfCoResponse = UrlFetchApp.fetch(presignedUrl, options);

  if(pdfCoResponse.getResponseCode() === 200){
    return true;
  }
  else{
    return false;
  }
}

Now that we have completed the file upload to PDF.co Cloud, we can use this temporary public URL to perform further operations such as a password-protected file.

Password-Protecting the File

So far so good! Now coming to the main logic of this function, we’re using the function ‘addPasswordToPDF’ to perform file protection.

Initially, we’re preparing a request payload with settings such as input file URL, owner and user password, encryption algorithm, and other file-related settings.

// Prepare Payload
  var data = {
    "url": pdfUrl,
    "ownerPassword": pdfPassword,
    "userPassword": pdfPassword,
    "EncryptionAlgorithm": "AES_128bit",
    "AllowPrintDocument": false,
    "AllowFillForms": false,
    "AllowModifyDocument": false,
    "AllowContentExtraction": false,
    "AllowModifyAnnotations": false,
    "PrintQuality": "LowResolution",
    "encrypt": false,
    "async": false,
    "name": outputFileName
  };

These options are used to call PDF.co API endpoint ‘https://api.pdf.co/v1/pdf/security/add’. This endpoint returns a protected PDF (within a moment).

The output result is then saved back to google drive using the `uploadFile` function.

PDF.co API Key

You must have noticed the PDF.co API key being passed in the header.

'headers': {
      "x-api-key": pdfCoAPIKey
    },

This API key is absolutely necessary for authenticating PDF.co requests. You can obtain this API key by signing up with PDF.co.

These are some useful links.

Well, that’s all! With PDF.co, it’s that easy to protect PDF. Thank You! See you onboard!

Video Guide