source: server/authjs-handler.ts@ 5a1bf39

main
Last change on this file since 5a1bf39 was 016481f, checked in by Tome <gjorgievtome@…>, 7 months ago

fix admin check

  • Property mode set to 100644
File size: 4.2 KB
Line 
1import { Auth, type AuthConfig, createActionURL, setEnvDefaults } from "@auth/core";
2import CredentialsProvider from "@auth/core/providers/credentials";
3import type { Session } from "@auth/core/types";
4import { enhance, type UniversalHandler, type UniversalMiddleware } from "@universal-middleware/core";
5import {eq, or} from "drizzle-orm";
6import { db } from "../database/drizzle/db";
7import {adminsTable, usersTable} from "../database/drizzle/schema";
8import bcrypt from "bcrypt";
9import { AuthDrizzleAdapter } from "./drizzle/auth-adapter";
10
11const authjsConfig = {
12 basePath: "/api/auth",
13 trustHost: true,
14 secret: process.env.AUTH_SECRET,
15 adapter: AuthDrizzleAdapter(),
16 session: {
17 strategy: "jwt",
18 },
19 providers: [
20 CredentialsProvider({
21 name: "Credentials",
22 credentials: {
23 username: { label: "Username", type: "text" },
24 password: { label: "Password", type: "password" },
25 },
26 async authorize(credentials) {
27 const username = typeof credentials?.username === "string" ? credentials.username : null;
28 const password = typeof credentials?.password === "string" ? credentials.password : null;
29
30 if(!username || !password || typeof username !== 'string' || typeof password !== 'string') { return null; }
31
32 const user = await db.query.usersTable.findFirst({
33 where: or(
34 eq(usersTable.username, username),
35 eq(usersTable.email, username)
36 ),
37 });
38
39 if(!user) return null;
40
41 let isPasswordValid = false;
42
43 if (user.passwordHash.startsWith('$2b$') || user.passwordHash.startsWith('$2a$')) {
44 isPasswordValid = await bcrypt.compare(password, user.passwordHash);
45 } else {
46 isPasswordValid = password === user.passwordHash;
47 }
48
49 if(!isPasswordValid) return null;
50
51 const admin = await db.query.adminsTable.findFirst({
52 where: eq(adminsTable.userId, user.id),
53 });
54
55 return {
56 id: String(user.id),
57 username: user.username,
58 email: user.email,
59 isAdmin: !!admin
60 }
61 },
62 }),
63 ],
64
65 callbacks: {
66 async jwt({ token, user }) {
67 if (user) {
68 token.sub = user.id;
69
70 const customUser = user as any;
71 token.username = customUser.username;
72 token.email = customUser.email;
73 token.isAdmin = customUser.isAdmin;
74 }
75 return token;
76 },
77 async session({ session, token }) {
78 if (session.user) {
79 session.user.id = token.sub!;
80 session.user.name = token.username as string;
81
82 const customToken = token as any;
83 session.user.email = customToken.email;
84 session.user.isAdmin = customToken.isAdmin;
85 }
86 return session;
87 },
88 },
89} satisfies Omit<AuthConfig, "raw">;
90
91export async function getSession(req: Request, config: Omit<AuthConfig, "raw">): Promise<Session | null> {
92 setEnvDefaults(process.env, config);
93 const requestURL = new URL(req.url);
94 const url = createActionURL("session", requestURL.protocol, req.headers, process.env, config);
95
96 const response = await Auth(new Request(url, { headers: { cookie: req.headers.get("cookie") ?? "" } }), config);
97
98 const { status = 200 } = response;
99
100 const data = await response.json();
101
102 if (!data || !Object.keys(data).length) return null;
103 if (status === 200) return data as Session;
104 throw new Error(typeof data === "object" && "message" in data ? (data.message as string) : undefined);
105}
106
107export const authjsSessionMiddleware: UniversalMiddleware = enhance(
108 async (request, context) => {
109 try {
110 return {
111 ...context,
112 session: await getSession(request, authjsConfig),
113 };
114 } catch (error) {
115 console.debug("authjsSessionMiddleware:", error);
116 return {
117 ...context,
118 session: null,
119 };
120 }
121 },
122 {
123 name: "pc-forge:authjs-middleware",
124 immutable: false,
125 },
126);
127
128export const authjsHandler = enhance(
129 async (request) => {
130 return Auth(request, authjsConfig);
131 },
132 {
133 name: "pc-forge:authjs-handler",
134 path: "/api/auth/**",
135 method: ["GET", "POST"],
136 immutable: false,
137 },
138) satisfies UniversalHandler;
Note: See TracBrowser for help on using the repository browser.