forked from ritik4ever/stellar-goal-vault
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapiKeyAuth.ts
More file actions
66 lines (57 loc) · 1.81 KB
/
Copy pathapiKeyAuth.ts
File metadata and controls
66 lines (57 loc) · 1.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import { Request, Response, NextFunction } from "express";
import { AppError } from "../types/errors";
export interface RequestWithApiKey extends Request {
apiKey?: string;
isAuthenticated?: boolean;
}
/**
* API Key authentication middleware.
* Validates API key from Authorization header (Bearer token format).
* Skips authentication for public endpoints (health, config, stats, leaderboard, open-issues).
*
* Environment variable: API_KEYS (comma-separated list of valid API keys)
* Header format: Authorization: Bearer <api-key>
*/
export function apiKeyAuthMiddleware(
req: RequestWithApiKey,
res: Response,
next: NextFunction,
): void {
// Public endpoints that don't require authentication
const publicPaths = [
"/api/health",
"/api/config",
"/api/stats",
"/api/leaderboard",
"/api/open-issues",
];
// Check if current path is public
const isPublicPath = publicPaths.some((path) => req.path.startsWith(path));
if (isPublicPath) {
req.isAuthenticated = true;
return next();
}
// Extract API key from Authorization header
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith("Bearer ")) {
throw new AppError(
"Missing or invalid Authorization header. Use format: Bearer <api-key>",
401,
"UNAUTHORIZED",
);
}
const apiKey = authHeader.slice(7); // Remove "Bearer " prefix
const validApiKeys = (process.env.API_KEYS || "").split(",").filter(Boolean);
if (validApiKeys.length === 0) {
// If no API keys configured, allow all requests (development mode)
req.isAuthenticated = true;
req.apiKey = apiKey;
return next();
}
if (!validApiKeys.includes(apiKey)) {
throw new AppError("Invalid API key", 403, "FORBIDDEN");
}
req.isAuthenticated = true;
req.apiKey = apiKey;
next();
}