← All posts
session managementvibe codingsecuritycookiesJWT

Fix Insecure Session Management in Vibe-Coded Apps

O

OverMCP Team

Quick answer

Insecure session management in vibe-coded apps often means missing or weak session expiration, storing tokens in vulnerable places (like localStorage), or failing to rotate session IDs after login. To fix it: use HTTP-only, secure, SameSite cookies for session tokens, set short expiration times (15-60 minutes), and regenerate session IDs on authentication state changes. Many AI-generated apps skip these steps, leaving user accounts exposed to session hijacking.

What to check first

Before diving into fixes, audit your app for these common session management gaps:

  • Where is the session token stored? Check for localStorage, sessionStorage, or document.cookie with HttpOnly=false. If you find tokens in localStorage, that's a red flag.
  • Is the session token set with Secure and SameSite attributes? Look at your Set-Cookie header in the browser's network tab. It should have Secure; HttpOnly; SameSite=Lax (or Strict).
  • What's the session expiry? Find the token's exp claim (if JWT) or check server-side session timeout. Anything over 24 hours is too long for most apps.
  • Does session ID rotate on login/logout? Test by logging in, then logging out and logging in again. The token should be different each time.
  • Is there a logout endpoint that invalidates the session? Clicking logout should clear the cookie and invalidate the server-side session.
  • Are session tokens transmitted over HTTPS only? Check if your app redirects HTTP to HTTPS. If not, tokens can be intercepted.
  • If you're unsure, use a security headers checker to verify cookie attributes.

    Step-by-step fix

    Here's how to implement secure session management in a typical vibe-coded Next.js app using the App Router.

    1. Use HTTP-only cookies instead of localStorage

    AI-generated code often stores JWTs in localStorage for simplicity. This is vulnerable to XSS attacks. Move tokens to HTTP-only cookies.

    Before (bad):

    // AuthContext.js (vibe-coded)
    localStorage.setItem('token', token);

    After (good):

    // API route: /api/login
    import { cookies } from 'next/headers';
    
    export async function POST(request) {
      const { username, password } = await request.json();
      // authenticate user...
      const token = generateJWT({ userId: user.id });
    
      cookies().set('session_token', token, {
        httpOnly: true,
        secure: process.env.NODE_ENV === 'production',
        sameSite: 'lax',
        path: '/',
        maxAge: 60 * 60 * 1, // 1 hour
      });
    
      return Response.json({ success: true });
    }

    2. Set short expiration and rotate tokens

    Set maxAge to 15-60 minutes for session tokens. Use a refresh token with longer expiry if needed, stored securely.

    // Token generation (using jose library)
    import { SignJWT } from 'jose';
    
    const secret = new TextEncoder().encode(process.env.JWT_SECRET);
    const token = await new SignJWT({ userId: user.id })
      .setProtectedHeader({ alg: 'HS256' })
      .setExpirationTime('15m') // short-lived
      .setIssuedAt()
      .sign(secret);

    3. Regenerate session ID on login/logout

    Always issue a new token after authentication changes.

    // On logout
    cookies().set('session_token', '', { maxAge: 0 });
    // Also invalidate server-side session if using database sessions

    4. Add logout endpoint that clears cookie

    // /api/logout
    export async function POST() {
      cookies().set('session_token', '', { maxAge: 0 });
      return Response.json({ success: true });
    }

    5. Verify cookie attributes in production

    Use your browser's dev tools to check the Set-Cookie header. It should look like:

    Set-Cookie: session_token=abc123; Path=/; HttpOnly; Secure; SameSite=Lax

    For a full audit, run a free AI app security scanner to catch other vulnerabilities.

    Common mistakes

  • Storing tokens in localStorage: AI tools often default to localStorage because it's easy. But any XSS vulnerability can steal the token.
  • No session expiration: Many vibe-coded apps set tokens to never expire or use extremely long expirations (days/weeks). This increases the window for hijacking.
  • Missing cookie attributes: HttpOnly, Secure, and SameSite are often omitted. Without HttpOnly, client-side JavaScript can read the cookie. Without Secure, the cookie is sent over HTTP.
  • No token rotation: AI-generated auth flows often reuse the same token after logout. Attackers can reuse stolen tokens.
  • Hardcoded secrets: Vibe-coded apps may embed JWT secrets or API keys in the code. Use a secret leak scanner to find them.
  • Not invalidating sessions on logout: The server-side session remains valid if not explicitly cleared, allowing session fixation attacks.
  • FAQ

    What is session hijacking?

    Session hijacking is when an attacker steals a user's session token (e.g., via XSS, network sniffing, or leaked cookies) and uses it to impersonate the user. Secure session management prevents this by using HTTP-only cookies, short expirations, and HTTPS.

    How do I test if my session is secure?

    Open your browser's developer tools, go to the Application tab, and check Cookies. Look for your session cookie. It should have HttpOnly, Secure, and SameSite flags. Also, log out and log in again to see if the token changes. Use a security headers checker to verify cookie attributes.

    Can I use JWTs with HTTP-only cookies?

    Yes, JWTs work well with HTTP-only cookies. The server sets the JWT as a cookie value. The client sends it automatically with each request. This combines the statelessness of JWTs with the security of HTTP-only cookies. Ensure the cookie has a short maxAge and SameSite=Lax.

    Is your app secure?

    Free scan in 30 seconds. No signup needed.

    Scan My App Free