The router.push function is not working in the login submit handler

I’m using the Next.js App Router and have implemented middleware to check for the presence of an access token. If a user tries to access any page other than the root (/) or login-related pages without a token, I’m adding the returnURL to the search params so they can be redirected back to that page after logging in. However, this approach hasn’t been working as expected. For handling the login process, I’m using react-hook-form along with tanstack-query’s useMutation.

const returnURL = useSearchParams().get('returnURL') || '/';

//submit handler
const onSubmit: SubmitHandler<FieldValues> = () => {
  postSigninMutate(
    { username: payload.username, password: payload.password },
    {
      onSuccess: async (res) => {
        const { response } = res;
        const authorizationToken = response.headers.get('authorization-token');
        const expiresAt = response.headers.get('authorization-token-expired-at');
        const refreshToken = response.headers.get('refresh-token');

        if (authorizationToken && expiresAt && refreshToken) {
          Cookies.set('authorization-token', authorizationToken, { secure: true });
          Cookies.set('expires-at', expiresAt);
          Cookies.set('refresh-token', refreshToken, { secure: true });
        }

        router.push(returnURL);
      },
      onError: (err) => alert(err)
    }
  );
};

<form onSubmit={handleSubmit(onSubmit)} className="flex-col-start m-0 w-80 gap-6 pt-10">
...

// middleware.ts
import { NextRequest, NextResponse } from 'next/server';

export function middleware(request: NextRequest) {
  const url = request.nextUrl.pathname;
  const accessToken = request.cookies.get('authorization-token');

  console.log(accessToken ? 'yes' : 'no');
  console.log(url);

  if (url === '/') {
    const response = NextResponse.next();
    response.headers.set('X-Skip-Icons', 'true');
    return response;
  }

  if (
    accessToken &&
    (url === '/signup' ||
      url === '/login' ||
      url === '/kakaoLogin' ||
      url === '/find-password-email' ||
      url === '/find-password-question' ||
      url === '/find-password-newpassword')
  ) {
    if (request.nextUrl.searchParams.has('returnURL')) {
      return NextResponse.redirect(new URL(request.nextUrl.searchParams.get('returnURL') || '/', request.url));
    }
    console.log('here');
    return NextResponse.redirect(new URL('/', request.url));
  }

  if (
    !accessToken &&
    url !== '/signup' &&
    url !== '/login' &&
    url !== '/kakaoLogin' &&
    url !== '/find-password-email' &&
    url !== '/find-password-question' &&
    url !== '/find-password-newpassword'
  ) {
    const redirectURL = new URL('/login', request.url);
    const returnURL = request.nextUrl.pathname + request.nextUrl.search;
    redirectURL.searchParams.set('returnURL', returnURL);

    const response = NextResponse.redirect(redirectURL);
    return response;
  }

  return NextResponse.next();
}

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico|icons/favicon.ico|icon).*)']
};

I suspected that the issue was due to page caching and a mismatch between cookie updates on the client and server. After calling router.refresh(), the middleware triggered and the page updated, but the URL in the address bar didn’t change. I then added a setTimeout after router.refresh() to delay the router.push(returnURL), and while this solution worked, it made me question whether this is the right approach.

However, when I press the back button, I can still access the login page, which shouldn’t happen after a successful login.

router.refresh();
setTimeout(() => {
  router.push(returnURL);
}, 1000);