Securely embed third-party scripts (chat widgets, analytics, forms) without hardcoding API keys in your HTML/JavaScript. Uses Service Worker + WebAssembly encryption for runtime credential injection with maximum security.
Modern websites need third-party embeds that require API keys:
<!-- DON'T DO THIS - API key visible to anyone -->
<script>
window.intercomSettings = { app_id: "abc123secret" };
</script>Anyone can view-source your page and steal your credentials.
SecureEmbed v2.0 uses WebAssembly to protect your security logic from reverse engineering:
- Credentials are encrypted at build time with domain-bound keys
- Service Worker + Wasm intercepts requests to embed providers
- Security logic is compiled to binary - algorithms can't be read from source
- Decryption happens in memory - credentials never appear in source code
- Domain verification ensures credentials only work on your site
npm install @olib-ai/secure-embed// embed.json
{
"provider": "intercom",
"credentials": {
"apiKey": "your-intercom-app-id"
},
"authorizedDomains": ["example.com", "www.example.com"]
}npx @olib-ai/secure-embed encrypt --config embed.json --output public/.secure-embedCopy these files to your public directory root:
# Service Worker (Wasm-protected)
cp node_modules/@olib-ai/secure-embed/dist/secure-sw.min.js public/secure-embed-sw.js
# WebAssembly crypto core
cp node_modules/@olib-ai/secure-embed/wasm/build/crypto-core.wasm public/secure-embed-core.wasmReact:
import { SecureEmbed } from '@olib-ai/secure-embed/react';
function App() {
return (
<SecureEmbed
provider="intercom"
configUrl="/.secure-embed/intercom.enc"
onLoad={() => console.log('Chat loaded!')}
onError={(err) => console.error(err)}
>
<div>Loading chat widget...</div>
</SecureEmbed>
);
}Vanilla JavaScript:
import { SecureEmbed } from '@olib-ai/secure-embed';
SecureEmbed.init({
provider: 'intercom',
configUrl: '/.secure-embed/intercom.enc'
}).then(() => {
console.log('Chat loaded!');
}).catch((err) => {
console.error('Failed to load:', err);
});- Intercom -
intercom - Crisp -
crisp - HubSpot -
hubspot - Drift -
drift
- Google Analytics -
google-analytics - Mixpanel -
mixpanel - Segment -
segment
- Typeform -
typeform - JotForm -
jotform
Use custom provider for any third-party script.
{
"provider": "intercom",
"credentials": {
"apiKey": "required-api-key",
"apiSecret": "optional-secret",
"metadata": {
"portalId": "for-hubspot",
"embedId": "for-drift"
}
},
"authorizedDomains": ["example.com"],
"expiresAt": "2025-12-31T23:59:59Z"
}| Prop | Type | Required | Description |
|---|---|---|---|
provider |
ProviderType |
Yes | The embed provider |
configUrl |
string |
Yes | URL to encrypted config |
containerId |
string |
No | Custom container element ID |
onLoad |
() => void |
No | Callback when loaded |
onError |
(error: Error) => void |
No | Error callback |
className |
string |
No | CSS class for container |
style |
CSSProperties |
No | Inline styles |
children |
ReactNode |
No | Loading state content |
fallback |
ReactNode |
No | Error state content |
import { useSecureEmbed } from '@olib-ai/secure-embed/react';
function MyComponent() {
const { init, destroy, isLoaded, isLoading, error, healthCheck } = useSecureEmbed();
useEffect(() => {
init({
provider: 'intercom',
configUrl: '/.secure-embed/intercom.enc',
});
return () => destroy('intercom');
}, [init, destroy]);
if (error) return <div>Error: {error.message}</div>;
if (isLoading) return <div>Loading...</div>;
return null;
}All security-critical operations are compiled to WebAssembly binary code:
- Cryptographic algorithms
- Domain validation logic
- Cache key generation
- Protocol message encoding
- Provider configurations
This makes reverse engineering extremely difficult compared to JavaScript.
Credentials are encrypted using a key derived from your domain. They can only be decrypted when running on an authorized domain.
Industry-standard authenticated encryption ensures both confidentiality and integrity.
100,000 iterations of PBKDF2-SHA256 make brute-force attacks impractical.
Optional credential expiration prevents stolen configs from working indefinitely.
SHA-384 hashes verify config files haven't been tampered with.
- Bounded cache (64 slots max)
- Automatic TTL-based eviction (1 hour)
- Explicit cleanup functions
- No memory leaks
┌─────────────────┐ ┌──────────────────────────────┐ ┌─────────────────┐
│ Build Time │ │ Runtime │ │ Provider │
├─────────────────┤ ├──────────────────────────────┤ ├─────────────────┤
│ │ │ │ │ │
│ embed.json │ │ Browser loads │ │ Intercom API │
│ │ │ │ encrypted .enc │ │ │
│ ▼ │ │ │ │ │ │
│ CLI encrypts │ │ ▼ │ │ │
│ with domain │────▶│ ┌────────────────────┐ │ │ │
│ key + salt │ │ │ Service Worker │ │ │ │
│ │ │ │ │ (9KB JS loader) │ │────▶│ Receives │
│ ▼ │ │ └─────────┬──────────┘ │ │ authenticated │
│ .enc file │ │ │ │ │ request │
│ │ │ ▼ │ │ │
│ │ │ ┌────────────────────┐ │ │ │
│ │ │ │ Wasm Crypto Core │ │ │ │
│ │ │ │ (21KB binary) │ │ │ │
│ │ │ │ - Decryption │ │ │ │
│ │ │ │ - Domain check │ │ │ │
│ │ │ │ - Cred injection │ │ │ │
│ │ │ └────────────────────┘ │ │ │
│ │ │ │ │ │
└─────────────────┘ └──────────────────────────────┘ └─────────────────┘
- Chrome 68+
- Firefox 61+
- Safari 11.1+
- Edge 79+
Requires Service Worker and WebAssembly support.
Full TypeScript support with strict types:
import type {
ProviderType,
EncryptedConfig,
CredentialPayload,
EmbedConfig,
} from '@olib-ai/secure-embed';import { SecureEmbed, init, destroy, healthCheck } from '@olib-ai/secure-embed';
// Initialize an embed
await init({ provider: 'intercom', configUrl: '/config.enc' });
// Destroy an embed
await destroy('intercom');
// Check if service worker is healthy
const isHealthy = await healthCheck();import { encryptCredentials, decryptCredentials, verifyIntegrity } from '@olib-ai/secure-embed';
// Encrypt credentials for deployment
const encrypted = await encryptCredentials(payload, domains, provider, expiresAt);
// Decrypt credentials (used internally by Service Worker)
const decrypted = await decryptCredentials(config, currentDomain);
// Verify the SHA-384 integrity hash
const isValid = await verifyIntegrity(config);import { loadWasmCore, getWasmCore, releaseWasmCore } from '@olib-ai/secure-embed';
// Load the Wasm module manually
const core = await loadWasmCore();
// Get the loaded instance
const instance = getWasmCore();
// Release resources
releaseWasmCore();| File | Size | Purpose |
|---|---|---|
secure-sw.min.js |
~9 KB | Service Worker loader |
crypto-core.wasm |
~21 KB | Security logic (binary) |
| Total | ~30 KB | Complete security layer |
- Service Workers require HTTPS (except localhost)
- WebAssembly must be supported by the browser
- Initial page load fetches encrypted config (small overhead)
- Some providers may detect Service Worker interception
# Build everything
npm run build
# Build Wasm only
npm run build:wasm
# Run demo server
npm run demo
# Type check
npm run typecheckMIT - Olib AI