> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/web/security/custom-handler.md).

# Apryse Custom Security Handler using JavaScript

Encrypt and decrypt files securely with the Apryse Custom Security Handler. Learn how to protect your documents with this DRM solution built into Apryse SDK. Simplify encryption methods and enhance se

{% hint style="info" %}
**Requirements**

*These packages are required to use these features in production. Trial keys have unlimited access to all features*

<a href="https://apryse.com/capabilities#Security" class="button primary">Package: Security</a><a href="https://showcase.apryse.com/password-protect" class="button primary">Live demo</a>
{% endhint %}

The Apryse Custom Security Handler provides a means to encrypt files in a way that cannot be decrypted by other applications. This makes it especially suitable for Digital Rights Management (DRM) use cases. This is an alternative to defining your own custom encryption method. In particular using the Apryse Custom Security Handler is much simpler as it comes built-in with Apryse SDK.

Like other encryption methods a password is required to encrypt and decrypt the document. This custom security handler also requires the application choose a unique unsigned integer custom id (typically one per application) of their choice to encrypt and decrypt the document. Using this unique id provides an extra level of security as even other applications based on Apryse SDK will not typically be configured to open files secured with that particular id.

## Encrypting an Apryse Custom secured document using the password and application custom id

The first step before encrypting is to choose an application custom id. A typical way to create this is to use a random generator to create a 32-bit number. This number would then be used throughout your document workflow.

Note that when using WebViewer you would generally perform the encryption on the server side, but the code is shown below for reference and will look similar on the server.

Once that is done, the document can be encrypted:

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
<html>
  <script src="../lib/core/webviewer-core.min.js"></script>
  <script src="../lib/core/pdf/PDFNet.js"></script>
  <script>
    (async function() {
      Core.setWorkerPath('../lib/core');
      const PDFNet = Core.PDFNet;
      const doc = await PDFNet.PDFDoc.createFromURL(fileURL);
      // Create Apryse custom security handler with a custom id. Replace this with your own integer
      const customHandler = await PDFNet.PDFTronCustomSecurityHandler.create(myCustomId);
      // Set a new password required to open a document
      customHandler.changeUserPasswordUString(myPassword);
      // Note: document takes the ownership of customHandler.
      doc.setSecurityHandler(customHandler);
      // Save the encrypted document
      const docArrayBuffer = await doc.saveMemoryBuffer(PDFNet.SDFDoc.SaveOptions.e_remove_unused);
    })()
  </script>
</html>
```

{% endcode %}

[PDFNet.PDFDoc.createFromURL](https://sdk.apryse.com/api/web/Core.PDFNet.PDFDoc.html#.createFromURL__anchor) [PDFNet.PDFDoc.setSecurityHandler](https://sdk.apryse.com/api/web/Core.PDFNet.PDFDoc.html#setSecurityHandler__anchor) [PDFNet.PDFTronCustomSecurityHandler.create](https://sdk.apryse.com/api/web/Core.PDFNet.PDFTronCustomSecurityHandler.html#.create__anchor) [PDFNet.SecurityHandler.changeUserPasswordUString](https://sdk.apryse.com/api/web/Core.PDFNet.SecurityHandler.html#changeUserPasswordUString__anchor) [Core.setWorkerPath](https://sdk.apryse.com/api/web/Core.html#.setWorkerPath__anchor)
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
<html>
  <script src="../lib/core/CoreControls.js"></script>
  <script src="../lib/core/pdf/PDFNet.js"></script>
  <script>
    (async function() {
      CoreControls.setWorkerPath('../lib/core');
      const doc = await PDFNet.PDFDoc.createFromURL(fileURL);
      // Create Apryse custom security handler with a custom id. Replace this with your own integer
      const customHandler = await PDFNet.PDFTronCustomSecurityHandler.create(myCustomId);
      // Set a new password required to open a document
      customHandler.changeUserPasswordUString(myPassword);
      // Note: document takes the ownership of customHandler.
      doc.setSecurityHandler(customHandler);
      // Save the encrypted document
      const docArrayBuffer = await doc.saveMemoryBuffer(PDFNet.SDFDoc.SaveOptions.e_remove_unused);
    })()
  </script>
</html>
```

{% endcode %}

