42 lines
1.3 KiB
TypeScript
42 lines
1.3 KiB
TypeScript
// JWT Authentication Middleware
|
|
import type { FastifyRequest, FastifyReply } from "fastify";
|
|
import type { JwtPayload } from "../types/index.js";
|
|
|
|
/**
|
|
* Verify JWT token and attach user to request.
|
|
*/
|
|
export async function authenticate(request: FastifyRequest, reply: FastifyReply): Promise<void> {
|
|
try {
|
|
await request.jwtVerify();
|
|
} catch (err) {
|
|
reply.status(401).send({ error: "Unauthorized", message: "Invalid or expired token", statusCode: 401 });
|
|
}
|
|
}
|
|
|
|
/** Helper to get typed user from request (after authenticate). */
|
|
export function getUser(request: FastifyRequest): JwtPayload {
|
|
return request.user as unknown as JwtPayload;
|
|
}
|
|
|
|
/**
|
|
* Require admin role.
|
|
* Must be used after authenticate.
|
|
*/
|
|
export async function requireAdmin(request: FastifyRequest, reply: FastifyReply): Promise<void> {
|
|
const user = request.user as unknown as JwtPayload | undefined;
|
|
if (!user || user.role !== "admin") {
|
|
reply.status(403).send({ error: "Forbidden", message: "Admin access required", statusCode: 403 });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Optional auth: attach user if token present, but don't fail if missing.
|
|
*/
|
|
export async function optionalAuth(request: FastifyRequest): Promise<void> {
|
|
try {
|
|
await request.jwtVerify();
|
|
} catch {
|
|
// No token or invalid — continue without user
|
|
}
|
|
}
|