nextjs-auth0 icon indicating copy to clipboard operation
nextjs-auth0 copied to clipboard

withMiddlewareAuthRequired doesn't check if access token has expired

Open jln13x opened this issue 2 years ago • 4 comments

Checklist

  • [X] The issue can be reproduced in the nextjs-auth0 sample app (or N/A).
  • [X] I have looked into the Readme, Examples, and FAQ and have not found a suitable solution or answer.
  • [X] I have looked into the API documentation and have not found a suitable solution or answer.
  • [X] I have searched the issues and have not found a suitable solution or answer.
  • [X] I have searched the Auth0 Community forums and have not found a suitable solution or answer.
  • [X] I agree to the terms within the Auth0 Code of Conduct.

Description

The withMiddlewareAuthRequired doesn't seem to check if the access token is actually still valid

Reproduction

  • Add Middleware
  • Wait for Token to expire
  • Still have access

Additional context

No response

nextjs-auth0 version

3.5.0

Next.js version

14.1.3

Node.js version

v20.11.1

jln13x avatar Apr 05 '24 20:04 jln13x

Had to add custom code to check for it. Isn't there a better way to do that?

import { logger } from "@/server/logger";
import { routes } from "@/shared/routes";
import { safeTryAsync } from "@/shared/safe-try";
import { getAccessToken, withMiddlewareAuthRequired } from "@auth0/nextjs-auth0/edge";
import type { NextMiddleware } from "next/server";
import { NextResponse } from "next/server";
import { pathToRegexp } from "path-to-regexp";

const publicRoutes: string[] = ["/api/auth/(.*)"];

const middleware: NextMiddleware = async (req, event) => {
  const publicRoutesAsRegex = publicRoutes.map((route) => pathToRegexp(route));

  const pathname = req.nextUrl.pathname;
  const isPublicRoute = publicRoutesAsRegex.some((route) => route.test(pathname));

  const tag = isPublicRoute ? "🌍" : "🔓";
  console.log(`[${tag}] Middleware hit for ${pathname}`);

  if (isPublicRoute) {
    return NextResponse.next();
  }

  // Only seems to check if a session exists, not if it's valid - But atleast it extends the Cookie expiration
  return withMiddlewareAuthRequired({
    middleware: async (req) => {
      const res = NextResponse.next();
      const [, error] = await safeTryAsync(() => getAccessToken(req, res));

      if (error) {
        logger.error("Error getting access token", error);
        return NextResponse.redirect(new URL(routes.logout(), req.nextUrl));
      }

      return res;
    },
  })(req, event);
};

export default middleware;

export const config = {
  matcher: ["/((?!.+\\.[\\w]+$|_next).*)"],
};

jln13x avatar Apr 06 '24 12:04 jln13x

Out of curiosity, do you also get the following error message:

nextjs-auth0 is attempting to set cookies from a server component,see https://github.com/auth0/nextjs-auth0#using-this-sdk-with-react-server-components

bashaus avatar Apr 16 '24 15:04 bashaus

Out of curiosity, do you also get the following error message:

nextjs-auth0 is attempting to set cookies from a server component,see https://github.com/auth0/nextjs-auth0#using-this-sdk-with-react-server-components

ye but shouldnt be related

jln13x avatar Apr 17 '24 07:04 jln13x

@jln13x – I implemented the same logic as your code, and it worked until I received the AccessTokenErrorCode ERR_EXPIRED_ACCESS_TOKEN. The problem was that the redirect was stuck in an infinite loop.

I solved it by updating the session to expire. This may not be the right way to do it (I know the documentation recommend against it), but I redirect to the logout URL afterwards to clean up the session:

import {
  AccessTokenError,
  getAccessToken,
  updateSession,
  withMiddlewareAuthRequired,
} from "@auth0/nextjs-auth0/edge";
import { NextResponse } from "next/server";

export default withMiddlewareAuthRequired({
  middleware: async function middleware(req) {
    try {
      await getAccessToken();
      return NextResponse.next();
    } catch (err) {
      if (err instanceof AccessTokenError) {
        const res = NextResponse.redirect(
          "https://www.example.com/api/auth/logout",
        );

        return updateSession(req, res, {
          user: [],
          accessToken: undefined,
          idToken: undefined,
          refreshToken: undefined,
          accessTokenExpiresAt: 0,
        });
      }

      /* Fallback: if you don't know how to handle the error */
      throw err;
    }
  },
});

bashaus avatar Apr 25 '24 15:04 bashaus

@bashaus

Is a redirect to the login page alone not sufficient? It looks like the /api/auth/logout clears the session.

ddegroot1985 avatar Nov 25 '24 11:11 ddegroot1985

Closing this since this issue is not relevant to the latest version of our SDK, V4. Please open a seperate issue if it is present in V4.

tusharpandey13 avatar Feb 14 '25 12:02 tusharpandey13