import NextAuth, { NextAuthOptions } from "next-auth" import GoogleProvider from "next-auth/providers/google" import FacebookProvider from "next-auth/providers/facebook" import GithubProvider from "next-auth/providers/github" import TwitterProvider from "next-auth/providers/twitter" import Auth0Provider from "next-auth/providers/auth0" import AppleProvider from "next-auth/providers/apple" import EmailProvider from "next-auth/providers/email" import CredentialsProvider from "next-auth/providers/credentials" import { PrismaAdapter } from "@auth/prisma-adapter" import bcrypt from "bcrypt" const emailHelper = require('../../../src/helpers/email'); //microsoft import AzureADProvider from "next-auth/providers/azure-ad"; // https://next-auth.js.org/getting-started/client const common = require("../../../src/helpers/common"); import { isLoggedIn, setAuthTokens, clearAuthTokens, getAccessToken, getRefreshToken } from 'axios-jwt' import { create } from "domain" //console.log("appleID:", process.env.APPLE_APP_ID); // console.log(process.env.EMAIL_SERVER) // For more information on each option (and a full list of options) go to // https://next-auth.js.org/configuration/options export const authOptions: NextAuthOptions = { // https://next-auth.js.org/configuration/providers/oauth site: process.env.NEXT_PUBLIC_PUBLIC_URL, secret: process.env.NEXTAUTH_SECRET, // Ensure you have this set in your .env file //adapter: PrismaAdapter(prisma), providers: [ // register new URL at https://console.cloud.google.com/apis/credentials/oauthclient/926212607479-d3m8hm8f8esp3rf1639prskn445sa01v.apps.googleusercontent.com?project=grand-forge-108716 //Request details: redirect_uri=http://20.101.62.76:8005/api/auth/callback/google https://s.mwitnessingmwitnessing.com/ GoogleProvider({ clientId: process.env.GOOGLE_ID, clientSecret: process.env.GOOGLE_SECRET, authorization: { params: { prompt: "consent", access_type: "offline", response_type: "code" } } }), AppleProvider({ // clientId: process.env.APPLE_APP_ID, // clientSecret: process.env.APPLE_SECRET clientId: process.env.APPLE_APP_ID, clientSecret: { appleId: process.env.APPLE_APP_ID, teamId: process.env.APPLE_TEAM_ID, privateKey: process.env.APPLE_PK, keyId: process.env.APPLE_KEY_ID, } }), AzureADProvider({ clientId: process.env.AZURE_AD_CLIENT_ID, clientSecret: process.env.AZURE_AD_CLIENT_SECRET, tenantId: process.env.AZURE_AD_TENANT_ID, }), CredentialsProvider({ id: 'credentials', // The name to display on the sign in form (e.g. 'Sign in with...') name: 'Credentials', credentials: { username: { label: "Потребител", type: "text", placeholder: "Потребителско име" }, password: { label: "Парола", type: "password" } }, async authorize(credentials, req) { const users = [ { id: "1", name: "admin", email: "admin@example.com", password: "admin123", role: "ADMIN", static: true }, { id: "2", name: "krasi", email: "krasi@example.com", password: "krasi123", role: "ADMIN", static: true }, { id: "3", name: "popov", email: "popov@example.com", password: "popov123", role: "ADMIN", static: true } ]; const user = users.find(user => user.name === credentials.username && user.password === credentials.password ); if (user) { return user; } else { const prisma = common.getPrismaClient(); const user = await prisma.user.findUnique({ where: { email: credentials.username } }); if (user) { if (!user.emailVerified) { const mailVerifyToken = await bcrypt.hash(credentials.username, 10); const date = new Date().getTime(); const emailVerifyToken = date + "_" + mailVerifyToken; await prisma.user.update({ where: { email: credentials.username }, data: { emailVerifyToken: emailVerifyToken } }); emailHelper.SendEmail_ValidateTemplate(credentials.username, emailVerifyToken); throw new Error('Моля потвърди имейла си преди да влезеш в системата.'); } else { const match = await bcrypt.compare(credentials?.password, user.passwordHashLocalAccount); if (match) { console.log("User authenticated successfully."); //create access token user.accessToken = await getAccessToken(); return user; } else { console.log("Password mismatch."); throw new Error('невалидна парола'); } } } else { const pub = await prisma.publisher.findUnique({ where: { email: credentials.username } }); if (pub) { const passHash = await bcrypt.hash(credentials.password, 10); const mailVerifyToken = await bcrypt.hash(pub.email, 10); const date = new Date().getTime(); const emailVerifyToken = date + "_" + mailVerifyToken; const newUser = await prisma.user.create({ data: { name: credentials.username, email: credentials.username, passwordHashLocalAccount: passHash, emailVerifyToken: emailVerifyToken } }); console.log("New local credential user created for publisher ", pub.firstName, " ", pub.lastName, " (", pub.email, ")"); emailHelper.SendEmail_ValidateTemplate(pub.email, emailVerifyToken, pub.firstName, pub.lastName); //return newUser; throw new Error("Моля проверете вашия имейл '" + credentials?.username + "' за да потвърдите регистрацията си."); } else { throw new Error("Не можем да намерим твоя имейл '" + credentials?.username + "' в участниците в ССОМ. Моля свържи се с нас за да те регистрираме ако искаш да ползваш този имейл."); } } } } }) /* EmailProvider({ server: { host: "smtp.mailtrap.io", port: 2525, auth: { user: "8ec69527ff2104", pass: "c7bc05f171c96c" } }, // server: process.env.EMAIL_SERVER, from: "noreply@example.com", }), // Temporarily removing the Apple provider from the demo site as the // callback URL for it needs updating due to Vercel changing domains /* */ //d-popov@abv.bg // Auth0Provider({ // clientId: process.env.AUTH0_ID, // clientSecret: process.env.AUTH0_SECRET, // issuer: process.env.AUTH0_ISSUER, // }), ], theme: { colorScheme: "light", }, session: { strategy: "jwt" }, callbacks: { // https://codevoweb.com/implement-authentication-with-nextauth-in-nextjs-14/ async signIn({ user, account, profile }) { if (account.provider === 'credentials' && user?.static) { return true; } var prisma = common.getPrismaClient(); console.log("[nextauth] signIn:", account.provider, user.email) //if (account.provider === 'google' ) { // Check user in your database and assign roles const dbUser = await prisma.publisher.findUnique({ where: { email: user.email } }); if (dbUser) { // Assign roles from your database to the session user.role = dbUser.role; user.id = dbUser.id; //user.permissions = dbUser.permissions; const session = { ...user }; await prisma.publisher.update({ where: { id: dbUser.id }, data: { lastLogin: new Date() } }); return true; } else { //user nor found in our database. deny access, showing error message. logout and redirect to message page //throw new Error(`Твоят имейл '${user.email}' не е регистриран в системата. Моля свържи се с нас за да те регистрираме ако искаш да ползваш този имейл.`); throw new Error(`UserNotFound&email=${encodeURIComponent(user?.email)}`); } }, // async redirect({ url, baseUrl, user }) { // // Redirect based on the user or error // console.log("[nextauth] redirect", url, baseUrl, user) // if (user) { // return url; // } else if (url.includes('error=UserNotFound')) { // // Redirect to a custom error page or display an error // return `${baseUrl}/error=UserNotFound&mail=${encodeURIComponent(user?.email)}`; // } // return baseUrl; // }, // Persist the OAuth access_token to the token right after signin async jwt({ token, user, account, profile, isNewUser }) { //!console.log("[nextauth] JWT", token, user) //token.userRole = "adminer" if (user) { token.role = user.role; token.id = user.id; //already done in session? //token.name = user.name; already done in session (name, email, picture, sub) } if (account && user) { token.accessToken = account.access_token; // Set the access token from the account object token.provider = account.provider; console.log("[nextauth] setting token.accessToken", token.accessToken); setAuthTokens({ accessToken: account.accessToken, refreshToken: account.refreshToken, }) } return token; }, // Send properties to the client, like an access_token from a provider. async session({ session, token, user }) { //!console.log("[nextauth] session", token, user) if (token) { //session.user.role = token.role; session.user.id = token.id; session.user.role = token.role; session.user.name = token.name || token.email; } if (user?.impersonating) { // Add flag to session if user is being impersonated session.user.impersonating = true; } // if (session?.user) { // session.user.id = user.id; //duplicate // } return { ...session, accessToken: token.accessToken }; }, }, pages: { signIn: "/auth/signin", signOut: "/auth/signout", error: "/message", // Error code passed in query string as ?error= verifyRequest: "/auth/verify-request", // (used for check email message) newUser: null // If set, new users will be directed here on first sign in }, debug: process.env.NODE_ENV === 'development', } export default NextAuth(authOptions)