Reputation: 963
I'm developing a Next.js application using NextAuth.js for authentication, and I'm facing a persistent issue:
After logging out, Chrome still shows protected content for a fraction of a second when navigating between pages.
This doesn't happen on Brave, only on Chrome.
Technical Setup
getToken()
and middleware)next-auth.session-token
Problem Description After logging out, when I navigate through pages, Chrome momentarily flashes protected content.
/login
.Steps Taken So Far Cache-Control headers in the middleware:
response.headers.set('Cache-Control', 'no-cache, no-store, must-revalidate, proxy-revalidate, private, max-age=0');
response.headers.set('Pragma', 'no-cache');
response.headers.set('Expires', '0');
response.headers.set('Surrogate-Control', 'no-store');
response.headers.set('Vary', 'Authorization, Cookie');
Forced a hard reload after logout: window.location.href = '/login?cacheBust=' + Date.now();
⚠️ Disabled Next.js prefetching:
Go to My OrdersBrowser & cache attempts:
Disabled Chrome bfcache
from chrome://flags/#back-forward-cache
.
Disabled cache via Chrome DevTools → Network → Disable Cache.
Cleared Service Worker caches with the following code:
if ('caches' in window) { caches.keys().then((names) => { for (let name of names) caches.delete(name); }); }
Despite all these attempts, the issue persists.
Current Middleware Configuration
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { getToken } from 'next-auth/jwt';
import Logger from '@/utils/logger';
export async function middleware(req: NextRequest) {
const { pathname } = req.nextUrl;
// Exclude /api/auth to avoid infinite loops
if (pathname.startsWith('/api/auth')) return NextResponse.next();
// Get the token
let token = await getToken({ req, secret: process.env.NEXTAUTH_SECRET });
// Redirect if token is missing
if (!token) {
Logger.warn('🔒 Missing token. Redirecting to login.');
return NextResponse.redirect(new URL('/login', req.url));
}
// Advanced cache control headers
const response = NextResponse.next();
response.headers.set('Cache-Control', 'no-cache, no-store, must-revalidate, proxy-revalidate, private, max-age=0');
response.headers.set('Pragma', 'no-cache');
response.headers.set('Expires', '0');
response.headers.set('Surrogate-Control', 'no-store');
response.headers.set('Vary', 'Authorization, Cookie');
return response;
}
// Apply to protected pages
export const config = {
matcher: [
'/my-orders/:path*',
'/dashboard/:path*',
'/api/:path*',
],
};
Logout Implementation
import { signOut } from 'next-auth/react';
const logout = async () => {
try {
await signOut({ redirect: false });
// Manually remove cookies
document.cookie = 'next-auth.session-token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC;';
document.cookie = 'next-auth.csrf-token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC;';
document.cookie = 'next-auth.callback-url=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC;';
// Clear service worker caches
if ('caches' in window) {
caches.keys().then((names) => {
for (let name of names) caches.delete(name);
});
}
// Force reload with cache-busting
window.location.href = '/login?cacheBust=' + Date.now();
} catch (error) {
console.error('❌ Logout error:', error);
}
};
Upvotes: 0
Views: 25