rafmacalaba commited on
Commit
aeca117
·
1 Parent(s): 5b37266

security: add auth middleware to block unauthenticated write API calls

Browse files

middleware.js checks hf_user cookie on POST/PUT/DELETE to /api/annotate
and /api/validate. Returns 401 if missing. Also enforces ALLOWED_USERS.
GET (read) endpoints remain open.

Files changed (1) hide show
  1. middleware.js +69 -0
middleware.js ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { NextResponse } from 'next/server';
2
+
3
+ /**
4
+ * Next.js Middleware — runs before every matched request.
5
+ * Enforces authentication (hf_user cookie) on write API endpoints.
6
+ */
7
+
8
+ // Routes that require authentication (write operations)
9
+ const PROTECTED_ROUTES = [
10
+ '/api/annotate', // POST: add annotation, DELETE: remove, PUT: update
11
+ '/api/validate', // PUT: validate mention, DELETE: remove mention
12
+ ];
13
+
14
+ export function middleware(request) {
15
+ const { pathname } = request.nextUrl;
16
+
17
+ // Only protect write endpoints
18
+ const isProtected = PROTECTED_ROUTES.some(route => pathname.startsWith(route));
19
+ if (!isProtected) return NextResponse.next();
20
+
21
+ // Allow GET requests (reads are OK without auth)
22
+ if (request.method === 'GET') return NextResponse.next();
23
+
24
+ // Check for hf_user cookie
25
+ const userCookie = request.cookies.get('hf_user');
26
+ if (!userCookie?.value) {
27
+ return NextResponse.json(
28
+ { error: 'Authentication required. Please sign in with HuggingFace.' },
29
+ { status: 401 }
30
+ );
31
+ }
32
+
33
+ // Parse and verify user is in allowed list
34
+ try {
35
+ const user = JSON.parse(userCookie.value);
36
+ const username = user.username;
37
+
38
+ if (!username) {
39
+ return NextResponse.json(
40
+ { error: 'Invalid session. Please sign in again.' },
41
+ { status: 401 }
42
+ );
43
+ }
44
+
45
+ // Check ALLOWED_USERS if set
46
+ const allowedUsers = process.env.ALLOWED_USERS;
47
+ if (allowedUsers) {
48
+ const allowlist = allowedUsers.split(',').map(u => u.trim().toLowerCase());
49
+ if (!allowlist.includes(username.toLowerCase())) {
50
+ return NextResponse.json(
51
+ { error: `Access denied. User "${username}" is not authorized.` },
52
+ { status: 403 }
53
+ );
54
+ }
55
+ }
56
+ } catch (e) {
57
+ return NextResponse.json(
58
+ { error: 'Invalid session cookie. Please sign in again.' },
59
+ { status: 401 }
60
+ );
61
+ }
62
+
63
+ return NextResponse.next();
64
+ }
65
+
66
+ // Only run middleware on API routes
67
+ export const config = {
68
+ matcher: '/api/:path*',
69
+ };