125 lines
3.5 KiB
TypeScript
125 lines
3.5 KiB
TypeScript
import {
|
|
TinaNodeBackend,
|
|
LocalBackendAuthProvider,
|
|
} from "@tinacms/datalayer";
|
|
import NextAuth from "next-auth";
|
|
import CredentialsProvider from "next-auth/providers/credentials";
|
|
import { getServerSession } from "next-auth/next";
|
|
|
|
import databaseClient from "../../../tina/__generated__/databaseClient";
|
|
|
|
const isLocal = process.env.TINA_PUBLIC_IS_LOCAL === "true";
|
|
|
|
const TINA_CREDENTIALS_PROVIDER_NAME = "TinaCredentials";
|
|
|
|
const authenticate = async (
|
|
dbClient: typeof databaseClient,
|
|
username: string,
|
|
password: string
|
|
) => {
|
|
try {
|
|
const result = await dbClient.authenticate({ username, password });
|
|
return result.data?.authenticate || null;
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
const authOptions = {
|
|
callbacks: {
|
|
jwt: async ({ token: jwt, account }: any) => {
|
|
if (account) {
|
|
try {
|
|
if (jwt?.sub) {
|
|
const result = await databaseClient.authorize({ sub: jwt.sub });
|
|
jwt.role = result.data?.authorize ? "user" : "guest";
|
|
jwt.passwordChangeRequired =
|
|
result.data?.authorize?._password?.passwordChangeRequired ||
|
|
false;
|
|
}
|
|
} catch {
|
|
// ignore auth errors
|
|
}
|
|
if (jwt.role === undefined) {
|
|
jwt.role = "guest";
|
|
}
|
|
}
|
|
return jwt;
|
|
},
|
|
session: async ({ session, token: jwt }: any) => {
|
|
session.user.role = jwt.role;
|
|
session.user.passwordChangeRequired = jwt.passwordChangeRequired;
|
|
session.user.sub = jwt.sub;
|
|
return session;
|
|
},
|
|
},
|
|
session: { strategy: "jwt" as const },
|
|
secret: process.env.NEXTAUTH_SECRET as string,
|
|
providers: [
|
|
CredentialsProvider({
|
|
name: TINA_CREDENTIALS_PROVIDER_NAME,
|
|
credentials: {
|
|
username: { label: "Username", type: "text" },
|
|
password: { label: "Password", type: "password" },
|
|
},
|
|
authorize: async (credentials: any) =>
|
|
authenticate(databaseClient, credentials.username, credentials.password),
|
|
}),
|
|
],
|
|
};
|
|
|
|
const handler = TinaNodeBackend({
|
|
authProvider: isLocal
|
|
? LocalBackendAuthProvider()
|
|
: {
|
|
initialize: async () => {},
|
|
isAuthorized: async (req: any, res: any) => {
|
|
const session = await getServerSession(req, res, authOptions);
|
|
if (!req.session) {
|
|
Object.defineProperty(req, "session", {
|
|
value: session,
|
|
writable: false,
|
|
});
|
|
}
|
|
if (!(session as any)?.user) {
|
|
return {
|
|
errorCode: 401,
|
|
errorMessage: "Unauthorized",
|
|
isAuthorized: false,
|
|
};
|
|
}
|
|
if ((session as any)?.user?.role !== "user") {
|
|
return {
|
|
errorCode: 403,
|
|
errorMessage: "Forbidden",
|
|
isAuthorized: false,
|
|
};
|
|
}
|
|
return { isAuthorized: true };
|
|
},
|
|
extraRoutes: {
|
|
auth: {
|
|
secure: false,
|
|
handler: async (req: any, res: any, opts: any) => {
|
|
const url = new URL(
|
|
req.url,
|
|
`http://${req.headers?.host || "localhost"}`
|
|
);
|
|
const authSubRoutes = url.pathname
|
|
?.replace(`${opts.basePath}auth/`, "")
|
|
?.split("/");
|
|
req.query.nextauth = authSubRoutes;
|
|
await NextAuth(authOptions)(req, res);
|
|
},
|
|
},
|
|
},
|
|
},
|
|
databaseClient,
|
|
});
|
|
|
|
export default (req: any, res: any) => {
|
|
return handler(req, res);
|
|
};
|
|
|
|
export { authOptions };
|