101 lines
2.5 KiB
TypeScript
101 lines
2.5 KiB
TypeScript
import type Elysia from "elysia";
|
|
import { auth } from "@/utils/auth";
|
|
import { prisma } from "@/utils/db";
|
|
import logger from "@/utils/logger";
|
|
|
|
export function apiMiddleware(app: Elysia) {
|
|
return app
|
|
.derive(async ({ request }) => {
|
|
const headers = request.headers;
|
|
|
|
// First, try to get user from session (Better Auth)
|
|
const userSession = await auth.api.getSession({
|
|
headers,
|
|
});
|
|
|
|
if (userSession?.user) {
|
|
// Return user data from session if authenticated via session
|
|
return {
|
|
user: {
|
|
...userSession.user,
|
|
id: userSession.user.id,
|
|
email: userSession.user.email,
|
|
name: userSession.user.name,
|
|
image: userSession.user.image,
|
|
emailVerified: userSession.user.emailVerified,
|
|
role: userSession.user.role || "user",
|
|
},
|
|
};
|
|
}
|
|
|
|
// If no session, try API key authentication
|
|
let apiKey = headers.get("x-api-key");
|
|
|
|
if (!apiKey) {
|
|
// Also check Authorization header for API key
|
|
const authHeader =
|
|
headers.get("authorization") || headers.get("Authorization");
|
|
if (authHeader?.startsWith("Bearer ")) {
|
|
apiKey = authHeader.substring(7);
|
|
}
|
|
}
|
|
|
|
if (!apiKey) {
|
|
return { user: null };
|
|
}
|
|
|
|
try {
|
|
// Look up the API key in the database
|
|
const apiKeyRecord = await prisma.apiKey.findFirst({
|
|
where: {
|
|
key: apiKey,
|
|
isActive: true,
|
|
},
|
|
include: {
|
|
user: true, // Include the associated user
|
|
},
|
|
});
|
|
|
|
if (!apiKeyRecord) {
|
|
return { user: null };
|
|
}
|
|
|
|
// Check if API key has expired
|
|
if (
|
|
apiKeyRecord.expiresAt &&
|
|
new Date(apiKeyRecord.expiresAt) < new Date()
|
|
) {
|
|
logger.info({ keyId: apiKeyRecord.id }, "[AUTH] API key expired");
|
|
return { user: null };
|
|
}
|
|
|
|
// Return the associated user data
|
|
return {
|
|
user: {
|
|
id: apiKeyRecord.user.id,
|
|
email: apiKeyRecord.user.email,
|
|
name: apiKeyRecord.user.name,
|
|
image: apiKeyRecord.user.image,
|
|
emailVerified: apiKeyRecord.user.emailVerified,
|
|
role: apiKeyRecord.user.role || "user",
|
|
},
|
|
};
|
|
} catch (err) {
|
|
logger.warn({ err }, "[AUTH] Error verifying API key");
|
|
return { user: null };
|
|
}
|
|
})
|
|
.onBeforeHandle(({ user, set, request }) => {
|
|
const url = new URL(request.url);
|
|
if (url.pathname.startsWith("/api/docs")) {
|
|
return;
|
|
}
|
|
|
|
if (!user) {
|
|
logger.warn(`[AUTH] Unauthorized: ${request.method} ${request.url}`);
|
|
set.status = 401;
|
|
return { message: "Unauthorized" };
|
|
}
|
|
});
|
|
}
|