---
title: "Web PKI quick reference"
description: "Web PKI on one page: install the JavaScript library, set the license, list and read certificates, sign in the browser and handle errors."
canonical: "https://docs.lacunasoftware.com/en-us/articles/web-pki/quick-reference"
locale: "en"
product: "Web PKI"
last_updated: "2026-10-12"
---

# Web PKI quick reference

The essentials of Web PKI on one page, with links to the full articles.

## What it is for

Web PKI lets web applications use the certificates on the user's computer through JavaScript: list them, read their properties and binary encoding, and sign data or a pre-computed digest with them. 
Its main job is the client-side part of a signature: a server-side SDK prepares the bytes to sign and assembles the signed file, because `signData` and `signHash` return only the raw output of the signature algorithm. If you already have a crypto SDK or write the backend yourself, Web PKI alone covers the frontend part. 

| Choose instead | When it fits better |
| --- | --- |
| [Rest PKI](https://docs.lacunasoftware.com/en-us/articles/rest-pki/quick-reference) (legacy) | Your backend already uses Rest PKI at pki.rest: the PKI guide recommends Rest PKI with Web PKI for web remote signatures from any language. |
| [Rest PKI Core](https://docs.lacunasoftware.com/en-us/articles/rest-pki/core/quick-reference) | You prefer not to write signature code: your application creates a signature session and Rest PKI Core hosts the signing page, where users sign through Web PKI or with cloud certificates. |
| [PKI SDK](https://docs.lacunasoftware.com/en-us/articles/pki-sdk/quick-reference) | Your backend is .NET: PKI SDK does the server side of web remote signatures, with Web PKI in the browser. |
| [PKI Express](https://docs.lacunasoftware.com/en-us/articles/pki-express/quick-reference) | Your backend runs on Windows or Linux in virtually any language: PKI Express signs on the server, and its samples use Web PKI in the browser. |
| [Signer](https://docs.lacunasoftware.com/en-us/articles/signer/quick-reference) | You need a complete document and signature manager rather than a component; its embedded signature widget needs a Web PKI license for your page's domain. |

## Install

| Language | Package | Current major | Registry |
| --- | --- | --- | --- |
| JavaScript / TypeScript (npm) | `web-pki` | 2 (latest 2.18.0) | https://www.npmjs.com/package/web-pki |
| Script tag (CDN) | `lacuna-web-pki-2.18.0.min.js` | 2 | https://cdn.lacunasoftware.com/libs/web-pki/lacuna-web-pki-2.18.0.min.js |

```html
<script type="text/javascript" src="https://cdn.lacunasoftware.com/libs/web-pki/lacuna-web-pki-2.18.0.min.js"
  integrity="sha256-utM/CTsggW5QWTZgkLcAwVGkMBhYKTz3n0992V4r2y4="
  crossorigin="anonymous"></script>
```

```bash
npm install web-pki --save
```

With npm, import the class as the Angular sample does: 

```javascript
import LacunaWebPKI from 'web-pki';
```

Web PKI also needs its components on the user's computer: when they are missing or outdated, or the browser is not supported, `init()` sends the user to the installation page, which returns to your page when done. 
The components update themselves; update the JavaScript library in your application regularly, as updates are backward compatible. 
See [Browser support](https://docs.lacunasoftware.com/en-us/articles/web-pki/browser-support) and, for Windows networks, [distribution through GPO](https://docs.lacunasoftware.com/en-us/articles/web-pki/installation-webpki-gpo). 

## Configuration and authentication

Web PKI runs in the user's browser: there is no API key. Outside localhost, your page needs a **license** bound to its domains, passed to the `LacunaWebPKI` constructor in binary or JSON format. 

```javascript
var webPkiLicense = 'ASYAanNma...Q==';
var pki = new LacunaWebPKI(webPkiLicense);
```

- No license is needed on localhost (any port), nor with Rest PKI on cloud, even in production. 
- The JSON license lists `allowedDomains` and `homologDomains` (staging); the latter include the private IP ranges 10.x, 127.x, 172.16–172.31 and 192.168.x. Use the whole license: the `signature` field alone is not a license. See [Licensing](https://docs.lacunasoftware.com/en-us/articles/web-pki/licensing). 
- To get a license, [contact Lacuna](https://www.lacunasoftware.com/en/home/purchase); PKI SDK licenses usually come with a Web PKI license. 

The `init()` arguments a client sets: 

| Argument | Purpose | Article |
| --- | --- | --- |
| `ready` | Callback run when the component is ready | [Get started](https://docs.lacunasoftware.com/en-us/articles/web-pki/get-started) |
| `license` | The license, when not passed to the constructor | [Licensing](https://docs.lacunasoftware.com/en-us/articles/web-pki/licensing) |
| `defaultFail` | Fail callback for every call without its own | [Default fail callback](https://docs.lacunasoftware.com/en-us/articles/web-pki/default-error-callback) |
| `notInstalled` | Replaces the redirect to the installation page | [Not installed](https://docs.lacunasoftware.com/en-us/articles/web-pki/customizing-not-installed) |
| `restPkiUrl` | Your Rest PKI instance, when it is not the standard https://pki.rest | [Custom Rest PKI URL](https://docs.lacunasoftware.com/en-us/articles/web-pki/customizing-restpki-url) |
| `requiredApiVersion` | API feature set the page needs (default API 1.3), avoiding needless updates | [API versions](https://docs.lacunasoftware.com/en-us/articles/web-pki/api-reference/versions) |
| `brand` | Customized installation page | [Customized installation page](https://docs.lacunasoftware.com/en-us/articles/web-pki/brand) |
| `angularScope`, `ngZone` | Runs callbacks inside AngularJS or Angular cycles | [Callbacks and Angular](https://docs.lacunasoftware.com/en-us/articles/web-pki/angularjs) |

With Rest PKI, Web PKI talks to the Rest PKI instance directly, by default through `https://restpki.lacunasoftware.com/`, an alternative URL of the cloud service at https://pki.rest that firewalls are less likely to block. 

## Core operations

All methods are asynchronous: they return a `Promise` on which you register `success()` and `fail()` callbacks ([Asynchronous calls](https://docs.lacunasoftware.com/en-us/articles/web-pki/async)). The [API reference](https://docs.lacunasoftware.com/en-us/articles/web-pki/api-reference) has every method, including those not shown here, such as `sendAuthenticatedRequest()` for [authenticated requests](https://docs.lacunasoftware.com/en-us/articles/web-pki/auth-request) with the user's certificate over mutual SSL/TLS. 

### Initialize the component

Create a `LacunaWebPKI` and call `init()` before any other method; your `ready` callback runs once the component is ready. See [Get started](https://docs.lacunasoftware.com/en-us/articles/web-pki/get-started). 

```javascript
var pki = new LacunaWebPKI();
pki.init({
    ready: onWebPkiReady,
    defaultFail: onWebPkiFail
});
```

### List the user's certificates

`listCertificates()` returns the certificates sorted by `subjectName`, each with properties such as `thumbprint`, `subjectName`, `issuerName` and `validityEnd`; with `selectId` it fills a select element. See [Customizing certificate selection](https://docs.lacunasoftware.com/en-us/articles/web-pki/cert-select) and [Certificate properties](https://docs.lacunasoftware.com/en-us/articles/web-pki/cert-properties). 
Show all certificates and [pre-validate the selected one](https://docs.lacunasoftware.com/en-us/articles/web-pki/cert-validation) rather than using [filters](https://docs.lacunasoftware.com/en-us/articles/web-pki/filters), which the docs advise against. 

```javascript
pki.listCertificates({
    selectId: 'certificateSelect',
    selectOptionFormatter: getCertText
});

function getCertText(cert) {
    return cert.subjectName + ' (issued by ' + cert.issuerName + ')';
}
```

### Read a certificate

`readCertificate()` returns the certificate's encoding in Base64, which you send to your backend when it starts a remote signature. See [Get started](https://docs.lacunasoftware.com/en-us/articles/web-pki/get-started). 
Pass `{ thumbprint }`: the library also accepts the thumbprint string, as the Java sample does, but the TypeScript typings (`lacuna-web-pki.d.ts`) accept only the object. 

```javascript
pki.readCertificate({ thumbprint: selectedCertThumbprint }).success(function (certEncoding) {
    // certEncoding contains the certificate's encoding (in Base64)
});
```

### Sign data

`signData()` signs Base64-encoded bytes with the selected certificate's private key and returns the signature in Base64. See [signData and signHash](https://docs.lacunasoftware.com/en-us/articles/web-pki/faq/sign-data-vs-hash). 

```javascript
pki.signData({
    thumbprint: '...',     // as returned by the listCertificates method
    data: '...',           // bytes encoded in Base64 (typically given by server)
    digestAlgorithm: '...' // for instance 'SHA-256' (typically given by server)
}).success(function (signature) {
    // signature contains the result of the signature operation (encoded in Base64)
});
```

### Sign a hash from your backend

`signHash()` signs the digest that your server-side SDK returns when it starts a remote signature (PKI Express, PKI SDK, Rest PKI Core); your backend then completes the signature with the result. See [Web remote signatures](https://docs.lacunasoftware.com/en-us/articles/pki-guide/web-signatures/remote). 

```javascript
pki.signHash({
    thumbprint: formElements.certThumbField.val(),
    hash: formElements.toSignHashField.val(),
    digestAlgorithm: formElements.digestAlgorithmField.val()
}).success(function (signature) {
    // Fill the "signature" field, needed on server-side to complete the signature.
    formElements.signatureField.val(signature);
    formElements.form.submit();
});
```

### Sign with Rest PKI

`signWithRestPki()` takes the token your backend got from Rest PKI and the certificate thumbprint; Web PKI exchanges the signature data with Rest PKI directly, and your backend then finishes the signature. See [Rest PKI](https://docs.lacunasoftware.com/en-us/articles/rest-pki/quick-reference). 

```javascript
pki.signWithRestPki({
    token: formElements.token,
    thumbprint: selectedCertThumbprint
}).success(function () {
    // Once the operation is completed, we submit the form.
    formElements.form.submit();
});
```

### Sign a local PDF

`signPdf()` signs a PDF on the user's computer, with nothing sent to a server; pick the file with `showFileBrowser()`. Local signatures need the local signature extension ([contact Lacuna](https://www.lacunasoftware.com/en/home/purchase)) and run only on Windows. See [Web local signatures](https://docs.lacunasoftware.com/en-us/articles/pki-guide/web-signatures/local). 

```javascript
pki.signPdf({
    fileId: file.id,
    output: { mode: 'autoSave', fileNameSuffix: '-signed' },
    certificateThumbprint: $('#certificateSelect').val(),
    policy: 'basic',
    trustArbitrators: [pki.standardTrustArbitrators.pkiBrazil]
}).success(function (result) {
    // result.isValid, result.signatureInfo
});
```

## Errors

A failed call runs its `fail()` callback, or the `defaultFail` set in `init()`; with neither, an exception is thrown. The callback receives an `ExceptionModel` with `userMessage` (for the user), `code`, `error`, `origin` and `message`. See [Default fail callback](https://docs.lacunasoftware.com/en-us/articles/web-pki/default-error-callback). 

- **Component missing or outdated, or browser not supported**: not an error code. `init()` redirects to the installation page, or calls your `notInstalled(status, message)` with `NOT_INSTALLED`, `OUTDATED` or `BROWSER_NOT_SUPPORTED`. See [Not installed](https://docs.lacunasoftware.com/en-us/articles/web-pki/customizing-not-installed). 
- **Error codes**: `code` tells which error occurred, and [Default fail callback](https://docs.lacunasoftware.com/en-us/articles/web-pki/default-error-callback#error-codes) describes each one. On `license_not_set`, `license_invalid`, `license_expired`, `license_domain_not_allowed` and `license_restricted`, check the license against [Licensing](https://docs.lacunasoftware.com/en-us/articles/web-pki/licensing); other common codes are `user_cancelled` (the user cancelled the operation) and `certificate_not_found` (the certificate is not in the user's store or crypto device). 
- **"Could not get pending signature"** with `signWithRestPki()`: Web PKI cannot talk to the Rest PKI instance, which is common with on-premises instances; first check that the user's computer can access it. See [the troubleshooting article](https://docs.lacunasoftware.com/en-us/articles/rest-pki/troubleshoot/could-not-get-pending-sig). 

TODO(docs): 13 error codes have no description, in the docs or in the library's typings: `algorithm_not_supported`, `signed_pdf_to_mark`, `json_error`, `io_error`, `keychain_error`, `keychain_sign_error`, `decode_error`, `csp_invalid_algorithm`, `csp_invalid_provider_type`, `mobile_not_authorized`, `command_decrypt_error`, `blocked_domain` and `invalid_operation`.

## Test certificates and credentials

- Use the Lacuna Test PKI certificates from [Test certificates](https://docs.lacunasoftware.com/en-us/articles/pki-guide/test-certs#web-pki); never trust that PKI in production. 
- To try Web PKI on Windows, you need a certificate in the Windows certificate store: `certmgr.msc` should show one under **Personal** with its private key. To use a test certificate, import its PKCS #12 file (password `1234`) into that store. 
- No license is needed on localhost, and staging hosts on private IPs are covered by the license's `homologDomains`. 
- With Rest PKI, trust the test PKI through the security context ID given on the Test certificates page; for local signatures, add the test root, Lacuna Root Test v3, as a `trustedRoot` trust arbitrator (development only). The .NET sample does this with an older root, Lacuna Root Test v1, which expired in January 2025 and does not accept the current test certificates. 

TODO(docs): how to install the test PKCS #12 files so that Web PKI lists them on Linux and macOS.

## Try it

Run the Web PKI demos, or the samples in your language:

**Demos and samples**

- Live demo: [Your certificates in the browser](https://try.lacunasoftware.com/en/web-pki/certificates-in-the-browser)
- Live demo: [Sign a file with your certificate](https://try.lacunasoftware.com/en/pki-suite/sign-a-file)
- Sign a local PDF in the browser with Web PKI: [.NET](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/dotnet/mvc/PkiSuiteAspNetMvcSample/Controllers/PadesSignatureWebController.cs)
- Sign a local file with CAdES in the browser using Web PKI: [.NET](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/dotnet/mvc/PkiSuiteAspNetMvcSample/Controllers/CadesSignatureWebController.cs)
- List the user's certificates with Web PKI: [.NET](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/dotnet/mvc/PkiSuiteAspNetMvcSample/Controllers/ListCertJQueryController.cs) · [Java](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/java/springmvc/src/main/java/com/lacunasoftware/pkisuite/controller/ListCertJQueryController.java) · [Node.js](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/nodejs/expressmvc/routes/list-cert-jquery.js) · [Python](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/python/flask/sample/views/list_cert_jquery.py) · [Ruby](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/ruby/rails/app/controllers/list_cert_jquery_controller.rb)
- Read a certificate's details with Web PKI: [.NET](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/dotnet/mvc/PkiSuiteAspNetMvcSample/Controllers/ReadCertJQueryController.cs) · [Java](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/java/springmvc/src/main/java/com/lacunasoftware/pkisuite/controller/ReadCertJQueryController.java) · [Node.js](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/nodejs/expressmvc/routes/read-cert-jquery.js) · [Python](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/python/flask/sample/views/read_cert_jquery.py) · [Ruby](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/ruby/rails/app/controllers/read_cert_jquery_controller.rb)
- Sign data with RSA in the browser using Web PKI: [.NET](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/dotnet/mvc/PkiSuiteAspNetMvcSample/Controllers/RSAWebController.cs) · [Java](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/java/springmvc/src/main/java/com/lacunasoftware/pkisuite/controller/RSAWebController.java) · [Node.js](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/nodejs/expressmvc/routes/rsa-web.js) · [Python](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/python/flask/sample/views/rsa_web.py) · [Ruby](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/ruby/rails/app/controllers/rsa_web_controller.rb)
