Skip to content

Commit c0facde

Browse files
committed
feat(security): add HMAC-SHA256 based API key generation and verification
1 parent 9d528bc commit c0facde

3 files changed

Lines changed: 38 additions & 4 deletions

File tree

backend/middleware/verifyApiKey.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
const Project = require('../models/Project');
2+
const { hashApiKey } = require('../utils/api');
23

34
module.exports = async (req, res, next) => {
45
try {
56
const apiKey = req.header('x-api-key');
67

78
if (!apiKey) return res.status(401).json({ error: 'API key not found' });
89

9-
const project = await Project.findOne({ apiKey })
10+
const hashedApi = hashApiKey(apiKey);
11+
12+
13+
const project = await Project.findOne({ apiKey: hashedApi })
1014
.populate('owner', 'isVerified');
1115
if (!project) return res.status(401).json({ error: 'Invalid API key' });
1216

backend/routes/projects.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const { z } = require('zod');
88
const authMiddleware = require('../middleware/authMiddleware');
99
const verifyEmail = require('../middleware/verifyEmail')
1010
const { v4: uuidv4 } = require('uuid');
11+
const { generateApiKey, hashApiKey } = require('../utils/api');
1112
const multer = require('multer');
1213
const { createClient } = require('@supabase/supabase-js');
1314

@@ -43,19 +44,25 @@ router.post('/', authMiddleware, verifyEmail, async (req, res) => {
4344
// Validation Applied
4445
const { name, description } = createProjectSchema.parse(req.body);
4546

47+
const rawApiKey = generateApiKey()
48+
const hashedkey = hashApiKey(rawApiKey);
49+
50+
const rawSecret = generateApiKey()
51+
4652
const newProject = new Project({
4753
name,
4854
description,
4955
owner: req.user._id,
50-
apiKey: uuidv4(),
51-
jwtSecret: uuidv4()
56+
apiKey: hashedkey,
57+
jwtSecret: rawSecret
5258
});
5359
await newProject.save();
5460

5561
const projectObj = newProject.toObject();
62+
projectObj.apiKey = rawApiKey;
5663
delete projectObj.jwtSecret;
5764

58-
res.status(201).json(projectObj); // Fixed: .json()
65+
res.status(201).json(projectObj);
5966
} catch (err) {
6067
if (err instanceof z.ZodError) return res.status(400).json({ error: err.errors });
6168
res.status(500).json({ error: err.message }); // Fixed: .json()

backend/utils/api.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const crypto = require('crypto');
2+
3+
function generateApiKey() {
4+
5+
// OS level cryptographic randomnesss
6+
const bytes = crypto.randomBytes(32)
7+
// console.log(bytes);
8+
9+
const key = bytes.toString("base64url");
10+
// console.log(key)
11+
12+
return `ub_key_${key}`
13+
14+
}
15+
16+
function hashApiKey(apikey) {
17+
return crypto
18+
.createHmac("sha256", "ikewdxnuuencwoi")
19+
.update(apikey)
20+
.digest("hex");
21+
}
22+
23+
module.exports = { generateApiKey, hashApiKey }

0 commit comments

Comments
 (0)