VerifyKitv0.5.1

Deployment

A production deployment guide for applications using the VerifyKit SDK.


Production Checklist

Before deploying to production, verify the following:

  • WASM loads successfully (no CSP or bundler errors)
  • PDF.js worker is configured and loading
  • CMap and standard font files are accessible (if using non-Latin PDFs)
  • Revocation proxy endpoint has correct CORS headers (if using @trexolab/verifykit-plugin-revocation)
  • Bundle size is acceptable for your performance targets
  • Trust store is configured with any custom root CAs your PDFs require

Content Security Policy (CSP)

The VerifyKit core engine runs WebAssembly. If your application uses a Content Security Policy, you must allow WASM execution in the script-src directive.

Content-Security-Policy: script-src 'self' 'wasm-unsafe-eval';

The wasm-unsafe-eval directive allows WebAssembly compilation and instantiation without allowing arbitrary JavaScript eval(). This is the recommended approach and is supported in all modern browsers.

Alternative (older browsers)

If you need to support older browsers that do not recognize wasm-unsafe-eval, use:

Content-Security-Policy: script-src 'self' 'unsafe-eval';

Warning: unsafe-eval also permits JavaScript eval(), which is less secure. Use wasm-unsafe-eval when possible.

Common CSP Errors

If WASM fails to load, you will see errors like:

Refused to compile or instantiate WebAssembly module because 'unsafe-eval'
is not an allowed source of script in the following Content Security Policy...

or:

CompileError: WebAssembly.instantiate(): Wasm code generation disallowed by embedder

Both indicate that your CSP needs the wasm-unsafe-eval (or unsafe-eval) directive.


PDF.js Worker

The VerifyKit viewer uses PDF.js to render PDF pages. PDF.js offloads page rendering to a Web Worker for performance. By default, @trexolab/verifykit-react configures the worker automatically, but you may need to host the worker file yourself in certain environments.

Default Behavior

The React and Vanilla packages set up the PDF.js worker automatically using a CDN-hosted copy. No configuration is needed for most deployments.

Custom Worker URL

If your CSP blocks external scripts or you need to self-host the worker:

tsx
import { VerifyKitProvider } from '@trexolab/verifykit-react'
 
<VerifyKitProvider config={{ workerUrl: '/static/pdf.worker.min.mjs' }}>
  {/* ... */}
</VerifyKitProvider>

Copy the worker file from node_modules/pdfjs-dist/legacy/build/pdf.worker.min.mjs to your static assets directory.


CMap and Standard Font Files

PDF documents using CJK (Chinese, Japanese, Korean) fonts or certain legacy encodings require CMap files for correct text rendering. PDFs may also reference the 14 standard PDF fonts.

Default Behavior

The viewer loads CMap and standard font files from the Mozilla CDN by default. This works for most deployments without configuration.

Self-Hosting

If your application cannot reach external CDNs (e.g., air-gapped environments, strict CSP):

  1. Copy the CMap files from node_modules/pdfjs-dist/cmaps/ to a public directory (e.g., /static/cmaps/).
  2. Copy the standard fonts from node_modules/pdfjs-dist/standard_fonts/ to a public directory (e.g., /static/standard_fonts/).
  3. Configure the viewer:
tsx
<VerifyKitProvider config={{
  workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs',
  cMapUrl: '/static/cmaps/',
  standardFontDataUrl: '/static/standard_fonts/',
}}>
  {/* ... */}
</VerifyKitProvider>

Bundle Size

The @trexolab/verifykit-core package includes the base64-embedded WASM binary, which accounts for the majority of its bundle size. Here are strategies to manage this:

Tree Shaking

All VerifyKit packages support tree shaking. If you only use verifyPdf(), unused exports like extractPdfMetadata() and utility functions will be eliminated by your bundler.

Code Splitting

For client-side applications, dynamically import VerifyKit so the WASM binary is not included in the initial page load:

tsx
// Load VerifyKit only when needed
const { verifyPdf } = await import('@trexolab/verifykit-core')
const result = await verifyPdf(buffer)

In Next.js, use dynamic imports to defer loading the viewer:

tsx
import dynamic from 'next/dynamic'
 
const PdfViewer = dynamic(() => import('./PdfViewerComponent'), {
  ssr: false,
  loading: () => <p>Loading viewer...</p>,
})

External WASM

If you want to reduce the JavaScript bundle size and load the WASM binary separately (e.g., from a CDN with better caching), use setWasmUrl():

ts
import { setWasmUrl } from '@trexolab/verifykit-core'
 
// Load WASM from a separate URL (can be cached independently)
setWasmUrl('https://cdn.example.com/verifykit/verifykit_core_wasm_bg.wasm')

