Index: auth.d.ts
===================================================================
--- auth.d.ts	(revision 898cf683befadffe8aea07855b58db8cd5082ff9)
+++ auth.d.ts	(revision 898cf683befadffe8aea07855b58db8cd5082ff9)
@@ -0,0 +1,15 @@
+import type { DefaultSession } from "@auth/core/types";
+
+declare module "@auth/core/types" {
+    interface User {
+        id: string;
+        isAdmin?: boolean;
+    }
+
+    interface Session {
+        user?: {
+            id: string;
+            isAdmin?: boolean;
+        } & DefaultSession["user"];
+    }
+}
Index: server/authjs-handler.ts
===================================================================
--- server/authjs-handler.ts	(revision e7f1bfa7ce76200b61fe01419065e5b4c1bc1f96)
+++ server/authjs-handler.ts	(revision 898cf683befadffe8aea07855b58db8cd5082ff9)
@@ -3,9 +3,9 @@
 import type { Session } from "@auth/core/types";
 import { enhance, type UniversalHandler, type UniversalMiddleware } from "@universal-middleware/core";
-import {eq} from "drizzle-orm";
+import {eq, or} from "drizzle-orm";
 import { db } from "../database/drizzle/db";
-import { usersTable } from "../database/drizzle/schema";
+import {adminsTable, usersTable} from "../database/drizzle/schema";
 import bcrypt from "bcrypt";
-// import { users, accounts, sessions, verificationTokens } from "../database/drizzle/schema/auth";
+import { AuthDrizzleAdapter } from "./drizzle/auth-adapter";
 
 const authjsConfig = {
@@ -13,4 +13,5 @@
   trustHost: true,
   secret: process.env.AUTH_SECRET,
+  adapter: AuthDrizzleAdapter(),
   session: {
     strategy: "jwt",
@@ -27,20 +28,34 @@
         const password = typeof credentials?.password === "string" ? credentials.password : null;
 
-        if(!username || !password) { return null; }
+        if(!username || !password || typeof username !== 'string' || typeof password !== 'string') { return null; }
 
         const user = await db.query.usersTable.findFirst({
-            where: eq(usersTable.username, username),
-        });
+            where: or(
+                eq(usersTable.username, username),
+                eq(usersTable.email, username)
+            ),
+          });
 
-        if(!user) { return null; }
+        if(!user) return null;
 
-        const isPasswordValid = await bcrypt.compare(password, user.passwordHash);
+        let isPasswordValid = false;
 
-        if(!isPasswordValid) { return null; }
+        if (user.passwordHash.startsWith('$2b$') || user.passwordHash.startsWith('$2a$')) {
+            isPasswordValid = await bcrypt.compare(password, user.passwordHash);
+        } else {
+            isPasswordValid = password === user.passwordHash;
+        }
+
+        if(!isPasswordValid) return null;
+
+          const admin = await db.query.adminsTable.findFirst({
+              where: eq(adminsTable.userId, user.id),
+          });
 
         return {
             id: String(user.id),
-            name: user.username,
+            username: user.username,
             email: user.email,
+            isAdmin: !!admin
         }
       },
@@ -50,9 +65,23 @@
   callbacks: {
       async jwt({ token, user }) {
-          if (user) token.sub = user.id;
+          if (user) {
+              token.sub = user.id;
+              token.username = user.name;
+
+              const customUser = user as any;
+              token.email = customUser.email;
+              token.isAdmin = customUser.isAdmin;
+          }
           return token;
       },
       async session({ session, token }) {
-          if (session.user && token.sub) session.user.id = token.sub;
+          if (session.user) {
+              session.user.id = token.sub!;
+              session.user.name = token.name as string;
+
+              const customToken = token as any;
+              session.user.email = customToken.email;
+              session.user.isAdmin = customToken.isAdmin;
+          }
           return session;
       },
@@ -60,7 +89,4 @@
 } satisfies Omit<AuthConfig, "raw">;
 
-/**
- * Retrieve Auth.js session from Request
- */
 export async function getSession(req: Request, config: Omit<AuthConfig, "raw">): Promise<Session | null> {
   setEnvDefaults(process.env, config);
@@ -79,8 +105,4 @@
 }
 
-/**
- * Add Auth.js session to context
- * @link {@see https://authjs.dev/getting-started/session-management/get-session}
- **/
 export const authjsSessionMiddleware: UniversalMiddleware = enhance(
   async (request, context) => {
@@ -104,8 +126,4 @@
 );
 
-/**
- * Auth.js route
- * @link {@see https://authjs.dev/getting-started/installation}
- **/
 export const authjsHandler = enhance(
   async (request) => {
Index: server/drizzle/auth-adapter.ts
===================================================================
--- server/drizzle/auth-adapter.ts	(revision 898cf683befadffe8aea07855b58db8cd5082ff9)
+++ server/drizzle/auth-adapter.ts	(revision 898cf683befadffe8aea07855b58db8cd5082ff9)
@@ -0,0 +1,64 @@
+import type { Adapter } from "@auth/core/adapters";
+import { db } from "../../database/drizzle/db";
+import { usersTable, adminsTable } from "../../database/drizzle/schema";
+import { eq } from "drizzle-orm";
+
+export function AuthDrizzleAdapter(): Adapter {
+    return {
+        async getUser(id) {
+            const userId = parseInt(id);
+            if (isNaN(userId)) return null;
+
+            const user = await db.query.usersTable.findFirst({
+                where: eq(usersTable.id, userId),
+            });
+
+            if (!user) return null;
+
+            const admin = await db.query.adminsTable.findFirst({
+                where: eq(adminsTable.userId, user.id),
+            });
+
+            return {
+                id: String(user.id),
+                email: user.email,
+                name: user.username,
+                emailVerified: null,
+                isAdmin: !!admin,
+            };
+        },
+
+        async getUserByEmail(email) {
+            const user = await db.query.usersTable.findFirst({
+                where: eq(usersTable.email, email),
+            });
+
+            if (!user) return null;
+
+            const admin = await db.query.adminsTable.findFirst({
+                where: eq(adminsTable.userId, user.id),
+            });
+
+            return {
+                id: String(user.id),
+                email: user.email,
+                name: user.username,
+                emailVerified: null,
+                isAdmin: !!admin,
+            };
+        },
+
+        async createUser() { return null as any; },
+        async updateUser() { return null as any; },
+        async deleteUser() {},
+        async getUserByAccount() { return null; },
+        async createSession() { return null as any; },
+        async getSessionAndUser() { return null; },
+        async updateSession() { return null; },
+        async deleteSession() {},
+        async linkAccount() { return null as any; },
+        async unlinkAccount() {},
+        async createVerificationToken() { return null as any; },
+        async useVerificationToken() { return null; },
+    };
+}
Index: server/telefunc/ctx.ts
===================================================================
--- server/telefunc/ctx.ts	(revision e7f1bfa7ce76200b61fe01419065e5b4c1bc1f96)
+++ server/telefunc/ctx.ts	(revision 898cf683befadffe8aea07855b58db8cd5082ff9)
@@ -33,7 +33,10 @@
     const { c, userId } = requireUser();
 
+
+    if(!c.session?.user?.isAdmin === false) throw Abort();
+
     const isAdmin = await drizzleQueries.isAdmin(c.db, userId);
+    if (!isAdmin) throw Abort();
 
-    if (!isAdmin) throw Abort();
     return { c, userId };
 }
