feat: user auth, API keys, Stripe billing, and dashboard scoping
- 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>
This commit is contained in:
50
apps/web/src/middleware.ts
Normal file
50
apps/web/src/middleware.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
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).*)"],
|
||||
};
|
||||
Reference in New Issue
Block a user