This trades the convenience of base64-embedded WASM for a smaller initial JavaScript payload and independent cache control.


CORS for Revocation Proxy

If you use @trexolab/verifykit-plugin-revocation, the plugin makes POST requests from the browser to your revocation proxy endpoint. The proxy must return appropriate CORS headers.

Required CORS Headers

Access-Control-Allow-Origin: <your-app-origin>
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: Content-Type

Next.js API Route

The handleRevocation() handler from @trexolab/verifykit-plugin-revocation/handler works automatically when mounted on the same origin as your frontend (the recommended setup). If you need cross-origin access, add CORS headers manually in your server framework:

ts
// app/api/revocation/route.ts
import { handleRevocation } from '@trexolab/verifykit-plugin-revocation/handler'
 
const handler = handleRevocation()
 
export async function POST(req: Request) {
  const res = await handler(req)
  res.headers.set('Access-Control-Allow-Origin', 'https://myapp.example.com')
  return res
}

SSRF Protection

The revocation proxy fetches external URLs (CRL distribution points and OCSP responder URLs) embedded in certificates. To prevent Server-Side Request Forgery (SSRF) attacks, the handler includes a urlFilter option:

ts
export const POST = handleRevocation({
  urlFilter: (url) => {
    const parsed = new URL(url)
    // Only allow HTTP/HTTPS to public internet
    if (!['http:', 'https:'].includes(parsed.protocol)) return false
    // Block internal networks
    if (parsed.hostname === 'localhost') return false
    if (parsed.hostname.startsWith('127.')) return false
    if (parsed.hostname.startsWith('10.')) return false
    if (parsed.hostname.startsWith('192.168.')) return false
    return true
  },
})

The default urlFilter allows URLs whose hostname starts with crl. or ocsp., contains .crl. or .ocsp., or whose path ends with .crl. Only HTTP and HTTPS protocols are permitted. Override it if your CA endpoints do not match these patterns.


CDN Deployment (Vanilla JS)

The @trexolab/verifykit-vanilla package produces a UMD bundle that can be loaded directly from a CDN or self-hosted:

CDN Usage

html
<script src="https://verifykit.trexolab.com/cdn/verifykit.umd.js"></script>
<link rel="stylesheet" href="https://verifykit.trexolab.com/cdn/verifykit.css" />
 
<div id="viewer" style="height: 100vh"></div>
 
<script>
  VerifyKit.create(document.getElementById('viewer'), {
    workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs',
  })
</script>

Self-Hosting

To self-host the UMD bundle:

  1. Copy the built files from packages/vanilla/dist/:

    • verifykit.umd.js — the main UMD bundle
    • verifykit.css — the viewer styles
  2. Serve them from your static file server or CDN.

  3. Reference them in your HTML:

html
<script src="/static/verifykit.umd.js"></script>
<link rel="stylesheet" href="/static/verifykit.css" />

Subresource Integrity (SRI)

When loading from a CDN, use SRI hashes to ensure the file has not been tampered with:

html
<script
  src="https://cdn.example.com/verifykit.umd.js"
  integrity="sha384-<hash>"
  crossorigin="anonymous"
></script>

Generate the hash with:

bash
cat verifykit.umd.js | openssl dgst -sha384 -binary | openssl base64 -A

AIA Network Implications

AIA (Authority Information Access) certificate chain resolution is enabled by default (enableAIA: true). When enabled, the core engine may make HTTP requests to CA-hosted URLs to fetch missing intermediate certificates. In production:

  • Ensure outbound HTTP access is available if AIA is enabled.
  • For air-gapped or restricted network environments, disable AIA: enableAIA: false.
  • AIA requests are cached in memory for the lifetime of the verifier instance.

Environment-Specific Notes

Next.js

  • Use dynamic(() => import(...), { ssr: false }) for the viewer component to avoid SSR issues with WASM and PDF.js.
  • The revocation proxy API route works with both Pages Router (pages/api/revocation.ts) and App Router (app/api/revocation/route.ts).
  • If using the Edge runtime, note that WASM support varies. The default Node.js runtime is recommended.

Vite

  • No special configuration is needed as of v0.3.1+. The base64-embedded WASM loads without vite-plugin-wasm.
  • For production builds, Vite will tree-shake unused exports automatically.

Webpack

  • No special configuration is needed as of v0.3.1+. Remove any asyncWebAssembly experiment configuration from older setups.

Node.js (Server-Side)

  • Requires Node.js >= 20.19.0.
  • WASM loads from the filesystem automatically. No HTTP server is needed for the WASM binary.
  • For large PDFs, increase memory with --max-old-space-size=4096.