blob: 51b4d9d42bad2f69ff05e6eddd8a7d63a0c7591b (
plain)
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
|
import type { Context, Next } from "hono";
import { verify } from "hono/jwt";
import { Errors } from "./error-handler.js";
const JWT_SECRET = process.env.JWT_SECRET;
if (!JWT_SECRET) {
throw new Error("JWT_SECRET environment variable is required");
}
export interface AuthUser {
id: string;
}
interface JWTPayload {
sub: string;
iat: number;
exp: number;
}
/**
* Auth middleware that validates JWT tokens from Authorization header
* Sets the authenticated user in context variables
*/
export async function authMiddleware(c: Context, next: Next) {
const authHeader = c.req.header("Authorization");
if (!authHeader) {
throw Errors.unauthorized("Missing Authorization header", "MISSING_AUTH");
}
if (!authHeader.startsWith("Bearer ")) {
throw Errors.unauthorized(
"Invalid Authorization header format",
"INVALID_AUTH_FORMAT",
);
}
const token = authHeader.slice(7);
try {
const payload = (await verify(token, JWT_SECRET)) as unknown as JWTPayload;
const user: AuthUser = {
id: payload.sub,
};
c.set("user", user);
await next();
} catch {
throw Errors.unauthorized("Invalid or expired token", "INVALID_TOKEN");
}
}
/**
* Helper function to get the authenticated user from context
* Throws if user is not authenticated
*/
export function getAuthUser(c: Context): AuthUser {
const user = c.get("user") as AuthUser | undefined;
if (!user) {
throw Errors.unauthorized("Not authenticated", "NOT_AUTHENTICATED");
}
return user;
}
|