Server-Side Rendering
How to use Sesamy with server-rendered pages. Even with SSR, you can use Sesamy's client-side components -- the server provides auth state, and sesamy-js handles the rest.
Overview
With SSR, your server renders the page before sending it to the browser. This creates two opportunities:
- Pre-populate auth state so sesamy-js knows the reader is logged in without an extra network call
- Check entitlements server-side for use cases like personalised content or SEO
The recommended approach combines Capsule encryption (content stays encrypted in the HTML, decrypted client-side) with server-injected auth state.
Injecting the id-token
When you use HttpOnly cookie auth with a reverse proxy, the server has access to the auth cookie on each request. You can decode the access token, extract the id-token claims, and inject them into the page so sesamy-js picks them up immediately.
Using the server-state element
Add a <script id="sesamy-server-state"> element with the id-token JWT:
<script type="application/json" id="sesamy-server-state">
{"idToken": "eyJhbGciOiJSUzI1NiIs..."}
</script>sesamy-js reads this element during initialisation. If the token is valid and not expired, the reader is treated as authenticated without calling /auth/userinfo.
Using the config property
If you initialise sesamy-js programmatically, pass the id-token via the config:
import { init } from '@sesamy/sesamy-js';
await init({
clientId: 'your-vendor-id',
auth: {
useHttpCookies: true,
idToken: serverProvidedIdToken,
},
capsule: { enabled: true },
});How to get the id-token on the server
The exact approach depends on your framework. The general pattern:
- Read the
at(access token) cookie from the incoming request - Decrypt it using the Token Handler encryption secret (or call the
/auth/userinfoendpoint with the cookie forwarded) - Extract the id-token claims (sub, name, email, exp, etc.)
- Inject the JWT string into the page HTML
Simpler approach: forward the cookie
If you do not want to decrypt the token yourself, your server can call GET /sesamy-api/auth/userinfo with the cookies forwarded. Use the response to mint a signed JWT with an exp claim and inject that as idToken — sesamy-js only accepts a JWT and will ignore raw JSON payloads.
Capsule with SSR
With Capsule, the encrypted content and the resourceJWT are already embedded in the HTML at publish time. The server does not need to fetch or prepare any content-related data.
The flow is:
- Server renders the page with the DCA manifest (encrypted content) and optionally the server-state element (id-token)
- Browser loads sesamy-js
- sesamy-js reads the id-token from the server-state element -- reader is authenticated immediately
- sesamy-js detects the DCA manifest, calls the unlock endpoint, decrypts the content, and injects it
The server never needs to handle content decryption.
Server-side entitlement checks
For cases where you need to know the reader's access level on the server (e.g. to render different layouts or for analytics), you can check entitlements via the Sesamy SDK:
import { client } from '@sesamy/sdk';
export async function getServerSideProps({ req }) {
// Forward the session cookie to the Sesamy API
const sesamyClient = client({
baseUrl: 'https://api2.sesamy.com',
headers: { cookie: req.headers.cookie },
});
const entitlements = await sesamyClient.entitlements.list();
const hasAccess = entitlements.some(e => e.sku === 'premium');
return { props: { hasAccess } };
}Do not skip client-side protection
Even if you check entitlements server-side, always use Capsule or another lock mode to protect the actual content. Server-side checks are useful for layout decisions, but the content itself should be encrypted or withheld to prevent it from leaking in cached HTML.
Next.js example
See the dedicated Next.js + Vercel guide for a complete example including Vercel Edge rewrites, server-side entitlement checks, and client-side Sesamy components.
When you cannot render per-user HTML
If your HTML is shared across readers (edge cache, static hosting, CDN-cached pages), you cannot inject a per-user sesamy-server-state element. In that case, use the Bootstrap Loader instead -- a tiny inline script that pre-fetches authentication state in parallel with the main bundle and sets a CSS class on <html> before first paint, so member-only blocks do not flash.
Next Steps
- Bootstrap Loader -- Alternative for shared-cache pages where per-user SSR is not possible
- Authentication Options -- Compare auth approaches for SSR
- Proxy Setup -- Configure your CDN for the reverse proxy pattern
- Content Protection -- Capsule encryption details