@yescure/auth-nextjs
v0.1.2
Published
Next.js App Router adapter for YesCure authentication
Maintainers
Readme
@yescure/auth-nextjs
Next.js App Router adapter for YesCure authentication. Drop in three files and you're done.
Install
npm install @yescure/auth-nextjs1. Configure once
// lib/auth.ts
import { createYescureAuth } from "@yescure/auth-nextjs";
export const { handlers, auth, requireAuth, middleware } = createYescureAuth({
issuer: process.env.OIDC_ISSUER!,
clientId: process.env.OIDC_CLIENT_ID!,
clientSecret: process.env.OIDC_CLIENT_SECRET!,
redirectUri: process.env.OIDC_REDIRECT_URI!, // https://yourapp.com/api/auth/callback
sessionSecret: process.env.SESSION_SECRET!, // openssl rand -hex 32
backchannelLogoutSecret: process.env.YESCURE_BACKCHANNEL_LOGOUT_SECRET,
onLogin: async ({ claims }) => {
const user = await db.upsertUser({
yescure_sub: claims.sub,
email: claims.email,
name: claims.preferred_username,
});
return { role: user.role }; // merged into session cookie
},
});2. Wire the catch-all route
// app/api/auth/[...yescure]/route.ts
import { handlers } from "@/lib/auth";
export const { GET, POST } = handlers;This single file registers all four endpoints:
| URL | What it does |
|-----|--------------|
| /api/auth/login | Starts the OIDC flow |
| /api/auth/callback | Handles the YesCure redirect |
| /api/auth/logout | Clears the session cookie |
| /api/auth/backchannel-logout | Receives SSO logout from YesCure |
3. Protect routes
Option A — middleware (recommended)
// middleware.ts
import { middleware } from "@/lib/auth";
export default middleware({
publicPaths: ["/", "/login", "/about", "/api/health"],
});
export const config = {
matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};Option B — per route handler
// app/api/me/route.ts
import { requireAuth } from "@/lib/auth";
export const GET = requireAuth(async (_req, session) => {
return Response.json({ user: session });
});Option C — Server Component
// app/dashboard/page.tsx
import { auth } from "@/lib/auth";
import { redirect } from "next/navigation";
export default async function Dashboard() {
const session = await auth();
if (!session) redirect("/api/auth/login?next=/dashboard");
return <div>Hello {session.name}</div>;
}Login / logout buttons
<a href="/api/auth/login">Sign in</a>
<a href="/api/auth/logout">Sign out</a>That's it. There's no provider component to wrap the app in, no client-side state library, no JWT decoding in the browser — just a signed HttpOnly cookie that auth() decodes on the server.
Configuration reference
| Option | Required | Description |
|--------|----------|-------------|
| issuer | ✓ | YesCure issuer URL |
| clientId | ✓ | From yescure-admin |
| clientSecret | confidential clients only | |
| redirectUri | ✓ | Must match the one registered |
| sessionSecret | ✓ | ≥32 chars |
| backchannelLogoutSecret | recommended | |
| basePath | | Default: "/api/auth" |
| defaultReturnTo | | Default: "/" |
| loginRedirect | | Default: "/api/auth/login" |
| cookieDomain | | Set for cross-subdomain SSO |
| onLogin | | Persist user to your DB, return extra session fields |
| onBackchannelLogout | | Record revocation |
| isSessionRevoked | | Reject sessions revoked by SSO logout |
Backchannel logout (SSO across apps)
Register https://yourapp.com/api/auth/backchannel-logout in yescure-admin and provide its shared secret as backchannelLogoutSecret. When any YesCure-integrated app fires a full logout, this endpoint is called for every app. Persist the event in your DB and use isSessionRevoked to block stale sessions:
onBackchannelLogout: async ({ sub }) => {
await db.recordLogout(sub, new Date());
},
isSessionRevoked: async (session) => {
const row = await db.getLogout(session.sub);
return row ? session.iat < row.revoked_at_seconds : false;
},