Skip to main content

Introduction

The Verification Center is an embeddable iframe that displays the status of Tinfoil’s enclave verification process. It shows users the cryptographic proof that their data is being processed in a verified secure enclave. You can see it live at chat.tinfoil.sh. This guide covers how to embed the Verification Center in your web application and feed it verification data from the Tinfoil JavaScript SDK.

Verification States

The Verification Center displays different states based on the verification results:
When all verification steps pass, users see confirmation that their data is protected:
Verification Center showing successful verification

Prerequisites

Install the Tinfoil JavaScript SDK:
npm install tinfoil

Basic Integration

The integration involves two parts: embedding the iframe and sending it verification data from the SDK.

1. Add the Iframe

<iframe
  id="tinfoil-verification"
  src="https://verification-center.tinfoil.sh"
  style="width: 420px; height: 100vh; border: none;"
  title="Tinfoil Verification Center"
></iframe>

2. Send Verification Data

Use the Tinfoil SDK to get the verification document and send it to the iframe via postMessage. You can use either TinfoilAI (OpenAI-compatible) or SecureClient (low-level):
import { TinfoilAI } from "tinfoil";

const client = new TinfoilAI({ apiKey: "<YOUR_API_KEY>" });
await client.ready();

const verificationDoc = await client.getVerificationDocument();
const iframe = document.getElementById("tinfoil-verification") as HTMLIFrameElement;

// Wait for the iframe to signal it's ready
window.addEventListener("message", (event) => {
  if (event.origin !== "https://verification-center.tinfoil.sh") return;

  if (event.data.type === "TINFOIL_VERIFICATION_CENTER_READY") {
    iframe.contentWindow?.postMessage(
      {
        type: "TINFOIL_VERIFICATION_DOCUMENT",
        document: verificationDoc,
      },
      "https://verification-center.tinfoil.sh"
    );
  }
});

URL Parameters

The Verification Center accepts these query parameters:
ParameterTypeDefaultDescription
darkModebooleanfalseEnable dark theme
showHeaderbooleantrueShow or hide the header
Example with dark mode enabled:
<iframe
  src="https://verification-center.tinfoil.sh?darkMode=true&showHeader=true"
  style="width: 420px; height: 100vh; border: none;"
  title="Tinfoil Verification Center"
></iframe>

PostMessage API

The Verification Center communicates with its parent window using the postMessage API.

Messages from the Iframe

Listen for these messages from the Verification Center:
window.addEventListener("message", (event) => {
  // Only handle messages from the Verification Center
  if (event.origin !== "https://verification-center.tinfoil.sh") return;

  switch (event.data.type) {
    case "TINFOIL_VERIFICATION_CENTER_READY":
      // Iframe is ready to receive verification data
      break;
    case "TINFOIL_REQUEST_VERIFICATION_DOCUMENT":
      // Iframe is requesting a fresh verification document
      break;
  }
});

Messages to the Iframe

Send verification data to the iframe:
iframe.contentWindow?.postMessage(
  {
    type: "TINFOIL_VERIFICATION_DOCUMENT",
    document: verificationDoc,
  },
  "https://verification-center.tinfoil.sh"
);

Complete Example

Here’s a complete integration with a sidebar layout:
<!DOCTYPE html>
<html>
<head>
  <style>
    .verification-sidebar {
      position: fixed;
      right: 0;
      top: 0;
      width: 420px;
      height: 100vh;
      transform: translateX(100%);
      transition: transform 200ms ease-in-out;
      border-left: 1px solid #e5e7eb;
      background: white;
      z-index: 40;
    }
    .verification-sidebar.open {
      transform: translateX(0);
    }
    .verification-sidebar iframe {
      width: 100%;
      height: 100%;
      border: none;
    }
  </style>
</head>
<body>
  <button id="verify-btn">Show Verification</button>

  <div id="sidebar" class="verification-sidebar">
    <iframe
      id="tinfoil-verification"
      src="https://verification-center.tinfoil.sh?darkMode=false&showHeader=true"
      title="Tinfoil Verification Center"
    ></iframe>
  </div>

  <script type="module">
    import { TinfoilAI } from "tinfoil";

    const iframe = document.getElementById("tinfoil-verification");
    const sidebar = document.getElementById("sidebar");
    const button = document.getElementById("verify-btn");

    let verificationDoc = null;
    let iframeReady = false;

    const client = new TinfoilAI({ apiKey: "<YOUR_API_KEY>" });

    async function initialize() {
      await client.ready();
      verificationDoc = await client.getVerificationDocument();

      if (iframeReady) {
        sendVerificationDocument();
      }
    }

    const VERIFICATION_CENTER_ORIGIN = "https://verification-center.tinfoil.sh";

    function sendVerificationDocument() {
      if (verificationDoc && iframe.contentWindow) {
        iframe.contentWindow.postMessage(
          {
            type: "TINFOIL_VERIFICATION_DOCUMENT",
            document: verificationDoc,
          },
          VERIFICATION_CENTER_ORIGIN
        );
      }
    }

    window.addEventListener("message", (event) => {
      if (event.origin !== VERIFICATION_CENTER_ORIGIN) return;

      if (event.data.type === "TINFOIL_VERIFICATION_CENTER_READY") {
        iframeReady = true;
        sendVerificationDocument();
      }

      if (event.data.type === "TINFOIL_REQUEST_VERIFICATION_DOCUMENT") {
        sendVerificationDocument();
      }
    });

    button.addEventListener("click", () => {
      sidebar.classList.toggle("open");
    });

    initialize();
  </script>
