Issue: Stack-auth and Localization Redirection Conflict
Hey everyone 👋
I’m using stack-auth successfully in my non-localized app, and the localized version works fine without stack-auth. However, after merging both, I’m encountering an issue: after signing in, I’m redirected back to afterSignInUrl I’ve defined.
Is there any documentation or guidance on handling this scenario? I checked the middleware examples, but they didn’t seem to resolve the issue.
I'm looking to be redirected to the specified afterSignIn but localised.
Thanks!
So, I've fixed my use-case with some workarounds and route hacking, but I'm still looking for a better approach, if possible.
Here's how I did it:
import { i18n } from "./i18n.config";
import { match as matchLocale } from "@formatjs/intl-localematcher";
import Negotiator from "negotiator";
import { NextResponse } from "next/server";
function getLocale(request: NextRequest): string | undefined {
// Negotiator expects plain object so we need to transform headers
const negotiatorHeaders: Record<string, string> = {};
request.headers.forEach((value, key) => (negotiatorHeaders[key] = value));
// @ts-ignore locales are readonly
const locales: string[] = i18n.locales;
// Use negotiator and intl-localematcher to get best locale
let languages = new Negotiator({ headers: negotiatorHeaders }).languages(
locales
);
const locale = matchLocale(languages, locales, i18n.defaultLocale);
return locale;
}
export async function middleware(request: NextRequest) {
const pathname = request.nextUrl.pathname;
// List of routes that should bypass locale redirection
const nonLocalizedPaths = [
"/handler/signin",
"/handler/sign-in",
"/handler/signup",
"/handler/sign-up",
"/handler/oauth-callback",
"/handler/account-settings",
];
// Check if the pathname matches any non-localized paths
if (nonLocalizedPaths.includes(pathname)) {
return NextResponse.next();
}
// Iterate over all locales, check and strip the locale prefix
const localeMatch = i18n.locales.find((locale) =>
pathname.startsWith(`/${locale}/`)
);
if (localeMatch) {
const strippedPath = pathname.replace(`/${localeMatch}`, "");
// Handle specific paths after stripping the locale
if (
strippedPath === "/handler/sign-in" ||
strippedPath === "/handler/sign-up" ||
strippedPath === "/handler/oauth-callback"
) {
request.nextUrl.pathname = strippedPath.replace("/sign-in", "/signin"); // Normalize path
return NextResponse.next();
}
}
// Ignore specific files (manifest, favicon, PNGs)
if (
["/manifest.json", "/favicon.ico"].includes(pathname) ||
/\/.*\.png$/.test(pathname)
) {
return;
}
// If pathname is missing a locale, redirect
const pathnameIsMissingLocale = i18n.locales.every(
(locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`
);
if (pathnameIsMissingLocale) {
const locale = getLocale(request);
return NextResponse.redirect(
new URL(
`/${locale}${pathname.startsWith("/") ? "" : "/"}${pathname}`,
request.url
)
);
}
return NextResponse.next();
}
export const config = {
// Matcher ignoring `/_next/` and `/api/`
matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
};
I don't have any idea on how to solve your issue, but just FYI: you can try https://github.com/amannn/next-intl, it has first class support for next.js and it is being used in big projects like https://nodejs.org. I'm also using it and the afterSignInUrl works flawlessly.
One solution for this is that we can make all the URLs like afterSignIn an optional function so you can decide dynamically where to redirect them. Does that maybe solve your problem?
I don't have any idea on how to solve your issue, but just FYI: you can try https://github.com/amannn/next-intl, it has first class support for next.js and it is being used in big projects like https://nodejs.org. I'm also using it and the afterSignInUrl works flawlessly.
Thanks for the help. I was also using it before, but decided to move on without a library for that purpose. If this ends up persisting, I might go back to next-intl and check if it solves the problem.
One solution for this is that we can make all the URLs like
afterSignInan optional function so you can decide dynamically where to redirect them. Does that maybe solve your problem?
Hey there. If there is no way to predict a localised url yet, I guess it would help indeed.
It would also be cool do have the same support for the sign-in and sign-up urls so we don't have to run this hardcoded routing handling in middleware.ts.
What do you think?
One solution for this is that we can make all the URLs like
afterSignInan optional function so you can decide dynamically where to redirect them. Does that maybe solve your problem?Hey there. If there is no way to predict a localised url yet, I guess it would help indeed.
It would also be cool do have the same support for the sign-in and sign-up urls so we don't have to run this hardcoded routing handling in middleware.ts.
What do you think?
That is the idea, I think we are going to rework the redirect process to make it more generalized
Closing as duplicate of the i18n overhaul meta issue https://github.com/stack-auth/stack-auth/issues/1047 .
The current localization system is being completely replaced, which will resolve the vast majority of translation bugs and enable proper support for new languages.
Once the rewrite is complete, any remaining problems will be re-opened or filed as fresh issues.
→ See https://github.com/stack-auth/stack-auth/issues/1047 for status and progress.
Thank you for the report! 🌍