What is your developer-dependent CMS actually costing you? Calculate your costs and get a full report
What is your developer-dependent CMS actually costing you? Calculate your costs and get a full report
Integrations
Learn how to work with Auth0 and Agility.
Auth0 is an easy to implement, adaptable authentication and authorization platform. Use Auth0 to allow users to sign up, login, and access protected Content or Pages on your Agility CMS powered website or application.
To get started with Auth0, sign up for a Free Account.

Next, you'll want to create an application by heading to Applications > Create Application.

Give you application a name and select the application type.

There are many ways to use Auth0 in your Applications and Websites. For this example, we will be creating a site powered by Next.js (App Router) and Agility CMS, paired with Auth0's `@auth0/nextjs-auth0` NPM package (v4).
Once you've created your application head to Settings and take note of your Domain, Client ID, and Client Secret as we'll need to use this in our application later.

Scroll down the page to Application URIs. Set Allowed Callback URLs to http://localhost:3000/auth/callback and Allowed Logout URLs to http://localhost:3000, and add the same paths on your production domain when you deploy.

Feel free to look through and update the other Application Properties as needed. Once you're done, click Save.

We'll want to add authentication to an Agility CMS powered website. Sign up for a Free Agility CMS Account. Once you have an account, you'll be able to select a starter and create an Instance.
For this example, we'll be using the Next.js Blog Starter Template.
Getting Started with Agility CMS
We may want to set up Protected Pages in Agility that only grants users who have access to an account visibility to that Page.
To add a Page in Agility, head to Pages and click the New Page Button.

Select a Page Model and give your Page a Title.

Add a Rich Text Area component with some top secret information.

Make sure to save your changes.
To make this Page Protected, heat to the Settings of the Page and enable the Secure Page on Website toggle.

Make sure to save your changes.
Create protected pages under a folder in your sitemap (this example uses /members), so your site can keep them out of its static, cached pages. Step 5 below shows why.
The last step is to add Authentication within our Agility CMS powered website.
We will be using the Agility CMS Next.js Starter (App Router, Next.js 16) as the boilerplate for our Authentication implementation.
The Next.js Starter (agilitycms.com)
Once you have a copy of the starter running locally on your machine, add the @auth0/nextjs-auth0 package as a dependency. The current SDK needs a recent Next.js 16 release, so update Next.js first if npm reports a peer dependency conflict.
npm install next@latest
npm install @auth0/nextjs-auth0Remember those Auth0 credentials we asked you to save earlier? You'll want to include them as Environment Variables in your .env.local file.
AUTH0_DOMAIN=
AUTH0_CLIENT_ID=
AUTH0_CLIENT_SECRET=
AUTH0_SECRET=
APP_BASE_URL=http://localhost:3000To retrieve your Auth0 Secret, you can run the following code snippet in the command line:
openssl rand -hex 32This will return long secret value used to encrypt the session cookie.
AUTH0_DOMAIN is the Domain from your Auth0 application settings, and APP_BASE_URL is the URL of your site. Set all five on your hosting provider too, with APP_BASE_URL pointing at your production domain.
Create lib/auth0.ts with a single Auth0 client for the whole app:
// lib/auth0.ts
import { Auth0Client } from "@auth0/nextjs-auth0/server"
export const auth0 = new Auth0Client()The starter already has a proxy.ts (the Next.js 16 name for middleware) that handles Agility preview requests. Run the Auth0 middleware at the top of it, let the SDK answer its own routes, send signed-out visitors away from members-only pages, and return the Auth0 response at the end so the session cookie stays fresh:
import { NextResponse } from "next/server"
import type { NextRequest } from "next/server"
import { getDynamicPageURL } from "@agility/nextjs/node"
import { auth0 } from "./lib/auth0"
export async function proxy(request: NextRequest) {
// Let the Auth0 SDK handle its own routes and keep the session cookie fresh
const authResponse = await auth0.middleware(request)
if (request.nextUrl.pathname.startsWith("/auth/")) {
return authResponse
}
// Members-only pages: send signed-out visitors to the login page first
if (request.nextUrl.pathname.startsWith("/members/")) {
const session = await auth0.getSession(request)
if (!session) {
const loginUrl = new URL("/auth/login", request.nextUrl.origin)
loginUrl.searchParams.set("returnTo", request.nextUrl.pathname)
return NextResponse.redirect(loginUrl)
}
}
// ...the starter's existing Agility preview and ContentID handling (unchanged)
return authResponse
}The SDK now mounts these routes for you. There are no route files to create:
# The route used to perform login with Auth0.
/auth/login
# The route used to log the user out.
/auth/logout
# The route Auth0 will redirect the user to after a successful login.
/auth/callback
# The route to fetch the user profile from.
/auth/profile
# The route to fetch an access token from.
/auth/access-tokenThe starter prerenders every page in your sitemap (dynamic = "force-static" with revalidate = 60). That's what makes it fast, but a protected page rendered that way would end up in publicly cached HTML, and a static render can't read the visitor's session cookie. Put protected pages under a folder in your Agility sitemap (this example uses /members) and leave them out of the starter's catch-all route. As a safety net, any page flagged Secure Page on Website that isn't under /members returns a 404 instead of rendering publicly:
// app/[...slug]/page.tsx (two additions to the starter)
export async function generateStaticParams() {
// ...the starter's existing sitemap fetch
const paths = Object.values(sitemap)
.filter((node, index) => {
if (node.redirect !== null || node.isFolder === true || index === 0) return false
// members-only pages are rendered per request by app/members/[...slug]
if (node.path.startsWith("/members/")) return false
return true
})
.map((node) => ({ slug: node.path.split("/").slice(1) }))
return paths
}
export default async function Page({ params }: PageProps) {
const agilityData = await getAgilityPage({ params })
if (!agilityData.page) notFound()
// a page marked "Secure Page on Website" outside /members must never render publicly
if (agilityData.page.securePage) notFound()
// ...render as before
}Create app/members/[...slug]/page.tsx. It renders on every request, checks the session, and only then fetches and renders the Agility page:
// app/members/[...slug]/page.tsx
import { notFound, redirect } from "next/navigation"
import { auth0 } from "lib/auth0"
import { getAgilityPage } from "lib/cms/getAgilityPage"
import { getPageTemplate } from "components/agility-pages"
// Render on every request: never prerender or cache protected content
export const dynamic = "force-dynamic"
export default async function MembersPage({ params }: { params: Promise<{ slug: string[] }> }) {
const { slug } = await params
const path = `/members/${slug.join("/")}`
const session = await auth0.getSession()
if (!session) redirect(`/auth/login?returnTo=${encodeURIComponent(path)}`)
const agilityData = await getAgilityPage({
params: Promise.resolve({ slug: ["members", ...slug] }),
})
if (!agilityData.page) notFound()
const AgilityPageTemplate = getPageTemplate(agilityData.pageTemplateName || "")
if (!AgilityPageTemplate) notFound()
return <AgilityPageTemplate {...agilityData} />
}The proxy redirects signed-out visitors before the request reaches the page, and the page checks the session again itself, so protected content is never served from a cache or to an anonymous visitor. To show login state in a Client Component (for example, a header link), use the SDK's useUser() hook from @auth0/nextjs-auth0, and link to /auth/login and /auth/logout.
If you try to access the Protected Page, it will now redirect you to login.

Once you authenticate, you'll be able to see the Protected Pages Content!!
