- NextAuth v5 credentials auth with registration/login pages - API key CRUD (create, list, revoke) with secure hashing - Stripe checkout, webhooks, and customer portal integration - Rate limiting per subscription tier - All dashboard API endpoints scoped to authenticated user - Prisma schema: User, Account, Session, ApiKey, plus Stripe fields - Auth middleware protecting dashboard and API routes Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-Claude) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
51 lines
1.3 KiB
TypeScript
51 lines
1.3 KiB
TypeScript
import NextAuth from "next-auth";
|
|
import { NextResponse } from "next/server";
|
|
import authConfig from "./auth.config";
|
|
|
|
const { auth } = NextAuth(authConfig);
|
|
|
|
const publicPaths = [
|
|
"/",
|
|
"/docs",
|
|
"/api/auth",
|
|
"/api/traces",
|
|
"/api/health",
|
|
];
|
|
|
|
function isPublicPath(pathname: string): boolean {
|
|
return publicPaths.some(
|
|
(p) => pathname === p || pathname.startsWith(`${p}/`)
|
|
);
|
|
}
|
|
|
|
export default auth((req) => {
|
|
const { pathname } = req.nextUrl;
|
|
const isLoggedIn = !!req.auth;
|
|
|
|
if (isPublicPath(pathname)) {
|
|
if (isLoggedIn && (pathname === "/login" || pathname === "/register")) {
|
|
return NextResponse.redirect(new URL("/dashboard", req.nextUrl.origin));
|
|
}
|
|
return NextResponse.next();
|
|
}
|
|
|
|
if (pathname === "/login" || pathname === "/register") {
|
|
if (isLoggedIn) {
|
|
return NextResponse.redirect(new URL("/dashboard", req.nextUrl.origin));
|
|
}
|
|
return NextResponse.next();
|
|
}
|
|
|
|
if (pathname.startsWith("/dashboard") && !isLoggedIn) {
|
|
const loginUrl = new URL("/login", req.nextUrl.origin);
|
|
loginUrl.searchParams.set("callbackUrl", pathname);
|
|
return NextResponse.redirect(loginUrl);
|
|
}
|
|
|
|
return NextResponse.next();
|
|
});
|
|
|
|
export const config = {
|
|
matcher: ["/((?!_next/static|_next/image|favicon.ico|og-image.png).*)"],
|
|
};
|