[PDFNet.PDFDoc.createFromURL](https://sdk.apryse.com/api/web/Core.PDFNet.PDFDoc.html#.createFromURL__anchor) [PDFNet.PDFDoc.setSecurityHandler](https://sdk.apryse.com/api/web/Core.PDFNet.PDFDoc.html#setSecurityHandler__anchor) [PDFNet.PDFTronCustomSecurityHandler.create](https://sdk.apryse.com/api/web/Core.PDFNet.PDFTronCustomSecurityHandler.html#.create__anchor) [PDFNet.SecurityHandler.changeUserPasswordUString](https://sdk.apryse.com/api/web/Core.PDFNet.SecurityHandler.html#changeUserPasswordUString__anchor) [CoreControls.setWorkerPath](https://sdk.apryse.com/api/web/Core.html#.setWorkerPath__anchor)
{% endtab %}
{% endtabs %}

[Encrypt and Decrypt PDF Files](/web/get-started/samples.md#encryption) Full sample code which illustrates some of our encryption support.

## Decrypting an Apryse Custom secured document using the password and application custom id

The same application custom id and password using during encryption are required for decryption. Failing to provide the correct password or application custom id will prevent opening the encrypted document.

To decrypt a PDF with Apryse Custom security:

If you're opening the file through the WebViewer UI or WebViewer Core then you can use the `customHandlerId` option in loadDocument.

With the WebViewer UI:

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
WebViewer({
  // options
}, viewerElement)
.then(instance => {
  instance.UI.loadDocument('secure.pdf', {
    password: 'password',
    customHandlerId: 42
  });
});
```

{% endcode %}
{% endtab %}
{% endtabs %}

With the WebViewer Core:

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
myDocumentViewerInstance.loadDocument('secure.pdf', {
  password: (callback) => {
    return callback('password');
  },
  customHandlerId: 42
});
```

{% endcode %}
{% endtab %}
{% endtabs %}

If you would like to use the full API to do this with a `PDFDoc` in memory:

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
<html>
  <script src="../lib/core/webviewer-core.min.js"></script>
  <script src="../lib/core/pdf/PDFNet.js"></script>
  <script>
    (async function() {
      Core.setWorkerPath('../lib/core');
      // Register the Apryse Custom Security handler with the same custom id used in encryption.
      // Calling this function is a requirement to load files encrypted with PDFTronCustomSecurityHandler.
      await PDFNet.addPDFTronCustomHandler(myCustomId);
      const doc_enc = await PDFNet.PDFDoc.createFromURL(filename);
      if ((await doc_enc.initStdSecurityHandlerUString(myPassword))) {
        // The password is correct! Document can now be used for reading and editing
      }
    })()
  </script>
</html>
```

{% endcode %}

[PDFNet.PDFDoc.createFromURL](https://sdk.apryse.com/api/web/Core.PDFNet.PDFDoc.html#.createFromURL__anchor) [PDFNet.PDFDoc.initStdSecurityHandlerUString](https://sdk.apryse.com/api/web/Core.PDFNet.PDFDoc.html#initStdSecurityHandlerUString__anchor) [PDFNet.addPDFTronCustomHandler](https://sdk.apryse.com/api/web/Core.PDFNet.html#addPDFTronCustomHandler__anchor) [Core.setWorkerPath](https://sdk.apryse.com/api/web/Core.html#.setWorkerPath__anchor)
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
<html>
  <script src="../lib/core/CoreControls.js"></script>
  <script src="../lib/core/pdf/PDFNet.js"></script>
  <script>
    (async function() {
      CoreControls.setWorkerPath('../lib/core');
      // Register the Apryse Custom Security handler with the same custom id used in encryption.
      // Calling this function is a requirement to load files encrypted with PDFTronCustomSecurityHandler.
      await PDFNet.addPDFTronCustomHandler(myCustomId);
      const doc_enc = await PDFNet.PDFDoc.createFromURL(filename);
      if ((await doc_enc.initStdSecurityHandlerUString(myPassword))) {
        // The password is correct! Document can now be used for reading and editing
      }
    })()
  </script>
</html>
```

{% endcode %}

[PDFNet.PDFDoc.createFromURL](https://sdk.apryse.com/api/web/Core.PDFNet.PDFDoc.html#.createFromURL__anchor) [PDFNet.PDFDoc.initStdSecurityHandlerUString](https://sdk.apryse.com/api/web/Core.PDFNet.PDFDoc.html#initStdSecurityHandlerUString__anchor) [PDFNet.addPDFTronCustomHandler](https://sdk.apryse.com/api/web/Core.PDFNet.html#addPDFTronCustomHandler__anchor) [CoreControls.setWorkerPath](https://sdk.apryse.com/api/web/Core.html#.setWorkerPath__anchor)
{% endtab %}
{% endtabs %}

[Encrypt and Decrypt PDF Files](/web/get-started/samples.md#encryption) Full sample code which illustrates some of our encryption support.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/web/security/custom-handler.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
