Just-in-Time (JIT) Hydration
By default, Volidator operates as a zero-knowledge system: sensitive fields like actor or target are encrypted client-side or statically redacted (e.g., replaced with [REDACTED:actor]) before they are stored on Volidator servers.
However, showing [REDACTED:actor] to compliance officers or admins makes audit trails difficult to read.
Just-in-Time (JIT) Hydration (also known as Reference-Based Redaction) solves this by replacing sensitive values with non-sensitive reference IDs (e.g., database primary keys like usr_890). When the dashboard is embedded in your application, it asks the host application to resolve these IDs on the fly in the browser via a secure postMessage handshake.
┌─────────────────┐ ┌───────────────────┐ ┌────────────────┐│ Host Portal │ │ Volidator Iframe │ │ Volidator API │└────────┬────────┘ └─────────┬─────────┘ └───────┬────────┘ │ │ │ │ │ Get Encrypted Logs │ │ ├──────────────────────────────>│ │ │ │ │ │ Decrypted: "[REF:usr_890]" │ │ |<──────────────────────────────┤ │ │ │ │ VOLIDATOR_RESOLVE_ACTORS │ │ │ ["usr_890"] │ │ |<───────────────────────────────┤ │ │ │ │ │ Resolve "usr_890" -> "John" │ │ ├──────────────────────────────┐ │ │ │ │ │ │ │<─────────────────────────────┘ │ │ │ │ │ │ VOLIDATOR_RESOLVE_RESPONSE │ │ │ { usr_890: { name: "John" } }│ │ ├───────────────────────────────>│ │ │ │ │ │ │ Renders "John" │ │ ├───────────────┐ │ │ │ │ │ │ │<──────────────┘ │1. Configure the SDK
Section titled “1. Configure the SDK”Specify which fields should use reference-based redaction using the referenceKeys option in your VolidatorClient constructor.
import { VolidatorClient } from '@volidator/node';
const volidator = new VolidatorClient({ apiKey: process.env.VOLIDATOR_API_KEY!, encryptionKey: process.env.VOLIDATOR_ENCRYPTION_KEY!, // Fields that will be stored as references referenceKeys: ['actor', 'metadata.ownerId'],});When logging, pass a ReferencePayload object { id, pii } instead of a plain string for any field listed in referenceKeys:
await volidator.log({ // 'actor' is a referenceKey actor: { id: 'usr_890', // Stored as "[REF:usr_890]" }, action: 'invoice.download', metadata: { // 'metadata.ownerId' is a referenceKey ownerId: { id: 'usr_456', } }});[!NOTE] The blind index is computed using the raw
piivalue ([email protected]). This ensures that searching by the actor’s real email in the dashboard still returns the correct logs, even though the plaintext email never leaves your system.
2. Generate Embed Token with hostOrigin
Section titled “2. Generate Embed Token with hostOrigin”When generating an embed token, you must pass the exact hostOrigin of the parent application embedding the iframe. This enables strict origin validation for the postMessage handshake, preventing unauthorized pages from reading or spoofing identity data.
const { embedUrl } = await volidator.generateEmbedToken({ actorId: session.userId, expiresIn: '2h', hostOrigin: 'https://app.yourcompany.com', // Parent origin});3. Install React Helpers
Section titled “3. Install React Helpers”Install the Volidator React package in your parent web application to simplify the handshake logic.
npm install @volidator/react4. Implement Hydration in the Host Page
Section titled “4. Implement Hydration in the Host Page”Use the useVolidatorHydration hook on the page rendering the Volidator iframe. This hook automatically listens for resolution requests, deduplicates and caches IDs, batches requests, and communicates securely with the iframe.
import { useRef } from 'react';import { useVolidatorHydration } from '@volidator/react';
export default function AuditLogsView({ embedUrl }: { embedUrl: string }) { const iframeRef = useRef<HTMLIFrameElement>(null);
useVolidatorHydration({ iframeRef, volidatorOrigin: 'https://dash.volidator.com', resolveActors: async (ids) => { // Call your backend API to map database IDs to display names const res = await fetch('/api/users/resolve', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ids }), }); return res.json(); // returns Record<string, { name: string; avatarUrl?: string }> }, });
return ( <iframe ref={iframeRef} src={embedUrl} width="100%" height="600" style={{ border: 'none' }} /> );}5. Implement the Backend Resolution API
Section titled “5. Implement the Backend Resolution API”On your backend, implement a batch endpoint that returns display names and optional avatars for the requested IDs.
// Next.js API Route Example (/pages/api/users/resolve.ts)import { NextApiRequest, NextApiResponse } from 'next';import { db } from '@/lib/db';
export default async function handler(req: NextApiRequest, res: NextApiResponse) { const { ids } = req.body as { ids: string[] };
// Fetch only the requested users from your database const users = await db.user.findMany({ where: { id: { in: ids } }, select: { id: true, name: true, image: true }, });
// Map to the required response structure const mapping = users.reduce((acc, user) => { acc[user.id] = { name: user.name, avatarUrl: user.image || undefined, }; return acc; }, {} as Record<string, { name: string; avatarUrl?: string }>);
return res.status(200).json(mapping);}Security & Edge Cases
Section titled “Security & Edge Cases”Strict Origin Verification
Section titled “Strict Origin Verification”To protect user privacy, both sides of the window handshake strictly enforce origins:
- The parent window ignores messages from any origin other than the configured
volidatorOrigin. - The embedded iframe ignores messages from any origin other than the
hostOriginspecified in the signed embed token.
Unresolved Identities
Section titled “Unresolved Identities”If an ID is not returned by the resolveActors callback (e.g., if a user was deleted from your database), the dashboard displays an amber warning badge:
⚠️ Unresolved: usr_890
Performance & Caching
Section titled “Performance & Caching”The useVolidatorHydration hook caches resolved identities inside a React useRef cache. When pagination or search updates the logs table, only new, uncached reference IDs are requested from your backend API. This completely avoids the N+1 queries problem and eliminates redundant network traffic.