1+ import type { Context , Next } from 'hono'
2+ import { verify } from 'hono/jwt'
3+ import { env } from '@/env'
4+ import { getAuthorByEmailOrId } from '@/db/author.repo'
5+
6+ /**
7+ * Authenticates a user by verifying the JWT token in the Authorization header.
8+ *
9+ * @example
10+ * ```ts
11+ import { authenticate } from './middleware/auth'
12+
13+ // Apply to specific routes
14+ auth.get('/protected-route', authenticate, async (c) => {
15+ const user = c.get('user')
16+ return c.json({ message: 'Protected data', user })
17+ })
18+
19+ // Or apply to all routes in a group
20+ const protectedRoutes = new Hono()
21+ protectedRoutes.use('*', authenticate)
22+
23+ protectedRoutes.get('/profile', async (c) => {
24+ const user = c.get('user')
25+ return c.json({ user })
26+ })
27+ */
28+ export const authenticate = async ( c : Context , next : Next ) => {
29+ const authHeader = c . req . header ( 'Authorization' )
30+
31+ if ( ! authHeader || ! authHeader . startsWith ( 'Bearer ' ) ) {
32+ return c . json ( { error : 'Authorization header required' } , 401 )
33+ }
34+
35+ const token = authHeader . substring ( 7 )
36+
37+ try {
38+ const payload = await verify ( token , env . ACCESS_TOKEN_SECRET )
39+
40+ if ( payload . type !== 'access' ) {
41+ return c . json ( { error : 'Invalid token type' } , 401 )
42+ }
43+
44+ const authorId = payload . sub
45+ if ( ! authorId || typeof authorId !== 'string' ) {
46+ return c . json ( { error : 'Invalid token payload' } , 401 )
47+ }
48+
49+ const author = await getAuthorByEmailOrId ( { authorId } )
50+ if ( author . length === 0 ) {
51+ return c . json ( { error : 'User not found' } , 404 )
52+ }
53+
54+ c . set ( 'user' , author [ 0 ] )
55+ await next ( )
56+ } catch ( error ) {
57+ return c . json ( { error : 'Invalid or expired token' } , 401 )
58+ }
59+ }
0 commit comments