Files
flatrender/src/middleware.ts
T

44 lines
1.4 KiB
TypeScript
Raw Normal View History

import { type NextRequest, NextResponse } from "next/server";
import createIntlMiddleware from "next-intl/middleware";
import { routing } from "@/i18n/routing";
import { ACCESS_TOKEN_COOKIE } from "@/lib/auth/constants";
import { decodeJwt, isJwtExpired } from "@/lib/auth/jwt";
const handleI18n = createIntlMiddleware(routing);
// Routes that require an authenticated Identity session (optionally /en/-prefixed).
const PROTECTED = /^\/(?:en\/)?(?:dashboard|studio)(?:\/|$)/;
export async function middleware(request: NextRequest) {
// 1. Locale detection / redirect (next-intl)
const i18nResponse = handleI18n(request);
if (
i18nResponse.status !== 200 ||
i18nResponse.headers.has("location")
) {
return i18nResponse;
}
// 2. Auth guard for protected sections
const { pathname } = request.nextUrl;
if (PROTECTED.test(pathname)) {
const token = request.cookies.get(ACCESS_TOKEN_COOKIE)?.value;
if (!token || isJwtExpired(decodeJwt(token))) {
const url = request.nextUrl.clone();
url.pathname = pathname.startsWith("/en") ? "/en/auth" : "/auth";
url.searchParams.set("next", pathname);
return NextResponse.redirect(url);
}
}
return i18nResponse;
}
export const config = {
// Match all routes except api, _next, static assets
matcher: [
"/((?!api|_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
],
};