Skip to content

Commit bfe2144

Browse files
committed
feat:Add JWT-based authentication middleware to protect APIs
1 parent b15403e commit bfe2144

File tree

10 files changed

+583
-9
lines changed

10 files changed

+583
-9
lines changed

backend/.env.example

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
# --- JWT Configuration ---
3+
# Secret key for signing access tokens. Should be a long, random string.
4+
JWT_SECRET=your_jwt_secret_key_here
5+
6+
# Secret key for signing refresh tokens. Should be a long, random string, different from JWT_SECRET.
7+
JWT_REFRESH_SECRET=your_jwt_refresh_secret_key_here
8+
9+
# Access token expiration time (e.g., 10m, 1h, 1d)
10+
ACCESS_TOKEN_EXPIRY=10m
11+
12+
# Refresh token expiration time (e.g., 7d, 30d)
13+
REFRESH_TOKEN_EXPIRY=7d
14+
15+
# --- Server Configuration ---
16+
# Port for the server to run on
17+
PORT=4000

backend/package-lock.json

Lines changed: 195 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/package.json

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,25 @@
1111
"author": "",
1212
"license": "MIT",
1313
"dependencies": {
14+
"bcryptjs": "^3.0.2",
1415
"body-parser": "^1.20.2",
16+
"cookie-parser": "^1.4.7",
1517
"cors": "^2.8.5",
16-
"dotenv": "^16.3.1",
17-
"express": "^4.18.2",
18+
"dotenv": "^16.6.1",
19+
"express": "^4.21.2",
20+
"jsonwebtoken": "^9.0.2",
1821
"morgan": "^1.10.0"
1922
},
2023
"devDependencies": {
24+
"@types/bcryptjs": "^2.4.6",
2125
"@types/body-parser": "^1.19.2",
26+
"@types/cookie-parser": "^1.4.9",
2227
"@types/cors": "^2.8.13",
23-
"@types/express": "^4.17.21",
28+
"@types/express": "^4.17.23",
29+
"@types/jsonwebtoken": "^9.0.10",
2430
"@types/morgan": "^1.9.7",
31+
"ts-node": "^10.9.2",
2532
"ts-node-dev": "^2.0.0",
26-
"typescript": "^5.2.2"
33+
"typescript": "^5.9.3"
2734
}
28-
}
35+
}

backend/src/controllers/auth.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import jwt, { SignOptions, JwtPayload } from "jsonwebtoken";
2+
import dotenv from "dotenv";
3+
dotenv.config();
4+
5+
if (!process.env.JWT_SECRET || !process.env.JWT_REFRESH_SECRET) {
6+
throw new Error("JWT secrets missing in environment variables");
7+
}
8+
9+
const accessSecret = process.env.JWT_SECRET as string;
10+
const refreshSecret = process.env.JWT_REFRESH_SECRET as string;
11+
12+
// Define your payload type
13+
export interface TokenPayload extends JwtPayload {
14+
sub: string;
15+
username?: string;
16+
role?: string;
17+
//role?:"user"|"admin"; // Example roles
18+
}
19+
20+
export function signAccessToken(payload: TokenPayload) {
21+
const options: SignOptions = { expiresIn: process.env.ACCESS_TOKEN_EXPIRY as any };
22+
23+
// --- CRITICAL FIX: Create a clean payload copy ---
24+
const cleanPayload = { ...payload };
25+
delete cleanPayload.iat; // Remove "Issued At" claim
26+
delete cleanPayload.exp; // Remove "Expiration" claim to allow options.expiresIn to work
27+
// --- END FIX ---
28+
29+
return jwt.sign(cleanPayload, accessSecret, options);
30+
}
31+
32+
export function signRefreshToken(payload: TokenPayload) {
33+
const options: SignOptions = { expiresIn: process.env.REFRESH_TOKEN_EXPIRY as any };
34+
35+
// --- CRITICAL FIX: Create a clean payload copy ---
36+
const cleanPayload = { ...payload };
37+
delete cleanPayload.iat; // Remove "Issued At" claim
38+
delete cleanPayload.exp; // Remove "Expiration" claim to allow options.expiresIn to work
39+
// --- END FIX ---
40+
41+
return jwt.sign(cleanPayload, refreshSecret, options);
42+
}
43+
44+
export function verifyAccessToken(token: string): TokenPayload {
45+
return jwt.verify(token, accessSecret) as TokenPayload;
46+
}
47+
48+
export function verifyRefreshToken(token: string): TokenPayload {
49+
return jwt.verify(token, refreshSecret) as TokenPayload;
50+
}

0 commit comments

Comments
 (0)