Skip to content

Commit 8a4f275

Browse files
committed
chore: updated auth middleware
1 parent f4a3bcf commit 8a4f275

File tree

3 files changed

+51
-38
lines changed

3 files changed

+51
-38
lines changed

src/common/helpers/crypto.service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export class CryptoService {
1414
token: code
1515
})
1616
}
17-
public async generateAccessToken(user: JwtPayloadInterface) {
17+
public generateAccessToken(user: JwtPayloadInterface) {
1818
const options: jwt.SignOptions = {
1919
algorithm: 'HS256',
2020
expiresIn: process.env.JWT_ACCESS_TOKEN_EXPIRATION,
@@ -31,7 +31,7 @@ export class CryptoService {
3131
return accessToken
3232
}
3333

34-
public async verifyAccessToken(token: string) {
34+
public verifyAccessToken(token: string) {
3535
const options: jwt.SignOptions = {
3636
algorithm: 'HS256',
3737
issuer: 'ExerciseDB'

src/middleware/auth/index.ts

Lines changed: 48 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,62 @@
11
import { CryptoService } from '#common/helpers/crypto.service.js'
22
import { Context, Next } from 'hono'
3-
import { verify } from 'jsonwebtoken'
43

54
type Role = 'member' | 'moderator' | 'admin'
65

7-
const ROLE_PERMISSIONS: Record<Role, string[]> = {
8-
member: ['GET'],
9-
moderator: ['GET', 'POST', 'PUT', 'PATCH'],
10-
admin: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']
6+
const ROLE_PERMISSIONS: Record<Role, Set<string>> = {
7+
member: new Set(['GET']),
8+
moderator: new Set(['GET', 'POST', 'PUT', 'PATCH']),
9+
admin: new Set(['GET', 'POST', 'PUT', 'PATCH', 'DELETE'])
1110
}
1211

13-
const restrictedMethods = ['POST', 'PUT', 'PATCH', 'DELETE']
12+
const RESTRICTED_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE'])
13+
const VALID_ROLES = new Set(['member', 'moderator', 'admin'])
1414

15-
function isValidRole(role: string): role is Role {
16-
return ['member', 'moderator', 'admin'].includes(role)
17-
}
1815
const cryptoService = new CryptoService()
19-
const authenticationRoutes = ['/api/v1/register', '/api/v1/authenticate']
2016

21-
/**
22-
* NOTE: REGISTRATION OF NEW USER ONLY ALLOWED IN STAGING EVIROMENT
23-
*/
17+
interface RouteConfig {
18+
path: string
19+
allowedEnvs: Set<string>
20+
skipAuth?: boolean
21+
message?: string
22+
}
23+
24+
const ROUTE_CONFIG: RouteConfig[] = [
25+
{
26+
path: '/api/v1/register',
27+
allowedEnvs: new Set(['development', 'staging']),
28+
skipAuth: true,
29+
message: 'signup is not allowed in production'
30+
},
31+
{ path: '/api/v1/authenticate', allowedEnvs: new Set(['development', 'staging', 'production']), skipAuth: true }
32+
// Add more routes as needed
33+
]
34+
2435
export async function authMiddleware(c: Context, next: Next) {
25-
const method = c.req.method
26-
const path = c.req.path
27-
// Skip middleware for /register and /authenticate routes
36+
const { method, path } = c.req
37+
const currentEnv = process.env.NODE_ENV || 'development'
2838

29-
if (authenticationRoutes.includes(path) && process.env.NODE_ENV !== 'production') {
30-
return next()
31-
}
32-
if (authenticationRoutes.includes(path) && process.env.NODE_ENV === 'production') {
33-
return c.json({ success: false, error: 'SIGNUP | LOGIN is not available in the production environment.' }, 403)
34-
}
39+
const routeConfig = ROUTE_CONFIG.find((route) => route.path === path)
3540

36-
// Allow OPTIONS, HEAD, and other non-restricted methods for all
37-
if (!restrictedMethods.includes(method)) {
38-
return next()
41+
if (routeConfig) {
42+
if (!routeConfig.allowedEnvs.has(currentEnv)) {
43+
return c.json(
44+
{
45+
success: false,
46+
error: routeConfig.message
47+
? routeConfig.message
48+
: `This route is not available in the ${currentEnv} environment.`
49+
},
50+
403
51+
)
52+
}
53+
if (routeConfig.skipAuth) {
54+
return next()
55+
}
3956
}
57+
58+
if (!RESTRICTED_METHODS.has(method)) return next()
59+
4060
const authorization = c.req.header('Authorization')
4161

4262
if (!authorization) {
@@ -49,22 +69,15 @@ export async function authMiddleware(c: Context, next: Next) {
4969
}
5070

5171
try {
52-
const userPayload = await cryptoService.verifyAccessToken(token)
53-
54-
if (!isValidRole(userPayload.role)) {
55-
return c.json({ success: false, error: 'Forbidden Request' }, 403)
56-
}
57-
const allowedMethods = ROLE_PERMISSIONS[userPayload.role]
58-
59-
if (!allowedMethods.includes(method)) {
72+
const userPayload = cryptoService.verifyAccessToken(token)
73+
if (!VALID_ROLES.has(userPayload.role) || !ROLE_PERMISSIONS[userPayload.role as Role].has(method)) {
6074
return c.json({ success: false, error: 'Forbidden' }, 403)
6175
}
6276

6377
c.set('user', userPayload)
64-
6578
await next()
6679
} catch (error) {
67-
console.log(error)
80+
console.error(error)
6881
return c.json({ success: false, error: 'Invalid token' }, 401)
6982
}
7083
}

src/modules/users/services/user.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export class UserService {
2121

2222
authenticate = async (args: AuthenticateUserArgs) => {
2323
const user = await this.authenticateUserUseCase.execute(args)
24-
const token = await this.cryptoService.generateAccessToken(user)
24+
const token = this.cryptoService.generateAccessToken(user)
2525
return {
2626
token
2727
}

0 commit comments

Comments
 (0)