58 lines
1.3 KiB
TypeScript
58 lines
1.3 KiB
TypeScript
import { Context, Next, State } from "@oak/oak";
|
|
import { verifyJWT } from "../lib/jwt.ts";
|
|
import {
|
|
APIErrorCode,
|
|
APIException,
|
|
type AuthPayload,
|
|
} from "../model/interfaces.ts";
|
|
import { getUserById } from "../services/user-service.ts";
|
|
|
|
export interface AuthContext extends Context {
|
|
state: AuthState;
|
|
}
|
|
|
|
export interface AuthState extends State {
|
|
user: AuthPayload;
|
|
}
|
|
|
|
export async function authMiddleware(ctx: AuthContext, next: Next) {
|
|
const authHeader = ctx.request.headers.get("Authorization");
|
|
|
|
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
throw new APIException(
|
|
APIErrorCode.UNAUTHORIZED,
|
|
401,
|
|
"Missing or invalid token",
|
|
);
|
|
}
|
|
|
|
const token = authHeader.substring(7);
|
|
const payload = await verifyJWT(token);
|
|
|
|
if (!payload) {
|
|
throw new APIException(APIErrorCode.UNAUTHORIZED, 401, "Invalid token");
|
|
}
|
|
|
|
try {
|
|
getUserById(payload.userId);
|
|
} catch {
|
|
throw new APIException(APIErrorCode.UNAUTHORIZED, 401, "User not found");
|
|
}
|
|
|
|
ctx.state.user = payload;
|
|
|
|
await next();
|
|
}
|
|
|
|
export async function adminOnlyMiddleware(ctx: AuthContext, next: Next) {
|
|
if (!ctx.state.user?.isAdmin) {
|
|
throw new APIException(
|
|
APIErrorCode.UNAUTHORIZED,
|
|
403,
|
|
"Admin access required",
|
|
);
|
|
}
|
|
|
|
await next();
|
|
}
|