import {Hono, type MiddlewareHandler} from "hono"; import {basicAuth} from "hono/basic-auth"; import {sign, verify} from "jsonwebtoken"; const JWT_SECRET = "your-secret-key"; const EXPIRATION_TIME = "1h"; // Token expires in 1 minute const REFRESH_THRESHOLD = 30; // Refresh token if it has less than 30 seconds left const ACCESS_EXPIRATION = "1h"; // 1 minute for access tokens const REFRESH_EXPIRATION = "7d"; // 7 days for refresh tokens const fakeUsers = [ {id: 1, username: "admin", password: "password123"}, {id: 2, username: "user", password: "password123"}, {id: 3, username: "user2", password: "password123"}, ]; // Hardcoded user credentials (for demonstration purposes) const users = [{username: "admin", password: "password123"}]; // Middleware to check authentication export const lstVerifyAuth = basicAuth({ verifyUser: (username, password) => { const user = users.find((u) => u.username === username && u.password === password); return !!user; // Return true if user exists, otherwise false }, }); /** * Authenticate a user and return a JWT. */ export function login(username: string, password: string): {token: string; user: {id: number; username: string}} { const user = fakeUsers.find((u) => u.username === username && u.password === password); if (!user) { throw new Error("Invalid credentials"); } // Create a JWT const token = sign({userId: user?.id, username: user?.username}, JWT_SECRET, {expiresIn: EXPIRATION_TIME}); return {token, user: {id: user?.id, username: user.username}}; } /** * Verify a JWT and return the decoded payload. */ export function verifyToken(token: string): {userId: number} { try { const payload = verify(token, JWT_SECRET) as {userId: number}; return payload; } catch (err) { throw new Error("Invalid token"); } } export const authMiddleware: MiddlewareHandler = async (c, next) => { const authHeader = c.req.header("Authorization"); if (!authHeader || !authHeader.startsWith("Bearer ")) { return c.json({error: "Unauthorized"}, 401); } const token = authHeader.split(" ")[1]; try { const decoded = verify(token, JWT_SECRET, {ignoreExpiration: false}) as {userId: number; exp: number}; const currentTime = Math.floor(Date.now() / 1000); // Get current timestamp const timeLeft = decoded.exp - currentTime; // If the token has less than REFRESH_THRESHOLD seconds left, refresh it let newToken = null; if (timeLeft < REFRESH_THRESHOLD) { newToken = sign({userId: decoded.userId}, JWT_SECRET, {expiresIn: EXPIRATION_TIME}); c.res.headers.set("Authorization", `Bearer ${newToken}`); } c.set("user", {id: decoded.userId}); await next(); // If a new token was generated, send it in response headers if (newToken) { console.log("token was refreshed"); c.res.headers.set("X-Refreshed-Token", newToken); } } catch (err) { return c.json({error: "Invalid token"}, 401); } }; /** * Logout (clear the token). * This is a placeholder function since JWTs are stateless. * In a real app, you might want to implement token blacklisting. */ export function logout(): {message: string} { return {message: "Logout successful"}; }