librelad 875a60f90f LibrePortal v0.1.0 — initial release
A free, open, self-hosted app platform (GNU AGPLv3): one-click app deploys,
Traefik reverse proxy with automatic SSL, rootless Docker support, gluetun
VPN routing, and a web dashboard to manage it all.

Free & open forever to self-host; optional paid hosted services fund it.
See PROMISE.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-21 20:37:54 +01:00

75 lines
2.3 KiB
TypeScript

import NextAuth from "next-auth";
import Credentials from "next-auth/providers/credentials";
import { DrizzleAdapter } from "@auth/drizzle-adapter";
import bcrypt from "bcryptjs";
import { eq } from "drizzle-orm";
import { db } from "@/db";
import {
users,
authAccounts,
sessions,
verificationTokens,
} from "@/db/schema";
import { authConfig } from "@/auth.config";
export const { handlers, signIn, signOut, auth } = NextAuth({
...authConfig,
adapter: DrizzleAdapter(db, {
usersTable: users,
accountsTable: authAccounts,
sessionsTable: sessions,
verificationTokensTable: verificationTokens,
}),
session: { strategy: "jwt" },
providers: [
Credentials({
name: "Credentials",
credentials: {
email: { label: "Email", type: "email" },
password: { label: "Password", type: "password" },
},
authorize: async (credentials) => {
const email = String(credentials?.email ?? "").toLowerCase().trim();
const password = String(credentials?.password ?? "");
if (!email || !password) return null;
const [u] = await db.select().from(users).where(eq(users.email, email));
if (!u || !u.passwordHash) return null;
const ok = await bcrypt.compare(password, u.passwordHash);
if (!ok) return null;
return {
id: u.id,
email: u.email,
name: u.name ?? u.email,
image: u.image ?? undefined,
};
},
}),
],
callbacks: {
...authConfig.callbacks,
async jwt({ token, user }) {
if (user?.id) token.userId = user.id;
if (token.userId) {
const [u] = await db
.select({ householdId: users.householdId, role: users.role })
.from(users)
.where(eq(users.id, token.userId as string));
if (u) {
token.householdId = u.householdId ?? null;
token.role = u.role;
}
}
return token;
},
async session({ session, token }) {
if (session.user) {
session.user.id = token.userId as string;
(session.user as { householdId?: string | null }).householdId =
(token.householdId as string | null) ?? null;
(session.user as { role?: string }).role = (token.role as string) ?? "member";
}
return session;
},
},
});