CMS Integrations
An overview of the building blocks for integrating Sesamy into your CMS. This covers authentication strategies, content protection methods, and Sesamy's web components that the platform-specific guides build upon.
Authentication
Sesamy supports three authentication approaches. The right choice depends on your infrastructure.
Option 1: BFF with Reverse Proxy (Recommended)
The BFF (Backend for Frontend) pattern stores tokens in HttpOnly cookies that JavaScript can never read, eliminating the XSS token-theft surface entirely. Your backend proxies /auth/* and /api/* to the Sesamy API so that cookies are first-party.
Browser Your Server / CDN Edge Sesamy API
| | |
|-- GET /auth/login ---> |-- proxy --------------> |
|<- Set-Cookie --------- |<----------------------- |
| | |
|-- GET /api/entitlements |-- proxy --------------> |
| (cookie attached) | |
|<- data --------------- |<----------------------- |Setup: Configure your server (nginx, Vercel, Cloudflare, etc.) to proxy two paths:
| Path | Destination |
|---|---|
/auth/* | https://api.sesamy.com/auth/* |
/api/* | https://api.sesamy.com/* |
Then configure sesamy-js to use relative paths and cookie auth:
{
"clientId": "your-vendor-id",
"vendorId": "your-vendor-id",
"api": {
"endpoint": "/api"
},
"auth": {
"useHttpCookies": true
}
}Since all requests go to your own origin, cookies are first-party automatically. No custom domain or CNAME required.
Example: nginx
location /auth/ {
proxy_pass https://api.sesamy.com/auth/;
proxy_set_header Host api.sesamy.com;
proxy_set_header X-Forwarded-Host $host;
}
location /api/ {
proxy_pass https://api.sesamy.com/;
proxy_set_header Host api.sesamy.com;
proxy_set_header X-Forwarded-Host $host;
}Example: Vercel / Next.js
// next.config.ts
const nextConfig = {
async rewrites() {
return [
{ source: '/auth/:path*', destination: 'https://api.sesamy.com/auth/:path*' },
{ source: '/api/:path*', destination: 'https://api.sesamy.com/:path*' },
];
},
};Vercel runs rewrites at the Edge Network, so there is no cold-start overhead.
Option 2: BFF with Custom API Domain
If you cannot set up a reverse proxy, point a subdomain (e.g. api.yoursite.com) at the Sesamy API proxy via CNAME. The page and the API domain must share a top-level domain so the cookie is first-party.
DNS: api.yoursite.com CNAME api.sesamy.com{
"clientId": "your-vendor-id",
"vendorId": "your-vendor-id",
"api": {
"endpoint": "https://api.yoursite.com"
},
"auth": {
"useHttpCookies": true
}
}The session cookie is set as HttpOnly; SameSite=Lax by the server. Contact Sesamy to enable the Token Handler for your custom domain.
Option 3: SPA Auth (Auth0 Plugin)
For publishers who already use Auth0 or need popup/redirect login flows. Tokens are managed by @auth0/auth0-spa-js in the browser. This is simpler to set up but stores tokens in localStorage, which is accessible to any JavaScript on the page.
Via Scripts Host (no code change needed):
When your vendor has no custom apiDomain configured, the Scripts Host bundle automatically includes the Auth0 plugin. This is the default for existing integrations.
Via npm:
import { init } from '@sesamy/sesamy-js';
import { createAuth0Plugin } from '@sesamy/sesamy-js/auth0-plugin';
const sesamy = await init(
{
clientId: 'your-client-id',
auth: {
domain: 'login.yoursite.com', // your Auth0 custom domain
},
},
{ authPlugin: createAuth0Plugin() },
);Via script tags:
<script src="https://cdn.sesamy.com/sesamy-js/latest/auth0-plugin.iife.js"></script>
<script src="https://cdn.sesamy.com/sesamy-js/latest/sesamy-js.iife.js"></script>
<script type="application/json" id="sesamy-js">
{
"clientId": "your-client-id",
"auth": { "domain": "login.yoursite.com" }
}
</script>Which auth mode should I use?
| Criteria | BFF (Proxy) | BFF (Custom Domain) | SPA (Auth0) |
|---|---|---|---|
| Security | Best -- tokens never in JS | Best -- tokens never in JS | Good -- tokens in localStorage |
| Setup complexity | Medium -- requires proxy config | Low -- DNS CNAME only | Lowest -- no infra changes |
| Custom domain required | No | Yes | Optional (for Auth0) |
| Third-party cookie issues | None | None | Possible in Safari/Firefox |
| Recommended for | New integrations | Sites without proxy capability | Existing Auth0 integrations |
Content Protection
Sesamy offers several strategies for protecting premium content. They differ in security level and implementation complexity.
Strategy 1: Capsule Encryption (Recommended)
Capsule uses AES-256-GCM encryption to protect content at rest. The encrypted content is embedded directly in the HTML -- even if someone views the page source, they see only ciphertext. Keys are fetched from the server only after entitlement is verified.
<!-- DCA data embedded by your CMS/build tool -->
<script class="dca-data" type="application/json">
{
"version": "1",
"resource": { "resourceId": "article-123", ... },
"resourceJWT": "eyJ...",
"issuerData": {
"sesamy": {
"unlockUrl": "https://api.yoursite.com/capsule/vendors/your-vendor/dca/unlock",
"sealed": { ... },
"keyId": "premium"
}
},
...
}
</script>
<template class="dca-sealed-content">
<div data-dca-content-name="bodytext">U2FsdGVkX1...encrypted...</div>
</template>Enable capsule in your sesamy-js config:
{
"clientId": "your-vendor-id",
"vendorId": "your-vendor-id",
"capsule": {
"enabled": true
}
}sesamy-js will automatically:
- Detect the
<script class="dca-data">element on the page - Authenticate the user and call the unlock endpoint
- Decrypt all content items
- Inject the decrypted HTML into the page
Why Capsule?
- Content is encrypted at rest -- viewing page source reveals nothing
- No server-side content gating needed -- the HTML is always the same
- Works with static sites and CDNs -- no dynamic rendering required
- Share links supported via pre-signed tokens
- Cache-friendly -- encrypted pages can be cached like any other page
Strategy 2: Proxy Lock Mode
The content is stored on the server and fetched only after the user is authenticated and entitled. The page initially contains only a preview; the full content is never in the HTML source.
<sesamy-content-container
item-src="https://example.com/articles/premium-article"
publisher-content-id="article-123"
lock-mode="proxy"
>
<div slot="preview">
<p>This is a preview of the premium content...</p>
</div>
</sesamy-content-container>Good security, but requires the content to be available via URL for the proxy to fetch. Not suitable for fully static sites where content is baked into the HTML at build time.
Strategy 3: Encode Lock Mode
Content is base64-encoded in the page source and decoded client-side after authentication. Prevents casual copy-paste but is not cryptographically secure -- anyone who reads the page source can decode the content.
<sesamy-content-container
item-src="https://example.com/articles/encoded-article"
publisher-content-id="article-456"
lock-mode="encode"
>
<div slot="preview">
<p>Free preview...</p>
</div>
</sesamy-content-container>Strategy 4: Embed Lock Mode (CSS Hidden)
Content is present in the DOM but hidden with CSS until the user is authenticated. The least secure option -- the content is fully visible in the page source.
<sesamy-content-container
item-src="https://example.com/articles/embedded-article"
publisher-content-id="article-789"
lock-mode="embed"
>
<div slot="preview">
<p>Read the first paragraph for free...</p>
</div>
<div slot="locked">
<p>This content is hidden with CSS until unlocked.</p>
</div>
</sesamy-content-container>Strategy 5: Event Lock Mode
No content is managed by Sesamy. Instead, a sesamyUnlocked event fires when the user has access, and you handle the content display yourself.
<sesamy-content-container
item-src="https://example.com/articles/custom-article"
publisher-content-id="event-101"
lock-mode="event"
>
<div slot="preview">
<p>Subscribe to unlock this content.</p>
</div>
</sesamy-content-container>
<script>
document.addEventListener('sesamyUnlocked', (event) => {
const { publisherContentId } = event.detail;
// Fetch and display content however you like
fetchAndRenderContent(publisherContentId);
});
</script>Strategy 6: Fetch from API
For fully custom implementations, skip the web components and use the sesamy-js API directly to check entitlements and gate content in your own code.
window.addEventListener('sesamyJsReady', async () => {
const hasAccess = await window.sesamy.entitlements.hasAccess('premium-article-123');
if (hasAccess) {
document.querySelector('.premium-content').style.display = 'block';
} else {
document.querySelector('.paywall').style.display = 'block';
}
});Comparison
| Strategy | Security | Content in source? | CDN-friendly | Complexity |
|---|---|---|---|---|
| Capsule (DCA) | Excellent | Encrypted only | Yes | Low (auto-processed) |
| Proxy | Good | No | No (dynamic fetch) | Low |
| Encode | Low | Encoded (reversible) | Yes | Low |
| Embed (CSS) | None | Yes (plain text) | Yes | Lowest |
| Event | Depends on impl. | No | Depends | Medium |
| API fetch | Depends on impl. | No | Depends | Highest |
Web Components
Sesamy provides web components that handle authentication, paywall display, and content gating. They work with any HTML page or framework.
Loading the Components
The simplest way is via the Scripts Host, which bundles sesamy-js, the auth plugin, and the web components:
<script type="module" src="https://scripts.sesamy.com/s/YOUR_VENDOR_ID/bundle/stable"></script>sesamy-login
Renders a login/logout button with user avatar. Handles the full auth flow automatically.
<header>
<nav>
<a href="/">Home</a>
<sesamy-login></sesamy-login>
</nav>
</header>Style it with CSS custom properties:
sesamy-login {
--sesamy-font-family: 'Inter', sans-serif;
--sesamy-login-button-background: #1a1a1a;
--sesamy-login-button-color: white;
--sesamy-login-button-border-radius: 8px;
}See sesamy-login reference for all properties, events, and slots.
sesamy-paywall
Displays pricing options and purchase/subscribe buttons. Fetches its configuration from a settings-url endpoint managed via the Sesamy dashboard.
<sesamy-paywall
settings-url="https://api2.sesamy.com/paywalls/YOUR_VENDOR_ID/YOUR_PAYWALL_ID"
>
</sesamy-paywall>You can customize the features section with a slot:
<sesamy-paywall
settings-url="https://api2.sesamy.com/paywalls/YOUR_VENDOR_ID/YOUR_PAYWALL_ID"
price="4.99"
currency="EUR"
>
<div slot="features">
<ul>
<li>Unlimited access to all articles</li>
<li>Ad-free reading experience</li>
<li>Cancel anytime</li>
</ul>
</div>
</sesamy-paywall>Paywall without content lock
You can use <sesamy-paywall> on its own for subscription pages or donation pages -- it doesn't require a <sesamy-content-container>.
See sesamy-paywall reference for all properties, events, and slots.
sesamy-content-container
Manages content visibility based on the user's entitlements. Pair it with a <sesamy-paywall> for the full experience.
<article
publisher-content-id="article-123"
item-src="https://example.com/articles/premium-article"
>
<sesamy-paywall
settings-url="https://api2.sesamy.com/paywalls/YOUR_VENDOR_ID/YOUR_PAYWALL_ID"
></sesamy-paywall>
<sesamy-content-container lock-mode="proxy">
<div slot="preview">
<p>This preview is visible to everyone...</p>
</div>
</sesamy-content-container>
</article>Key attributes:
| Attribute | Description |
|---|---|
lock-mode | How content is protected: proxy, embed, encode, event |
access-level | Who can access: public, logged-in, entitlement |
item-src | URL identifying the content |
publisher-content-id | Your internal content ID |
pass | Semicolon-separated pass IDs for tier-based access |
See sesamy-content-container reference for the full API.
sesamy-visibility
A simple component for showing/hiding content based on authentication status. No entitlement check -- just logged in or not.
<sesamy-visibility>
<div slot="logged-in">
<p>Welcome back! <a href="#" onclick="window.sesamy.profile.openHostedAccountPage()">Manage account</a></p>
</div>
<div slot="not-logged-in">
<p>Log in to access your subscriptions.</p>
</div>
</sesamy-visibility>How Components Find Configuration
Components traverse the DOM upward to find configuration attributes. This means you can set shared properties on a parent element (typically an <article> tag) and all child components inherit them:
<article
publisher-content-id="article-123"
item-src="https://example.com/articles/premium-article"
price="4.99"
currency="EUR"
>
<!-- Both components inherit publisher-content-id, item-src, price, currency -->
<sesamy-paywall settings-url="..."></sesamy-paywall>
<sesamy-content-container lock-mode="proxy">
<div slot="preview">Preview...</div>
</sesamy-content-container>
</article>Putting It All Together
Here is a complete example combining BFF auth, Capsule encryption, and Sesamy components:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Premium Article</title>
<!-- Load Sesamy bundle (includes components + auth) -->
<script type="module" src="https://scripts.sesamy.com/s/YOUR_VENDOR_ID/bundle/stable"></script>
<!-- Override sesamy-js config for BFF auth + Capsule -->
<script type="application/json" id="sesamy-js">
{
"clientId": "your-vendor-id",
"vendorId": "your-vendor-id",
"api": { "endpoint": "/api" },
"auth": { "useHttpCookies": true },
"capsule": { "enabled": true }
}
</script>
</head>
<body>
<header>
<h1>My Publication</h1>
<sesamy-login></sesamy-login>
</header>
<article
publisher-content-id="article-2025-001"
item-src="https://example.com/articles/premium-article"
>
<h1>Premium Article Title</h1>
<p>This introduction is visible to everyone.</p>
<!-- Paywall: shown when user lacks access -->
<sesamy-paywall
settings-url="https://api2.sesamy.com/paywalls/YOUR_VENDOR_ID/YOUR_PAYWALL_ID"
></sesamy-paywall>
<!-- Encrypted content: decrypted automatically by Capsule -->
<script class="dca-data" type="application/json">
{ ... }
</script>
<template class="dca-sealed-content">
<div data-dca-content-name="bodytext">...encrypted...</div>
</template>
</article>
<sesamy-visibility>
<div slot="logged-in">
<a href="#" onclick="window.sesamy.profile.openHostedAccountPage()">My Account</a>
</div>
</sesamy-visibility>
</body>
</html>Related Resources
- Content Meta Tags -- How the scraper reads page metadata for content ingestion
- Static Website Integration -- Detailed lock mode examples
- Next.js + Vercel -- BFF setup with Vercel Edge rewrites
- sesamy-js Authentication -- Full auth API reference
- Component Reference -- All web components
- Scripts Host -- Bundle delivery and configuration