SSR Frameworks
SSR Frameworks Connect a Nuxt, Next.js, SvelteKit, or Remix app to Enfyra with same-origin REST, OAuth cookies, refresh-token support, and Socket.IO. Integration Model Browser -> your SSR app origin -> local Enfyra proxy prefix -> Enfyra app /api and /ws bridge -> Enfyra server D
SSR Frameworks
Connect a Nuxt, Next.js, SvelteKit, or Remix app to Enfyra with same-origin REST, OAuth cookies, refresh-token support, and Socket.IO.
Integration Model
Browser
-> your SSR app origin
-> local Enfyra proxy prefix
-> Enfyra app /api and /ws bridge
-> Enfyra server
Do not call the raw Enfyra server from browser code. Browser code should call your app origin only.
Required Proxies
Expose two paths from your app:
| Local path | Forward to | Purpose |
|---|---|---|
/enfyra/** |
https://demo.enfyra.io/api/** |
REST, auth, OAuth, files, GraphQL |
/socket.io/** |
https://demo.enfyra.io/ws/socket.io/** |
Socket.IO transport |
You may choose another REST prefix, but keep it stable. If your prefix is /enfyra, OAuth must pass cookieBridgePrefix=/enfyra.
Shared Browser Code
After the proxy exists, browser calls are the same in every SSR framework.
Password login:
await fetch("/enfyra/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "include",
body: JSON.stringify({ email, password, remember: true }),
})
Current user:
const me = await fetch("/enfyra/me", {
credentials: "include",
})
OAuth starts on the Enfyra app URL, then returns through your app proxy:
const redirect = new URL("/chat", window.location.origin)
const url = new URL("/api/auth/google", "https://demo.enfyra.io")
url.searchParams.set("redirect", redirect.toString())
url.searchParams.set("cookieBridgePrefix", "/enfyra")
window.location.href = url.toString()
Socket.IO:
import { io } from "socket.io-client"
const socket = io("/chat", {
path: "/socket.io",
withCredentials: true,
reconnection: false,
transports: ["polling"],
upgrade: false,
})
/chat is the Enfyra websocket namespace. /socket.io is the transport path your SSR app proxies to the Enfyra app websocket bridge.
The demo chat apps use polling-only Socket.IO because it works consistently through simple SSR framework rewrites and reverse proxies. If your deployment proxy supports websocket upgrade cleanly, you can enable websocket transport later.
OAuth Flow
User clicks Google
-> https://demo.enfyra.io/api/auth/google?redirect=...&cookieBridgePrefix=/enfyra
-> Enfyra redirects to Google
-> Google returns to Enfyra callback
-> Enfyra redirects through {yourAppOrigin}/enfyra/auth/set-cookies
-> the proxy response sets cookies on your app origin
-> browser returns to redirect
The user does not handle tokens manually.
Nuxt
Use routeRules.
export default defineNuxtConfig({
routeRules: {
"/enfyra/**": {
proxy: {
to: "https://demo.enfyra.io/api/**",
fetchOptions: { redirect: "manual" },
},
},
"/socket.io/**": {
proxy: {
to: "https://demo.enfyra.io/ws/socket.io/**",
},
},
},
})
redirect: "manual" keeps OAuth and set-cookie redirects under your app origin.
Next.js
Use rewrites().
const nextConfig = {
async rewrites() {
return [
{
source: "/enfyra/:path*",
destination: "https://demo.enfyra.io/api/:path*",
},
{
source: "/socket.io/",
destination: "https://demo.enfyra.io/ws/socket.io/",
},
]
},
}
export default nextConfig
For server components, forward the incoming cookie header when fetching through your own app URL:
import { cookies } from "next/headers"
const res = await fetch(`${process.env.NEXT_PUBLIC_APP_URL}/enfyra/me`, {
headers: { cookie: (await cookies()).toString() },
cache: "no-store",
})
SvelteKit
Use a server hook for the REST/auth prefix.
import type { Handle } from "@sveltejs/kit"
const ENFYRA_API = "https://demo.enfyra.io/api"
export const handle: Handle = async ({ event, resolve }) => {
if (!event.url.pathname.startsWith("/enfyra/")) {
return resolve(event)
}
const upstream = new URL(
event.url.pathname.replace(/^\/enfyra/, ""),
ENFYRA_API,
)
upstream.search = event.url.search
return fetch(upstream, {
method: event.request.method,
headers: event.request.headers,
body:
event.request.method === "GET" || event.request.method === "HEAD"
? undefined
: event.request.body,
redirect: "manual",
})
}
Configure your deployment proxy to forward /socket.io/** to https://demo.enfyra.io/ws/socket.io/**.
Remix
Create a catch-all resource route for /enfyra/*.
import type { ActionFunctionArgs, LoaderFunctionArgs } from "@remix-run/node"
const ENFYRA_API = "https://demo.enfyra.io/api"
async function proxy(request: Request, params: { "*": string }) {
const url = new URL(request.url)
const upstream = new URL(`/${params["*"] ?? ""}`, ENFYRA_API)
upstream.search = url.search
return fetch(upstream, {
method: request.method,
headers: request.headers,
body:
request.method === "GET" || request.method === "HEAD"
? undefined
: request.body,
redirect: "manual",
})
}
export const loader = ({ request, params }: LoaderFunctionArgs) =>
proxy(request, params)
export const action = ({ request, params }: ActionFunctionArgs) =>
proxy(request, params)
Configure your hosting proxy to forward /socket.io/** to https://demo.enfyra.io/ws/socket.io/**.
Common Mistakes
Missing cookieBridgePrefix
If the app proxy prefix is /enfyra, OAuth must include:
cookieBridgePrefix=/enfyra
Without this, Enfyra uses the default /api cookie bridge, which is correct for the Enfyra app itself but wrong for a third-party app using /enfyra.
Starting OAuth from the wrong origin
The production demo chat apps start OAuth on the Enfyra app URL:
new URL("/api/auth/google", "https://demo.enfyra.io")
They do not start Google OAuth at /enfyra/auth/google. The local /enfyra/** proxy is still required for the later /enfyra/auth/set-cookies bridge.
Calling the backend host from browser code
Avoid:
fetch("https://raw-server.example.com/project_task")
Use:
fetch("/enfyra/project_task", { credentials: "include" })
Connecting to /ws/chat
Do not treat Enfyra realtime as a raw WebSocket path. Use Socket.IO namespace plus transport path:
io("/chat", { path: "/socket.io", withCredentials: true })
Next Step
After your framework is integrated, build a real feature with Third-Party Chat App Example.