119 lines
3.3 KiB
TypeScript
119 lines
3.3 KiB
TypeScript
import { betterAuth } from "better-auth";
|
|
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
|
import { createAuthMiddleware } from "better-auth/api";
|
|
import { apiKey } from "better-auth/plugins";
|
|
import { magicLink } from "better-auth/plugins/magic-link";
|
|
|
|
import type { dbClient } from "@kan/db/client";
|
|
import * as memberRepo from "@kan/db/repository/member.repo";
|
|
import * as userRepo from "@kan/db/repository/user.repo";
|
|
import * as schema from "@kan/db/schema";
|
|
import { sendEmail } from "@kan/email";
|
|
import { createStripeClient } from "@kan/stripe";
|
|
|
|
export const initAuth = (db: dbClient) => {
|
|
return betterAuth({
|
|
secret: process.env.BETTER_AUTH_SECRET!,
|
|
baseURL: process.env.BETTER_AUTH_BASE_URL!,
|
|
trustedOrigins: process.env.BETTER_AUTH_TRUSTED_ORIGINS
|
|
? process.env.BETTER_AUTH_TRUSTED_ORIGINS.split(",")
|
|
: [],
|
|
database: drizzleAdapter(db, {
|
|
provider: "pg",
|
|
schema: {
|
|
...schema,
|
|
user: schema.users,
|
|
},
|
|
}),
|
|
socialProviders: {
|
|
google: {
|
|
clientId: process.env.GOOGLE_CLIENT_ID!,
|
|
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
|
|
},
|
|
},
|
|
user: {
|
|
additionalFields: {
|
|
stripeCustomerId: {
|
|
type: "string",
|
|
required: false,
|
|
defaultValue: null,
|
|
input: false,
|
|
},
|
|
},
|
|
},
|
|
plugins: [
|
|
apiKey(),
|
|
magicLink({
|
|
expiresIn: 60 * 60 * 24 * 7, // 7 days
|
|
sendMagicLink: async ({ email, url }) => {
|
|
if (url.includes("type=invite")) {
|
|
await sendEmail(
|
|
email,
|
|
"Invitation to join workspace",
|
|
"JOIN_WORKSPACE",
|
|
{
|
|
magicLoginUrl: url,
|
|
},
|
|
);
|
|
} else {
|
|
await sendEmail(email, "Sign in to kan.bn", "MAGIC_LINK", {
|
|
magicLoginUrl: url,
|
|
});
|
|
}
|
|
},
|
|
}),
|
|
],
|
|
hooks: {
|
|
after: createAuthMiddleware(async (ctx) => {
|
|
if (ctx.path.startsWith("/get-session")) {
|
|
const user = ctx.context.session?.user;
|
|
|
|
if (
|
|
process.env.NEXT_PUBLIC_KAN_ENV === "cloud" &&
|
|
user &&
|
|
!user.stripeCustomerId
|
|
) {
|
|
const stripe = createStripeClient();
|
|
const stripeCustomer = await stripe.customers.create({
|
|
email: user.email,
|
|
metadata: {
|
|
userId: user.id,
|
|
},
|
|
});
|
|
|
|
await userRepo.update(db, user.id, {
|
|
stripeCustomerId: stripeCustomer.id,
|
|
});
|
|
}
|
|
} else if (
|
|
ctx.path === "/magic-link/verify" &&
|
|
(ctx.query?.callbackURL as string | undefined)?.includes(
|
|
"type=invite",
|
|
) &&
|
|
ctx.query?.memberPublicId
|
|
) {
|
|
const userId = ctx.context.newSession?.session.userId;
|
|
const memberPublicId = ctx.query.memberPublicId as string;
|
|
|
|
if (userId) {
|
|
const member = await memberRepo.getByPublicId(db, memberPublicId);
|
|
|
|
if (member?.id) {
|
|
await memberRepo.acceptInvite(db, {
|
|
memberId: member.id,
|
|
userId,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}),
|
|
},
|
|
advanced: {
|
|
cookiePrefix: "kan",
|
|
database: {
|
|
generateId: false,
|
|
},
|
|
},
|
|
});
|
|
};
|