Skip to content

Middleware example does not always handle the response object #7888

Open
@OrmEmbaar

Description

@OrmEmbaar

Describe the content issue:
I am highlighting this as a potential issue, although I am not 100% sure whether it's a bug or not.

This is the example given by the docs to handle middleware authentication in NextJS:

export async function middleware(request: NextRequest) {
  const response = NextResponse.next();

  const authenticated = await runWithAmplifyServerContext({
    nextServerContext: { request, response },
    operation: async (contextSpec) => {
      try {
        const session = await fetchAuthSession(contextSpec);
        return (
          session.tokens?.accessToken !== undefined &&
          session.tokens?.idToken !== undefined
        );
      } catch (error) {
        console.log(error);
        return false;
      }
    }
  });

  if (authenticated) {
    return response; // Response object is returned here
  }

  return NextResponse.redirect(new URL('/sign-in', request.url)); // Response object is not used here.
}

As you can see, the example creates a response object which is used by runWithAmplifyServerContext to set headers on the response. However, that response object is only returned where the user is authenticated. Shouldn't that response object be used to initialise NextResponse.redirect too? What if the refresh token has expired or revoked? There might be set-cookie headers that need to be passed to the browser.

Unless I misunderstand something, is the following not the better option?

export async function middleware(request: NextRequest) {
  const response = NextResponse.next();

  const authenticated = await runWithAmplifyServerContext({
    nextServerContext: { request, response },
    operation: async (contextSpec) => {
      try {
        const session = await fetchAuthSession(contextSpec);
        return (
          session.tokens?.accessToken !== undefined &&
          session.tokens?.idToken !== undefined
        );
      } catch (error) {
        console.log(error);
        return false;
      }
    }
  });

  if (authenticated) {
    return response;
  }

  // Use the response object to initialise the redirect
  return NextResponse.redirect(new URL('/sign-in', request.url), response); 
}

Again, unless I misunderstand something, this is even more important when you need to redirect authenticated users, because there is a high likelihood that the response contains set-cookie headers.

export async function middleware(request: NextRequest) {
  const response = NextResponse.next();

  const authenticated = await runWithAmplifyServerContext({
    nextServerContext: { request, response },
    operation: async (contextSpec) => {
      try {
        const session = await fetchAuthSession(contextSpec);
        return (
          session.tokens?.accessToken !== undefined &&
          session.tokens?.idToken !== undefined
        );
      } catch (error) {
        console.log(error);
        return false;
      }
    }
  });

  if (!authenticated) {
    return response;
  }

  return NextResponse.redirect(new URL('/dashboard', request.url), response);
}

Is this correct? Should we be passing the response object to NextResponse.redirect and NextResponse.rewrite?

URL page where content issue is: https://docs.amplify.aws/gen1/javascript/build-a-backend/server-side-rendering/nextjs/#manage-auth-session-with-the-nextjs-middleware

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions