♻️ Switch to next-auth for handling authentication (#899)

This commit is contained in:
Luke Vella 2023-10-19 09:14:53 +01:00 committed by GitHub
parent 5f9e428432
commit 6fa66da681
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
65 changed files with 1514 additions and 1586 deletions

View file

@ -1,76 +1,70 @@
import { getSession } from "@rallly/backend/next/edge";
import languages from "@rallly/languages";
import languageParser from "accept-language-parser";
import { NextRequest, NextResponse } from "next/server";
import { NextResponse } from "next/server";
import withAuth from "next-auth/middleware";
const supportedLocales = Object.keys(languages);
// these paths are always public
const publicPaths = ["/login", "/register", "/invite", "/auth"];
// these paths always require authentication
const protectedPaths = ["/settings/profile"];
export default withAuth(
function middleware(req) {
const { headers, nextUrl } = req;
const newUrl = nextUrl.clone();
const checkLoginRequirements = async (req: NextRequest, res: NextResponse) => {
const session = await getSession(req, res);
const isGuest = session.user?.isGuest !== false;
// if the user is already logged in, don't let them access the login page
if (
/^\/(login|register)/.test(newUrl.pathname) &&
req.nextauth.token?.email
) {
newUrl.pathname = "/";
return NextResponse.redirect(newUrl);
}
if (!isGuest) {
// already logged in
return false;
}
// Check if locale is specified in cookie
const preferredLocale = req.nextauth.token?.locale;
if (preferredLocale && supportedLocales.includes(preferredLocale)) {
newUrl.pathname = `/${preferredLocale}${newUrl.pathname}`;
} else {
// Check if locale is specified in header
const acceptLanguageHeader = headers.get("accept-language");
// TODO (Luke Vella) [2023-09-11]: We should handle this on the client-side
if (process.env.NEXT_PUBLIC_SELF_HOSTED === "true") {
// when self-hosting, only public paths don't require login
return !publicPaths.some((publicPath) =>
req.nextUrl.pathname.startsWith(publicPath),
);
} else {
// when using the hosted version, only protected paths require login
return protectedPaths.some((protectedPath) =>
req.nextUrl.pathname.includes(protectedPath),
);
}
};
if (acceptLanguageHeader) {
const locale = languageParser.pick(
supportedLocales,
acceptLanguageHeader,
);
export async function middleware(req: NextRequest) {
const { headers, cookies, nextUrl } = req;
const newUrl = nextUrl.clone();
const res = NextResponse.next();
const isLoginRequired = await checkLoginRequirements(req, res);
if (isLoginRequired) {
newUrl.pathname = "/login";
newUrl.searchParams.set("redirect", req.nextUrl.pathname);
return NextResponse.redirect(newUrl);
}
// Check if locale is specified in cookie
const localeCookie = cookies.get("NEXT_LOCALE");
const preferredLocale = localeCookie && localeCookie.value;
if (preferredLocale && supportedLocales.includes(preferredLocale)) {
newUrl.pathname = `/${preferredLocale}${newUrl.pathname}`;
return NextResponse.rewrite(newUrl);
} else {
// Check if locale is specified in header
const acceptLanguageHeader = headers.get("accept-language");
if (acceptLanguageHeader) {
const locale = languageParser.pick(
supportedLocales,
acceptLanguageHeader,
);
if (locale) {
newUrl.pathname = `/${locale}${newUrl.pathname}`;
return NextResponse.rewrite(newUrl);
if (locale) {
newUrl.pathname = `/${locale}${newUrl.pathname}`;
}
}
}
}
return res;
}
const res = NextResponse.rewrite(newUrl);
/**
* We moved from a bespoke session implementation to next-auth.
* This middleware looks for the old session cookie and moves it to
* a temporary cookie accessible to the client which will exchange it
* for a new session token with the legacy-token provider.
*/
const legacyToken = req.cookies.get("rallly-session");
if (legacyToken) {
res.cookies.set({
name: "legacy-token",
value: legacyToken.value,
});
res.cookies.delete("rallly-session");
}
return res;
},
{
secret: process.env.SECRET_PASSWORD,
callbacks: {
authorized: () => true, // needs to be true to allow access to all pages
},
},
);
export const config = {
matcher: ["/((?!api|_next/static|_next/image|static|.*\\.).*)"],