Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent Session Expiration When Using AWS Amplify with Next.js Middleware #14118

Open
3 tasks done
okashaaijaz opened this issue Jan 7, 2025 · 3 comments
Open
3 tasks done
Assignees
Labels
Auth Related to Auth components/category Next.js pending-maintainer-response Issue is pending a response from the Amplify team. question General question

Comments

@okashaaijaz
Copy link

Before opening, please confirm:

JavaScript Framework

Next.js

Amplify APIs

Authentication

Amplify Version

v6

Amplify Categories

auth

Backend

Amplify Gen 2

Environment information

  System:
    OS: Windows 11 10.0.22631
    CPU: (12) x64 13th Gen Intel(R) Core(TM) i5-1334U
    Memory: 2.31 GB / 15.65 GB
  Binaries:
    Node: 20.18.0 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.22 - ~\AppData\Roaming\npm\yarn.CMD
    npm: 10.9.0 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Edge: Chromium (129.0.2792.89)
    Internet Explorer: 11.0.22621.3527
  npmGlobalPackages:
    npm: 10.9.0
    vercel: 37.14.0
    yarn: 1.22.22

Describe the bug

We are experiencing random logout issues for users when using AWS Amplify with Next.js in a custom middleware setup. Some users remain logged in for 4–5 days, while others get logged out after only 1–2 days. Cookies are present in the browser, but the session becomes undefined in the middleware, leading to forced redirections. I have added logs in middleware and authenticateUser function which is logging undefined. Below is a simplified version of our current setup:

// middleware.ts
import { NextRequest, NextResponse } from "next/server";
import { authenticatedUser } from "./utils/amplify-server-utils";

export async function middleware(request: NextRequest) {
  const authRoutes = [
    '/login',
    '/signup',
    '/forget-password',
    '/reset-password',
  ];
  const privateRoutes = [
    '/dashboard/analytics',
    '/profile',
    '/dashboard/manager',
    '/dashboard/user',
    '/dashboard/pricing'
  ];
  const onlyManagerRoutes = [
    '/dashboard/user',
    '/dashboard/pricing'
  ];
  const onlyAdminRoutes = [
    '/dashboard/manager',
    '/dashboard/user',
  ];

  const { pathname } = request.nextUrl;
  const response = NextResponse.next();
  const user = await authenticatedUser({ request, response });
  console.log("user in middleware ===>>> ", user);

  if (pathname === '/') {
    return NextResponse.redirect(new URL('/dashboard/analytics', request.url));
  }

  if (authRoutes.includes(pathname) && user) {
    return NextResponse.redirect(new URL('/dashboard/analytics', request.url));
  }

  if (privateRoutes.includes(pathname) && !user) {
    return NextResponse.redirect(new URL('/login', request.url));
  }

  if (onlyAdminRoutes.includes(pathname) && user?.groups.includes('Admin')) {
    return NextResponse.next();
  }

  if (onlyManagerRoutes.includes(pathname) && user?.groups.includes('Manager')) {
    return NextResponse.next();
  }

  if (onlyManagerRoutes.includes(pathname) && !user?.groups.includes('Manager')) {
    return NextResponse.redirect(new URL('/dashboard/analytics', request.url));
  }

  if (onlyAdminRoutes.includes(pathname) && !user?.groups.includes('Admin')) {
    return NextResponse.redirect(new URL('/dashboard/analytics', request.url));
  }

  return NextResponse.next();
}

export const config = {
  matcher: [
    "/((?!api|_next/static|_next/public|_next/image|assets|favicon.ico|sw.js).*)",
  ],
};

// ./utils/amplify-server-utils.ts
import { createServerRunner } from "@aws-amplify/adapter-nextjs";
import { fetchAuthSession, getCurrentUser } from "aws-amplify/auth/server";
import { authConfig } from "./aws-auth-config";

export const { runWithAmplifyServerContext } = createServerRunner({
  config: {
    Auth: authConfig,
  },
});

export async function authenticatedUser(context: any) {
  return await runWithAmplifyServerContext({
    nextServerContext: context,
    operation: async (contextSpec) => {
      try {
        const session = await fetchAuthSession(contextSpec);
        console.log("session for middleware ==>> ", session);

        if (!session.tokens) {
          return;
        }

        const user = {
          ...((await getCurrentUser(contextSpec))),
          groups: [] as string[],
        };
        const groups: string[] = session?.tokens?.accessToken.payload["cognito:groups"] || [];
        user.groups = groups;

        return user;
      } catch (error) {
        console.log(error);
      }
    },
  });
}

Expected behavior

  1. All users should remain logged in until their token truly expires, or until they explicitly log out.
  2. The session should consistently recognize user credentials.

Reproduction steps

  1. Sign in to the application using AWS Amplify.
  2. Open the application periodically (over days) to observe how soon the session is lost.
  3. Observe the middleware logs and note the inconsistent undefined user session.

Code Snippet

// Put your code below this line.

Log output

// Put your logs below this line


aws-exports.js

No response

Manual configuration

No response

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

No response

@github-actions github-actions bot added pending-triage Issue is pending triage pending-maintainer-response Issue is pending a response from the Amplify team. labels Jan 7, 2025
@cwomack cwomack self-assigned this Jan 7, 2025
@cwomack cwomack added Auth Related to Auth components/category Next.js labels Jan 7, 2025
@cwomack
Copy link
Member

cwomack commented Jan 7, 2025

Hello, @okashaaijaz and thanks for opening this issue. Are you using any custom cookie storage potentially or just the out of the box version with Amplify? Can you confirm if the Amplify generated cookies are able to be seen when this happens or if they are expired? Finally, what is the TTL you have set for your tokens?

@github-actions github-actions bot removed the pending-maintainer-response Issue is pending a response from the Amplify team. label Jan 7, 2025
@cwomack cwomack added bug Something isn't working question General question pending-community-response Issue is pending a response from the author or community. and removed pending-triage Issue is pending triage bug Something isn't working labels Jan 7, 2025
@okashaaijaz
Copy link
Author

@cwomack I am not setting any custom cookie my self, everything is handled by amplify itself. I am fetching session in next js middleware using next.js adapter which is returning undefined in logs and my cookies are present in browser.

@github-actions github-actions bot added pending-maintainer-response Issue is pending a response from the Amplify team. and removed pending-community-response Issue is pending a response from the author or community. labels Jan 9, 2025
@okashaaijaz
Copy link
Author

@cwomack Another issue I encountered today was that my access token expired, and I was automatically logged out because I am validating the token on the backend side. It is throwing an error stating that the token has expired.

My question is: Will Amplify automatically refresh the access token, or do we need to implement some custom logic for this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Auth Related to Auth components/category Next.js pending-maintainer-response Issue is pending a response from the Amplify team. question General question
Projects
None yet
Development

No branches or pull requests

2 participants