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

v4: Session is expired, but after Server Action is called i dont get redirected #1934

Open
6 tasks done
BratislavZ opened this issue Feb 25, 2025 · 2 comments
Open
6 tasks done
Labels

Comments

@BratislavZ
Copy link

BratislavZ commented Feb 25, 2025

Checklist

Description

I wanted to see how my app behaves when the session is expired and i call a server action.
In prev version (v3.5) server action would be called and then await getAccessToken would throw an error after which I would just redirect to api/auth/login . But in the current v4 the error is thrown before an action has started. Which is ok, Im creating a POST request when i want to call a server action and Auth0 can see in the middleware that I dont have session.
The issue is that the middleware sees the session is null and calls:

return NextResponse.redirect(new URL("/auth/login", req.url), {
  status: 303,
});

I can see in the terminal that the new path is /auth/login but browser is still showing page from which I initiated Server Action. In the browser Network I can see 3 requests:

Image

My middleware looks like this:

import { NextRequest, NextResponse } from "next/server";
import createIntlMiddleware from "next-intl/middleware";
import { routing } from "./i18n/routing";
import { auth0 } from "./lib/auth0";

const intlMiddleware = createIntlMiddleware(routing);

const loginPages = ["/", "/en-US"] as const;

export default async function middleware(req: NextRequest) {
  const pathname = req.nextUrl.pathname;
  const isLoginPage = loginPages.some((page) => page === pathname);
  const isProtectedPage = !isLoginPage
  const authResponse = await auth0.middleware(req);

  console.log("👀 Path:", pathname);

  if (pathname.startsWith("/auth")) {
    return authResponse;
  }

  const session = await auth0.getSession(req);

  console.log("🔥 Session:", session);

  // User is not logged in and tries to access a page that requires authentication
  if (!session && isProtectedPage) {
    return NextResponse.redirect(new URL("/auth/login", req.url), {
      status: 303,
    });
  }

  // Apply intl middleware
  const intlResponse = intlMiddleware(req);

  // Add Auth0 headers to the response
  for (const [key, value] of authResponse.headers) {
    intlResponse.headers.set(key, value);
  }

  return intlResponse;
}

export const config = {
  matcher: [
    "/",

    "/(en-US|is|de)/:path*",

    "/auth/:path*", // Make sure Auth0 routes are included

    "/((?!_next/image|_next/static|images|api|favicon.ico|_vercel|.*\\..*).*)",
  ],
};

My logs in the terminal:

👀 Path: /en-US/user-management/1/departments 
🔥 Session: null 
👀 Path: /auth/login

Browser logs:

Image

Reproduction

  1. Set auth0 server client:
export const auth0 = new Auth0Client({
  authorizationParameters: {
    audience: process.env.AUTH0_AUDIENCE,
  },
  session: {
    absoluteDuration: 15, // short session so I can test how app behaves after session is expired
  },
});
  1. Set middleware I provided in the description
  2. Call a server Action after the session is expired

Additional context

next-intl

nextjs-auth0 version

v4.02

Next.js version

v15.1.7

Node.js version

v20.10.0

@BratislavZ BratislavZ changed the title Session is expired, but after Server Action is called i dont get redirected v4: Session is expired, but after Server Action is called i dont get redirected Feb 25, 2025
@tusharpandey13
Copy link
Contributor

Thank you for reporting this issue with server actions and expired sessions!

This looks like an interesting edge case with how Next.js Server Actions handle redirects from middleware. Based on the logs you've provided, the middleware is correctly identifying the expired session and attempting to redirect, but the redirect isn't being properly handled in the context of a server action.

We're investigating this issue to better understand how redirects should be handled in this scenario.

In the meantime, you could work around this by:

  1. Checking the session validity at the beginning of your server action and throwing a redirect error:
import { redirect } from 'next/navigation';
async function myServerAction() {
  const session = await auth0.getSession();
  if (!session) {
    redirect('/auth/login');
  }
  // Rest of your server action
}
  1. Or handling the expired session case in your client component after the server action fails

Could you share a simplified version of your server action code? This would help us reproduce and fix the issue more effectively.

@BratislavZdravkovic
Copy link

Hi @tusharpandey13 , ty for your comment.
I also tried with that approach of checking the session and then call a redirect, but i still dont get redirected.
When i click on submit button and call a server action i get tag that my page becomes static (which is not possible because im using next-intl and params) and I get this error:

Image Image Image

The simplified version of my server action:

export const serverAction = async (
  data: ActionInputType
): Promise<ActionReturnType> => {
  let responseData;
  try {
    const result = ValidationSchema.readonly().safeParse(data);
    if (!result.success) {
      throw new Error("Invalid data");
    }
    const { customerId } = result.data;
    const session = await auth0.getSession();
    if (!session) {
      throw new AccessTokenError("No session found", "Failed");
    }

    const response = await fetch(MY_URL,
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${session.tokenSet.accessToken}`,
        },
        body: JSON.stringify(result.data),
      }
    );

    responseData = await response.json();
  } catch (error) {
    if (error instanceof AccessTokenError) {
        redirect("/auth/login");
    } else
      return {
        error: DEFAULT_SERVER_ERROR,
      };
  }
  return { departmentId: responseData };
};

Keep in mind that I still used your code (just checking if I have session and then redirecting, but it doesnt work).

Im not sure if all of this happens because of:

export const auth0 = new Auth0Client({
  authorizationParameters: {
    audience: process.env.AUTH0_AUDIENCE,
    max_age: 1, // also confused why we cant write 0 like in v3.5 
  },
  session: {
    rolling: false,
    absoluteDuration: 15, // for short sessions, so I can check the behaviour
  },
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants