Skip to content

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:

  1. Pre-populate auth state so sesamy-js knows the reader is logged in without an extra network call
  2. 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:

html
<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:

typescript
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:

  1. Read the at (access token) cookie from the incoming request
  2. Decrypt it using the Token Handler encryption secret (or call the /auth/userinfo endpoint with the cookie forwarded)
  3. Extract the id-token claims (sub, name, email, exp, etc.)
  4. 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:

  1. Server renders the page with the DCA manifest (encrypted content) and optionally the server-state element (id-token)
  2. Browser loads sesamy-js
  3. sesamy-js reads the id-token from the server-state element -- reader is authenticated immediately
  4. 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:

typescript
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

Released under the MIT License.