platforms
platforms copied to clipboard
Supporting tenant subdomain login
Thank you for the amazing work on this repo!
I wanted to ask how can I support users logging on the tenant's website as well.
Here's what I wanted to do:
- Support users logging in on the admin dashboard (app.xxx.xx)[This is working fine with next-auth].
- Customers logging in on the tentant's website as well. (xxx.xxx.xxx) [I am not sure how will that work].
Since the /api can only have one auth route, I though of doing something like this firstly:
import { adminAuthOptions, customerAuthOptions } from "@gramflow/auth"; // Import both admin and user authentication options
import NextAuth from "next-auth";
export async function GET(request: Request) {
const url = new URL(request.headers.get("referer") ?? "");
// Check if the subdomain is 'app'
const subdomain = url.hostname.split('.')[0];
console.log({ subdomain });
if (subdomain === 'app') {
return NextAuth(adminAuthOptions);
} else {
return NextAuth(customerAuthOptions);
}
}
export async function POST(request: Request) {
const url = new URL(request.headers.get("referer") ?? "");
// Check if the subdomain is 'app'
const subdomain = url.hostname.split('.')[0];
console.log({ subdomain });
if (subdomain === 'app') {
return NextAuth(adminAuthOptions);
} else {
return NextAuth(customerAuthOptions);
}
}
but next complains that i am not returning a response here.
My auth-options look something like this:
import { CookiesOptions, DefaultSession, DefaultUser, Session, SessionStrategy, User, getServerSession, type NextAuthOptions } from "next-auth";
import { PrismaAdapter } from "next-auth-prisma-adapter";
import OtpGenerator from "otp-generator";
import { Resend } from "resend";
import { USER_ROLE, db } from "@gramflow/db";
import { env } from "../env.mjs";
import { JWT } from "next-auth/jwt";
import { AdapterUser } from "next-auth/adapters";
import { Provider } from "next-auth/providers";
const VERCEL_DEPLOYMENT = !!process.env.VERCEL_URL;
const sessionStrategy = {
strategy: "jwt" as SessionStrategy,
};
const secret = process.env.NEXTAUTH_SECRET;
const callbacks = {
async jwt({ token, user }: {
token: JWT,
user: AdapterUser | User
}) {
if (user) {
token.role = user.role;
}
return token;
},
async session({ session, token }: {
session: Session,
token: JWT
}) {
if (token?.role) {
//@ts-ignore
session.user.role = token.role;
}
//add the user id to the session
session.user.id = token.sub ?? "";
return session;
},
}
const pages = {
signIn: "/login",
}
const cookies = {
sessionToken: {
name: `${VERCEL_DEPLOYMENT ? "__Secure-" : ""}next-auth.session-token`,
options: {
httpOnly: true,
sameSite: "lax",
path: "/",
// When working on localhost, the cookie domain must be omitted entirely (https://stackoverflow.com/a/1188145)
domain: VERCEL_DEPLOYMENT
? `.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`
: undefined,
secure: VERCEL_DEPLOYMENT,
},
},
} as Partial<CookiesOptions>
const providers: Provider[] = [
{
id: "email",
type: "email",
from: env.EMAIL_FROM,
server: {},
maxAge: 5 * 60,
name: "Email",
options: {},
async generateVerificationToken() {
const token = OtpGenerator.generate(6, {
lowerCaseAlphabets: false,
upperCaseAlphabets: false,
digits: true,
specialChars: false,
});
console.log("Generated OTP", token);
return token;
},
async sendVerificationRequest({ identifier: email, url, token }: {
identifier: string,
url: string,
token: string
}) {
console.log("Token", token);
try {
console.log("Sending email....", email);
// const data = await resend.emails.send({
// from: `${AppConfig.StoreName} <${env.EMAIL_FROM}>`,
// to: [email],
// subject: "Login to your account",
// html: OtpEmailHtml({
// emailDetails: {
// otp: token,
// storeName: AppConfig.StoreName,
// storeInstagramUsername: AppConfig.InstagramUsername,
// baseOrderUrl: AppConfig.BaseOrderUrl,
// warehouseCity: AppConfig.WarehouseDetails.city,
// warehouseState: AppConfig.WarehouseDetails.state,
// warehouseCountry: AppConfig.WarehouseDetails.country,
// }
// })
// });
//console.log(data)
} catch (e) {
console.log(e);
throw new Error(JSON.stringify(e));
}
},
},
]
export const adminAuthOptions: NextAuthOptions = {
session: sessionStrategy,
secret: secret,
callbacks: callbacks,
cookies: cookies,
adapter: PrismaAdapter(db, {
userModel: "User",
accountModel: "Account",
sessionModel: "Session",
verificationTokenModel: "VerificationToken",
}),
pages,
providers,
};
export const customerAuthOptions: NextAuthOptions = {
session: sessionStrategy,
secret: secret,
callbacks: callbacks,
adapter: PrismaAdapter(db, {
userModel: "Customer",
accountModel: "AccountCustomer",
sessionModel: "SessionCustomer",
verificationTokenModel: "VerificationToken",
}),
pages,
providers,
};
export function getSession() {
return getServerSession(adminAuthOptions) as Promise<{
user: {
id: string;
name: string;
username: string;
email: string;
image: string;
};
} | null>;
}
Here: User-> Users who sign up on the admin panel Customer-> Customer who sign up on the tenant website.