@sendoracloud/sdk-web-ssr
v0.2.0
Published
Sendora Cloud server-side Web SDK — HttpOnly-cookie session helpers, Next.js / Remix / SvelteKit middleware + RSC clients. Pairs with @sendoracloud/sdk-web (peer dep) for the browser-side surface.
Maintainers
Readme
@sendoracloud/sdk-web-ssr
Server-side companion to @sendoracloud/sdk-web.
For Next.js (App Router), Remix, SvelteKit, SolidStart, or any framework with a server runtime where Sendora sessions live in HttpOnly cookies. For pure SPA / browser-only apps, use @sendoracloud/sdk-web instead.
Why
Storing session tokens in localStorage (the default for @sendoracloud/sdk-web) is fine for SPAs but exposes them to any XSS payload that runs on your origin. The industry-standard secure posture for framework apps is:
- Tokens in HttpOnly + Secure + SameSite cookies — JS can't read them.
- Refresh-token rotation with reuse detection — a stolen refresh cookie is single-use and triggers a family-wide revoke on replay.
- CSRF double-submit for any cookie-authenticated mutation.
- Edge middleware that gates protected routes without an extra round trip per request.
This package wraps all four behind a small surface so your middleware.ts and RSC code stay clean.
Install
npm install @sendoracloud/sdk-web-ssr @sendoracloud/sdk-web@sendoracloud/sdk-web is an optional peer dependency, only required if you import the ./client subpath (browser-side surface — analytics, feature flags, surveys, in-app messaging, chatbot, auth-from-the-browser). Pure middleware / server / token decode usage doesn't need it.
Targets Node 18+, Bun, Deno, and the Next.js Edge runtime. Zero non-peer runtime dependencies.
Subpath exports
| Subpath | Use it from | What it has |
|---|---|---|
| ./middleware | middleware.ts (edge runtime) | sendoraMiddleware() route gate |
| ./server | RSC, route handlers, server actions | createSendoraServerClient() |
| ./client | client components ("use client") | re-export of @sendoracloud/sdk-web |
| . | anywhere | low-level token decode + cookie name constants |
The ./client subpath is a pure re-export, not a bundle — @sendoracloud/sdk-web is resolved as a peer dep so version compatibility is explicit and tree-shaking deduplicates it.
Next.js — middleware
// middleware.ts
import { sendoraMiddleware } from "@sendoracloud/sdk-web-ssr/middleware";
export default sendoraMiddleware({
publicKey: process.env.NEXT_PUBLIC_SENDORA_KEY!,
protected: ["/dashboard", "/account"],
publicPaths: ["/login", "/api/public"],
loginPath: "/login",
});
export const config = {
matcher: "/((?!_next/static|_next/image|favicon.ico).*)",
};Per request: pass-through if cookie is valid, silent rotation if access expired but refresh present, redirect to /login?from=… otherwise.
Next.js — client components
"use client";
import { SendoraCloud } from "@sendoracloud/sdk-web-ssr/client";
const sendora = SendoraCloud.init({ apiKey: process.env.NEXT_PUBLIC_SENDORA_KEY! });
export function TrackButton() {
return <button onClick={() => sendora.track("button.clicked")}>Click</button>;
}Next.js — server components + route handlers
import { cookies } from "next/headers";
import { createSendoraServerClient } from "@sendoracloud/sdk-web-ssr/server";
export default async function Dashboard() {
const sendora = createSendoraServerClient(cookies(), {
publicKey: process.env.NEXT_PUBLIC_SENDORA_KEY!,
});
const session = sendora.getSession();
if (!session) return <p>Not signed in.</p>;
return <p>Hello {session.email}</p>;
}Server actions — sign in / sign out
"use server";
import { cookies } from "next/headers";
import { createSendoraServerClient } from "@sendoracloud/sdk-web-ssr/server";
export async function signOut() {
const sendora = createSendoraServerClient(cookies(), {
publicKey: process.env.NEXT_PUBLIC_SENDORA_KEY!,
});
await sendora.signOut();
}Sign-in (email + password, magic link, social, etc.) calls Sendora's /auth-service/login-family endpoints from a server action with credentials: "include". The backend sets the cookies on the response — the framework forwards them automatically.
Token verification model
getSession() decodes the JWT and checks expiry. It does not verify the RS256 signature locally — that would require fetching JWKS on every render and defeat the cookie-cache speed. The Sendora backend re-verifies the signature on every protected API call, which is the authoritative gate. The cookie's HttpOnly + Secure + SameSite attributes guarantee it can only have come from a real backend response.
If you need strict signature verification in middleware (financial dashboards, compliance tooling), use the lower-level decodeAccessToken + your own JWKS fetcher.
License
Apache-2.0