</body>
</html>

Understanding the Verification Document

The verification document contains the results of the three-step verification process:
interface VerificationDocument {
  // Repository and enclave information
  configRepo: string;           // GitHub repo (e.g., "tinfoilsh/confidential-deepseek-r1")
  enclaveHost: string;          // Enclave hostname
  releaseDigest: string;        // SHA256 digest of the release

  // Cryptographic measurements
  codeMeasurement: object;      // Measurement from Sigstore verification
  enclaveMeasurement: object;   // Measurement from enclave attestation
  codeFingerprint: string;      // SHA-256 fingerprint of code
  enclaveFingerprint: string;   // SHA-256 fingerprint of enclave

  // Verification status
  securityVerified: boolean;    // True if all checks passed
  steps: {
    fetchDigest: StepState;
    verifyCode: StepState;
    verifyEnclave: StepState;
    compareMeasurements: StepState;
    verifyCertificate: StepState;
  };
}

interface StepState {
  status: "pending" | "success" | "failed";
  error?: string;
}
The securityVerified field indicates whether all verification steps passed. Individual step statuses are available in the steps object for granular status display. The getVerificationDocument() method is available on both TinfoilAI and SecureClient. On TinfoilAI it returns a promise; on SecureClient it returns synchronously after ready() has resolved.

React Integration

For React applications, create a component that manages the iframe lifecycle:
import { useEffect, useRef, useState } from "react";
import { TinfoilAI } from "tinfoil";

interface VerificationCenterProps {
  apiKey: string;
  darkMode?: boolean;
  showHeader?: boolean;
}

export function VerificationCenter({
  apiKey,
  darkMode = false,
  showHeader = true,
}: VerificationCenterProps) {
  const iframeRef = useRef<HTMLIFrameElement>(null);
  const [verificationDoc, setVerificationDoc] = useState(null);
  const [iframeReady, setIframeReady] = useState(false);

  const iframeUrl = `https://verification-center.tinfoil.sh?darkMode=${darkMode}&showHeader=${showHeader}`;
  const VERIFICATION_CENTER_ORIGIN = "https://verification-center.tinfoil.sh";

  useEffect(() => {
    const client = new TinfoilAI({ apiKey });

    async function initialize() {
      await client.ready();
      const doc = await client.getVerificationDocument();
      setVerificationDoc(doc);
    }

    initialize();
  }, [apiKey]);

  useEffect(() => {
    if (iframeReady && verificationDoc && iframeRef.current?.contentWindow) {
      iframeRef.current.contentWindow.postMessage(
        {
          type: "TINFOIL_VERIFICATION_DOCUMENT",
          document: verificationDoc,
        },
        VERIFICATION_CENTER_ORIGIN
      );
    }
  }, [iframeReady, verificationDoc]);

  useEffect(() => {
    function handleMessage(event: MessageEvent) {
      if (event.origin !== VERIFICATION_CENTER_ORIGIN) return;

      if (event.data.type === "TINFOIL_VERIFICATION_CENTER_READY") {
        setIframeReady(true);
      }

      if (event.data.type === "TINFOIL_REQUEST_VERIFICATION_DOCUMENT") {
        if (verificationDoc && iframeRef.current?.contentWindow) {
          iframeRef.current.contentWindow.postMessage(
            {
              type: "TINFOIL_VERIFICATION_DOCUMENT",
              document: verificationDoc,
            },
            VERIFICATION_CENTER_ORIGIN
          );
        }
      }
    }

    window.addEventListener("message", handleMessage);
    return () => window.removeEventListener("message", handleMessage);
  }, [verificationDoc]);

  return (
    <iframe
      ref={iframeRef}
      src={iframeUrl}
      style={{ width: "420px", height: "100%", border: "none" }}
      title="Tinfoil Verification Center"
    />
  );
}

Next Steps

JavaScript SDK

Full SDK documentation for TinfoilAI and SecureClient

How Verification Works

Understanding the three-step verification process