Ory logo

Server-rendered auth without the cookie headaches

Server-side rendering made React apps faster and authentication harder. Ory’s packages for Next.js, TanStack Start and React Router move login flows and sessions to the server, and make cookies work on localhost and preview URLs too.

Cookies are how your application knows who made the credit card transaction, who deleted the spreadsheet, or who sent the email. Ory's security model relies on them, and getting them right across a server, a browser and a remote identity provider is harder than it should be, especially once your React app renders on the server.

Ory's server-side rendering packages for Next.js, TanStack Start and React Router handle this for you. They fetch Ory's login flows and sessions on the server, and they include a proxy that makes Ory Network's cookie-based authentication work on localhost and on preview deployments such as Vercel's.

The packages

There's one package per framework, and each gives you the same server-side helpers for flows and sessions, plus the proxy for local development and preview deployments. All three are stable as of version 1.0.

FrameworkPackageProxy runs asGet started
Next.js, App Router and Pages Router@ory/nextjsMiddleware (proxy.ts on Next.js 16 and later)Docs · Example
TanStack Start@ory/tanstack-startMiddlewareDocs · Example
React Router 7.9 and later, framework mode@ory/react-routerResource routeDocs · Example

Install the package for your framework together with Ory Elements:

npm install @ory/nextjs @ory/elements-react

Building for another framework? The three packages share a framework-neutral core, @ory/ssr, that you can use to write your own adapter.

Why server-side rendering?

The React ecosystem has shifted toward rendering the initial page on the server, sending HTML and some JavaScript to the user's browser, but handling navigation and user actions within React's lifecycle. This gives you fast initial renders and smooth client-side navigation at the same time. The approach comes with its own challenges, especially for applications that need user authentication. You now need to fetch the user's authentication flows, session and metadata on both the server and the browser. That makes the APIs exposed by your authentication system much harder to secure, because the server is now acting on behalf of the user.

Ory supports this type of setup as a first-class citizen. Flow and user data can be fetched securely from any environment, as long as the request includes the cookies Ory uses to attribute each request to its user.

With @ory/nextjs, a login page is a server component. The flow is fetched on the server with the user's cookies, and the browser receives the rendered form.

// app/auth/login/page.tsx
import { Login } from "@ory/elements-react/theme"
import "@ory/elements-react/theme/styles.css"
import { getLoginFlow, OryPageParams } from "@ory/nextjs/app"

import config from "@/ory.config"

export default async function LoginPage(props: OryPageParams) {
  const flow = await getLoginFlow(config, props.searchParams)

  if (!flow) {
    return null
  }

  return <Login flow={flow} config={config} />
}

The same goes for the session. Check it on the server, before any of the page reaches the browser.

// app/dashboard/page.tsx
import { getServerSession } from "@ory/nextjs/app"
import { redirect } from "next/navigation"

export default async function DashboardPage() {
  const session = await getServerSession()

  if (!session) {
    redirect("/auth/login")
  }

  return <h1>Welcome back, {session.identity?.traits.email}</h1>
}

Ory Proxy

To prevent cross-site tracking without the user's consent, the browser's security model restricts third-party cookies. In local development and preview environments, though, the URL you access your application under and your Ory Network project's URL aren't on the same site, which effectively makes Ory Network a third party to your application.

This limitation causes real issues in authentication setups, which is why the packages include a proxy helper that sits "in front" of your Ory Network project, inside your app. Rather than talking to Ory Network directly, the browser side of your application talks to this proxy, which forwards the request to Ory Network and rewrites the response dynamically so that the browser treats the cookies as local.

One file turns the proxy on. List the origins your app is served from, and Ory's APIs become available on each of them, so Ory's cookies are first-party.

// proxy.ts
import { createOryMiddleware } from "@ory/nextjs/middleware"

import oryConfig from "@/ory.config"

export const proxy = createOryMiddleware({
  ...oryConfig,
  trustedOrigins: [
    "http://localhost:3000",
    "https://my-app-*-my-team.vercel.app",
  ],
})

export const config = {}

The proxy is built for local development and preview deployments. Through it, Ory sees every request as coming from your app server instead of your user's browser. In production, add a custom domain to your Ory Network project so Ory runs on the same site as your app. The packages then talk to Ory directly.

Pair the packages with Ory Elements

While these packages are designed to work in any SSR-enabled React app where you want to use Ory, they work best with @ory/elements-react. Install both in your React web application to get server-side rendering along with Ory's best-in-class customization of the end-user experience.

Get started

Pick your starting point:

Don't have an Ory Network project yet? Create one for free and have a login page running in minutes.

We'd love to hear what you build. Open an issue or a discussion on GitHub, or join us in the Ory community Slack.

Further reading

<- Back to Blog