← All posts
vibe codinglogout functionalitysecurityNext.jsJWT

Fix Missing Logout Functionality in Vibe-Coded Apps

O

OverMCP Team

Quick answer

Missing logout functionality in vibe-coded apps is a security risk that leaves user sessions active indefinitely, potentially allowing unauthorized access. To fix it, add a server-side endpoint that invalidates the session token and clears client-side storage. For Next.js apps, implement a logout API route that revokes the JWT or session cookie.

What is the missing logout vulnerability?

When you vibe-code an app with tools like Cursor, Bolt.new, or v0, the AI often focuses on login flows but forgets to implement a proper logout. This means a user who signs in on a shared computer—or even their own device—can never truly end their session. The session token remains valid until it expires, which could be days or weeks later. This is a classic "broken authentication" issue from the OWASP Top 10.

What to check first

Before writing any code, verify if your app has a logout mechanism:

  • [ ] Does your app have a "Logout" or "Sign out" button visible after login?
  • [ ] Does clicking that button actually clear the session? (Open DevTools > Application > Cookies and check if the token is removed after clicking)
  • [ ] Can you access protected routes using the old token after "logging out"? (Try reusing a previously stored token via Postman or curl)
  • [ ] Is the session token stored in localStorage instead of an httpOnly cookie? (localStorage is more vulnerable to XSS)
  • [ ] Does the backend have a token blacklist or revocation mechanism?
  • If you answered "no" to any of these, your app likely has missing logout functionality.

    Step-by-step fix

    1. Create a logout API route (Next.js App Router)

    In your Next.js app, add a route handler at app/api/auth/logout/route.ts:

    import { NextResponse } from 'next/server';
    import { cookies } from 'next/headers';
    
    export async function POST() {
      // Clear the session cookie
      const cookieStore = cookies();
      cookieStore.set('session_token', '', {
        httpOnly: true,
        secure: process.env.NODE_ENV === 'production',
        sameSite: 'lax',
        maxAge: 0, // Expire immediately
        path: '/',
      });
    
      // Optional: Add token to a blacklist in your database
      // await blacklistToken(token);
    
      return NextResponse.json({ message: 'Logged out successfully' });
    }

    2. Add a logout button in your UI

    In your dashboard or profile component:

    'use client';
    import { useRouter } from 'next/navigation';
    
    export default function LogoutButton() {
      const router = useRouter();
    
      const handleLogout = async () => {
        await fetch('/api/auth/logout', { method: 'POST' });
        // Also clear client-side storage
        localStorage.removeItem('token');
        sessionStorage.clear();
        router.push('/login');
      };
    
      return <button onClick={handleLogout}>Logout</button>;
    }

    3. Verify the fix

    After implementing, test:

  • Click logout, then try to access a protected route (e.g., /dashboard). You should be redirected to login.
  • Check DevTools > Application > Cookies: the session cookie should be gone.
  • Try reusing the old token via curl: curl -X GET https://yourapp.com/api/protected -H "Cookie: session_token=oldtoken" — it should return 401.
  • 4. For JWT-based apps: blacklist tokens

    If you use JWTs, clearing the cookie isn't enough because the JWT remains valid until expiry. Implement a token blacklist (e.g., Redis or database):

    // In logout route
    const token = cookieStore.get('session_token')?.value;
    if (token) {
      await redis.set(`blacklist:${token}`, 'true', { EX: 3600 }); // TTL matches JWT expiry
    }

    Then in your middleware, check the blacklist before verifying the JWT.

    Common mistakes

  • Only clearing client-side storage: Vibe-coded apps often just remove the token from localStorage on the frontend. The backend still considers the token valid. An attacker who intercepted the token can still use it.
  • Not using httpOnly cookies: AI tools often store tokens in localStorage or sessionStorage for simplicity. This makes them accessible to JavaScript, increasing XSS risk. Always prefer httpOnly cookies for session tokens.
  • No token revocation: Without a blacklist or short expiry, even if you delete the cookie, the JWT remains valid. Set short expiry times (e.g., 15 minutes for access tokens) and use refresh tokens with rotation.
  • Forgetting to invalidate all sessions: Users may be logged in on multiple devices. Implement "log out from all devices" by invalidating all tokens for that user (e.g., incrementing a token version in the database).
  • Not testing the logout flow: Many vibe-coded apps skip testing edge cases like logging out after a long session or during an API call.
  • Why this matters for vibe-coded apps

    AI coding tools generate functional code quickly, but they often miss security best practices because they optimize for "it works" rather than "it's secure." Missing logout is a classic example: the AI implements login, session management, and protected routes, but forgets the logout button. This flaw can lead to account takeover if a user forgets to close their browser on a shared machine.

    To catch issues like this before they reach production, use a free AI app security scanner to scan your vibe-coded app for common vulnerabilities. You can also check your security headers and run a secret leak scanner to find exposed tokens. For Vercel-deployed apps, the Vercel security scanner can automate checks. Consider continuous security monitoring to catch regressions after each vibe-coded update.

    FAQ

    How do I know if my app has missing logout functionality?

    Check if there's a logout button or API endpoint. If not, your app likely has the issue. Also test if the session persists after closing the browser or after clicking a logout link.

    Is clearing localStorage enough for logout?

    No. Clearing localStorage only removes the token from the client-side. The backend still considers the token valid until it expires. Always invalidate the token on the server.

    How should I handle logout with JWTs?

    Use a combination of short-lived access tokens (e.g., 15 minutes) and refresh tokens. When logging out, delete the refresh token from the database and add the access token to a blacklist until it expires naturally.

    Is your app secure?

    Free scan in 30 seconds. No signup needed.

    Scan My App Free