Skip to content

Instantly share code, notes, and snippets.

@AvinashSKaranth
Last active October 6, 2022 07:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AvinashSKaranth/55297f02ef4ae1a3d696868b528e4d4f to your computer and use it in GitHub Desktop.
Save AvinashSKaranth/55297f02ef4ae1a3d696868b528e4d4f to your computer and use it in GitHub Desktop.
JWT Security for Offline Token Generation and Validation
// Client side Offline Token Generation
require("dotenv").config();
const http = require("http");
const jwt = require("jsonwebtoken");
const token = jwt.sign({ method: "send" }, process.env.CLIENT_SECRET, {
algorithm: "HS256",
header: { typ: "JWT", kid: process.env.CLIENT_ID },
});
const postData = JSON.stringify({
somedata: "123",
});
const options = {
hostname: "localhost",
port: process.env.PORT,
path: "/path/to/api",
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": postData.length,
Authorization: "Bearer " + token,
},
};
const req = http.request(options, (res) => {
console.log("statusCode:", res.statusCode);
console.log("headers:", res.headers);
res.on("data", (d) => {
process.stdout.write(d);
});
});
req.on("error", (e) => {
console.error(e);
});
req.write(postData);
req.end();
// Load all CLIENT_ID and CLIENT_SECRET to a inMemory hash
// Move require("./client.json"); to a API call to support dynamically created
// You can repl
let credentials = {};
if (fs.existsSync("./client.json")) {
credentials = require("./client.json");
} else {
const CLIENT_ID = process.env.CLIENT_ID || "";
const CLIENT_SECRET = process.env.CLIENT_SECRET || "";
if (CLIENT_ID !== "" && CLIENT_SECRET !== "") {
credentials[CLIENT_ID] = CLIENT_SECRET;
}
}
// Middleware for Validation of offline Token
// You can add object to request object in the middleware (Example: req.client = getClientDetails("kid"))
app.use(authorizeJWT);
const authorizeJWT = function (req, res, next) {
if (!req.headers.hasOwnProperty("authorization")) {
res.status(401).send({ message: "Authorization Bearer Token is required" });
}
if (!req.headers.authorization.startsWith("Bearer ")) {
res.status(401).send({ message: "Authorization Bearer Token is required" });
}
let token = req.headers.authorization
.toString()
.replace("Bearer ", "")
.trim();
let kid = "";
try {
kid = JSON.parse(Buffer.from(token.toString().split(".")[0], "base64"))[
"kid"
];
} catch (err) {
res
.status(401)
.send({ message: "kid must be passed in the JsonWebToken header" });
}
jwt.verify(token, credentials[kid], function (err, decoded) {
if (err || decoded === undefined) {
res.status(401).send({ message: "Unauthorized" });
} else {
try {
if (Math.abs(decoded.iat - new Date().getTime() / 1000) < 300) {
next();
} else {
res.status(401).send({ message: "Token Expired" });
}
} catch (_err) {
res.status(401).send({ message: "Invalid Token" });
}
}
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment