Skip to content

Commit 17737b8

Browse files
committed
Enhance security and caching strategies in Next.js configuration: Updated next.config.ts to implement no-cache headers for auth-sensitive pages and added comprehensive security headers. Removed obsolete favicon and icon files. Refactored layout and page components to disable caching for dynamic content, ensuring proper auth state updates. Improved API route handling for user session management and enhanced error handling in AuthContext.
1 parent a743a50 commit 17737b8

18 files changed

Lines changed: 676 additions & 189 deletions

File tree

nextjs/next.config.ts

Lines changed: 100 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,9 @@ const nextConfig: NextConfig = {
117117
// Enhanced security and SEO headers
118118
async headers() {
119119
return [
120+
// No cache for main pages that depend on auth state
120121
{
121-
source: "/(.*)",
122+
source: "/",
122123
headers: [
123124
// Security headers
124125
{
@@ -145,10 +146,106 @@ const nextConfig: NextConfig = {
145146
key: "Strict-Transport-Security",
146147
value: "max-age=31536000; includeSubDomains; preload",
147148
},
148-
// Performance and caching headers
149+
// Disable caching for auth-sensitive pages
149150
{
150151
key: "Cache-Control",
151-
value: "public, max-age=31536000, immutable",
152+
value: "no-store, no-cache, must-revalidate, private",
153+
},
154+
// SEO and crawling headers
155+
{
156+
key: "X-Robots-Tag",
157+
value: "index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1",
158+
},
159+
// Content security headers
160+
{
161+
key: "Content-Security-Policy",
162+
value: [
163+
"default-src 'self'",
164+
"script-src 'self' 'unsafe-eval' 'unsafe-inline' https://www.googletagmanager.com https://www.google-analytics.com https://cdn.auth0.com https://vercel.live",
165+
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
166+
"img-src 'self' data: blob: https: http:",
167+
"font-src 'self' https://fonts.gstatic.com",
168+
"connect-src 'self' https://api.pecha-tools.com https://www.google-analytics.com https://vercel.live wss://vercel.live",
169+
"frame-src 'self' https://www.youtube.com https://player.vimeo.com",
170+
"media-src 'self' https:",
171+
"object-src 'none'",
172+
"base-uri 'self'",
173+
"form-action 'self'",
174+
"frame-ancestors 'none'",
175+
"upgrade-insecure-requests",
176+
].join("; "),
177+
},
178+
],
179+
},
180+
// No cache for auth-related pages
181+
{
182+
source: "/(login|logout|profile|admin|dashboard)/:path*",
183+
headers: [
184+
// Security headers
185+
{
186+
key: "X-Frame-Options",
187+
value: "DENY",
188+
},
189+
{
190+
key: "X-Content-Type-Options",
191+
value: "nosniff",
192+
},
193+
{
194+
key: "X-XSS-Protection",
195+
value: "1; mode=block",
196+
},
197+
{
198+
key: "Referrer-Policy",
199+
value: "strict-origin-when-cross-origin",
200+
},
201+
{
202+
key: "Permissions-Policy",
203+
value: "camera=(), microphone=(), geolocation=(), payment=(), usb=(), interest-cohort=()",
204+
},
205+
{
206+
key: "Strict-Transport-Security",
207+
value: "max-age=31536000; includeSubDomains; preload",
208+
},
209+
// Disable caching for auth pages
210+
{
211+
key: "Cache-Control",
212+
value: "no-store, no-cache, must-revalidate, private",
213+
},
214+
],
215+
},
216+
// Cache for other pages
217+
{
218+
source: "/((?!api|_next/static|_next/image|favicon.ico|login|logout|profile|admin|dashboard).*)",
219+
headers: [
220+
// Security headers
221+
{
222+
key: "X-Frame-Options",
223+
value: "DENY",
224+
},
225+
{
226+
key: "X-Content-Type-Options",
227+
value: "nosniff",
228+
},
229+
{
230+
key: "X-XSS-Protection",
231+
value: "1; mode=block",
232+
},
233+
{
234+
key: "Referrer-Policy",
235+
value: "strict-origin-when-cross-origin",
236+
},
237+
{
238+
key: "Permissions-Policy",
239+
value: "camera=(), microphone=(), geolocation=(), payment=(), usb=(), interest-cohort=()",
240+
},
241+
{
242+
key: "Strict-Transport-Security",
243+
value: "max-age=31536000; includeSubDomains; preload",
244+
},
245+
// Performance and caching headers for non-auth pages
246+
{
247+
key: "Cache-Control",
248+
value: "public, max-age=3600, stale-while-revalidate=86400",
152249
},
153250
// SEO and crawling headers
154251
{

nextjs/public/favicon.ico

-3.04 KB
Binary file not shown.

nextjs/public/icon.png

-49.3 KB
Binary file not shown.

nextjs/public/img/icon_logo.png

-3.04 KB
Binary file not shown.

nextjs/src/app/api/auth/[...auth0]/route.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ const afterCallback = async (req: any, session: any, config: any) => {
3434
};
3535

3636
}
37-
} else {
38-
console.log("⚠️ No access token found in session, using basic user data");
3937
}
4038

4139

@@ -70,12 +68,8 @@ const afterCallback = async (req: any, session: any, config: any) => {
7068
accessToken: session.accessToken
7169
};
7270

73-
console.log("✅ User session enhanced with DB data:", {
74-
id: user.id,
75-
email: user.email,
76-
role: user.role,
77-
isAdmin: user.isAdmin
78-
});
71+
72+
7973

8074
} catch (error) {
8175
console.error("❌ Auth callback failed:", error);
@@ -95,7 +89,7 @@ const handler = handleAuth({
9589
}
9690
}),
9791
logout: handleLogout({
98-
returnTo: process.env.AUTH0_BASE_URL
92+
returnTo: `${process.env.AUTH0_BASE_URL}/`
9993
}),
10094
callback: handleCallback({
10195
afterCallback: afterCallback,

nextjs/src/app/api/auth/me/route.ts

Lines changed: 0 additions & 48 deletions
This file was deleted.

nextjs/src/app/api/auth/test-session/route.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
import { NextResponse } from "next/server";
22
import { getSession } from "@auth0/nextjs-auth0";
3+
import { NextRequest } from "next/server";
34

4-
export async function GET() {
5+
export async function GET(request: NextRequest) {
56
try {
6-
const session = await getSession();
7+
const session = await getSession(request);
78

8-
return NextResponse.json({
9+
const response = NextResponse.json({
910
hasSession: !!session,
1011
hasUser: !!session?.user,
1112
userSub: session?.user?.sub,
1213
sessionKeys: session ? Object.keys(session) : [],
1314
userKeys: session?.user ? Object.keys(session.user) : [],
1415
timestamp: new Date().toISOString()
1516
});
17+
18+
// Disable caching for auth endpoints
19+
response.headers.set('Cache-Control', 'no-store, no-cache, must-revalidate, private');
20+
response.headers.set('Pragma', 'no-cache');
21+
response.headers.set('Expires', '0');
22+
23+
return response;
1624
} catch (error: any) {
1725
return NextResponse.json({
1826
error: "Failed to get session",
Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,47 @@
1-
import { NextRequest, NextResponse } from "next/server";
2-
import { verifyToken, createErrorResponse } from "@/lib/auth";
1+
import { NextResponse } from "next/server";
2+
import { getSession } from "@auth0/nextjs-auth0";
3+
import { NextRequest } from "next/server";
34

45
export async function GET(request: NextRequest) {
56
try {
6-
const authResult = await verifyToken(request);
7+
const session = await getSession(request);
8+
9+
if (!session || !session.user) {
10+
return NextResponse.json(
11+
{ error: "No authenticated user found" },
12+
{ status: 401 }
13+
);
14+
}
715

8-
return NextResponse.json({
9-
id: authResult.sub,
10-
email: authResult["https://pecha-tool/email"],
11-
picture: authResult["https://pecha-tool/picture"],
16+
// Return the user data from the session
17+
const user = session.user;
18+
19+
const response = NextResponse.json({
20+
id: user.sub,
21+
email: user.customEmail || user.email,
22+
name: user.name,
23+
picture: user.customPicture || user.picture,
24+
role: user.role || 'USER',
25+
isAdmin: user.isAdmin || false,
26+
// Include additional fields that might be useful
27+
dbUser: user.dbUser,
28+
timestamp: new Date().toISOString()
1229
});
13-
} catch (error) {
14-
return createErrorResponse("Unauthorized", 401);
30+
31+
// Disable caching for auth endpoints
32+
response.headers.set('Cache-Control', 'no-store, no-cache, must-revalidate, private');
33+
response.headers.set('Pragma', 'no-cache');
34+
response.headers.set('Expires', '0');
35+
36+
return response;
37+
} catch (error: any) {
38+
console.error("Error fetching user from session:", error);
39+
return NextResponse.json(
40+
{
41+
error: "Failed to fetch user data",
42+
message: error.message
43+
},
44+
{ status: 500 }
45+
);
1546
}
16-
}
47+
}

nextjs/src/app/layout.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import {
99
organizationData,
1010
} from "@/components/ServerStructuredData";
1111

12+
// Disable caching to ensure auth state updates properly
13+
export const dynamic = 'force-dynamic';
14+
1215
const geistSans = Geist({
1316
variable: "--font-geist-sans",
1417
subsets: ["latin"],

nextjs/src/app/page.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ import { homeMetadata } from "@/lib/metadata";
1010

1111
export const metadata = homeMetadata;
1212

13+
// Disable caching for this page to ensure auth state updates properly
14+
export const dynamic = 'force-dynamic';
15+
export const revalidate = 0;
16+
1317
export default function Home() {
1418
return (
1519
<>

0 commit comments

Comments
 (0)