60 lines
1.6 KiB
TypeScript
Executable file
60 lines
1.6 KiB
TypeScript
Executable file
import { Context, Next } from 'hono';
|
|
import { jwtVerify, errors } from 'jose';
|
|
import { ApiError } from '@/src/lib/api-error'
|
|
import { getEncodedJwtSecret } from '@/src/lib/env-exporter';
|
|
|
|
export const verifyToken = async (c: Context, next: Next) => {
|
|
try {
|
|
// Get token from Authorization header
|
|
const authHeader = c.req.header('authorization');
|
|
|
|
|
|
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
throw new ApiError('Access denied. No token provided', 401);
|
|
}
|
|
|
|
const token = authHeader.split(' ')[1];
|
|
|
|
if (!token) {
|
|
throw new ApiError('Access denied. Invalid token format', 401);
|
|
}
|
|
|
|
// Verify token
|
|
const { payload } = await jwtVerify(token, getEncodedJwtSecret());
|
|
|
|
|
|
// Add user info to context
|
|
c.set('user', payload);
|
|
|
|
await next();
|
|
} catch (error) {
|
|
if (error instanceof errors.JOSEError) {
|
|
throw new ApiError('Invalid Auth Credentials', 401);
|
|
} else {
|
|
throw error;
|
|
}
|
|
}
|
|
};
|
|
|
|
export const requireRole = (roles: string[]) => {
|
|
return async (c: Context, next: Next) => {
|
|
try {
|
|
const user = c.get('user');
|
|
if (!user) {
|
|
throw new ApiError('Authentication required', 401);
|
|
}
|
|
|
|
// Check if user has any of the required roles
|
|
const userRoles = user.roles || [];
|
|
const hasPermission = roles.some(role => userRoles.includes(role));
|
|
|
|
if (!hasPermission) {
|
|
throw new ApiError('Access denied. Insufficient permissions', 403);
|
|
}
|
|
|
|
await next();
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
};
|
|
};
|