Files
dokploy/packages/server/src/lib/auth.ts

152 lines
3.4 KiB
TypeScript

import type { IncomingMessage } from "node:http";
import * as bcrypt from "bcrypt";
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import {
createAuthMiddleware,
organization,
twoFactor,
} from "better-auth/plugins";
import { desc, eq } from "drizzle-orm";
import { db } from "../db";
import * as schema from "../db/schema";
export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg",
schema: schema,
}),
appName: "Dokploy",
socialProviders: {
github: {
clientId: process.env.GITHUB_CLIENT_ID as string,
clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
},
google: {
clientId: process.env.GOOGLE_CLIENT_ID as string,
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
},
},
emailAndPassword: {
enabled: true,
password: {
async hash(password) {
return bcrypt.hashSync(password, 10);
},
async verify({ hash, password }) {
return bcrypt.compareSync(password, hash);
},
},
},
hooks: {
after: createAuthMiddleware(async (ctx) => {
if (ctx.path.startsWith("/sign-up")) {
const newSession = ctx.context.newSession;
const organization = await db
.insert(schema.organization)
.values({
name: "My Organization",
ownerId: newSession?.user?.id || "",
createdAt: new Date(),
})
.returning()
.then((res) => res[0]);
await db.insert(schema.member).values({
userId: newSession?.user?.id || "",
organizationId: organization?.id || "",
role: "owner",
createdAt: new Date(),
});
}
}),
},
databaseHooks: {
session: {
create: {
before: async (session) => {
const member = await db.query.member.findFirst({
where: eq(schema.member.userId, session.userId),
orderBy: desc(schema.member.createdAt),
with: {
organization: true,
},
});
return {
data: {
...session,
activeOrganizationId: member?.organization.id,
},
};
},
},
},
},
user: {
modelName: "users_temp",
additionalFields: {
role: {
type: "string",
required: true,
},
ownerId: {
type: "string",
required: true,
},
},
},
plugins: [
twoFactor(),
organization({
async sendInvitationEmail(data, request) {
const inviteLink = `https://example.com/accept-invitation/${data.id}`;
// https://example.com/accept-invitation/8jlBi9Tb9isDb8mc8Sb85u1BaJYklKB2
// sendOrganizationInvitation({
// email: data.email,
// invitedByUsername: data.inviter.user.name,
// invitedByEmail: data.inviter.user.email,
// teamName: data.organization.name,
// inviteLink
// })
console.log("Invitation link", inviteLink);
},
}),
],
});
export const validateRequest = async (request: IncomingMessage) => {
const session = await auth.api.getSession({
headers: new Headers({
cookie: request.headers.cookie || "",
}),
});
if (!session?.session || !session.user) {
return {
session: null,
user: null,
};
}
if (session?.user) {
const member = await db.query.member.findFirst({
where: eq(schema.member.userId, session.user.id),
with: {
organization: true,
},
});
session.user.role = member?.role || "member";
if (member) {
session.user.ownerId = member.organization.ownerId;
} else {
session.user.ownerId = session.user.id;
}
}
return session;
};