API Authentication with JWT gives WebTokenError always - javascript

I've been learning about JWT and I face this problem in which the response gives as JsonWebTokenError. The token generation works fine. But the verification of the token give me an error stating that "JsonWebTokenError" with a message "invalid signature". Here's my code
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();
app.get('/api', (request, response) => {
response.json({
message: 'This is an Authentication API'
})
})
app.post('/api/posts', verifyToken, (request, response) => {
jwt.verify(request.token, 'secretkey', (err, authData) => {
if(err){
response.json({err});
}
else{
response.json({
message: 'Post was created successfully',
authData
})
}
})
})
app.post('/api/login', (request, response) => {
const user = {
id: 1,
user: 'sarath',
email: 'sarathsekaran#gmail.com'
}
jwt.sign({user}, 'secretKey', (err, token) => {
response.json({
token
});
});
});
//VerifyToken
//Authori FORMAT: Bearer <token>
function verifyToken(request, response, next){
//Get auth header value
const bearerHeader = request.headers['authorization'];
//Checking if bearer is undefined
if(typeof bearerHeader !== 'undefined'){
//Spilt the token from Bearer
const bearer = bearerHeader.split(' ');
const bearerToken = bearer[1];
//Set the token
request.token = bearerToken;
//Next Middleware
next();
}
else{
//Forbidden
response.sendStatus(403);
}
}
app.listen(5000, ()=>console.log('Server Started'));

While creating a jwt token you should use a unique secret key and should store that unique somewhere else and not directly into the code. You are facing this error because your secret key is having a lowercase of "k" at one place and uppercase at the other.

Related

Failed to load resource: the server responded with a status of 401 (Unauthorized) in REACT and NODE.js

This is REACT js client side code
in console error is this 1.Failed to load resource: the server responded with a status of 401 (Unauthorized) 2. Uncaught TypeError: inventories.map is not a function
useEffect(() => {
setDataLoading(true);
const url = `http://localhost:5000/inventoryByEmail?email=${user.email}`;
fetch(url, {
headers: {
authorization: `Bearer ${localStorage.getItem("access-token")}`,
},
})
.then((res) => res.json())
.then((data) => {
setInventories(data);
setDataLoading(false);
});
}, [user]);
This is Server site Nodejs code
function verifyJWT(req, res, next) {
const authHeader = req.header.authorization;
if (!authHeader) {
return res.status(401).send({ message: "unauthorized access" });
}
const token = authHeader.split(" ")[1];
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, decoded) => {
if (err) {
return res.status(403).send({ message: "Forbidden access" });
}
req.decoded = decoded;
next();
});
}
and this is api Route
app.get("/inventoryByEmail", verifyJWT, async (req, res) => {
const decodedEmail = req.decoded.email;
const email = req.query.email;
if (email === decodedEmail) {
const query = { email: email };
const cursor = inventoryCollection.find(query);
const result = await cursor.toArray();
res.send(result);
} else {
res.status(403).send({ message: "forbidden access" });
}
});
How to slove this issue? thanks so much for your time!
in your function verifyJWT it's : req.headers.authorization; or if you want to get the token : req.headers.authorization.split(' ')[1];

How do I transfer a jwt token from local storage on the web browser to the server backend?

I am currently designing a simple website, where users can log in as a normal user or as an admin. Right now I am coding out the portion for when the user wants to go to an admin only web page, and the server will retrieve the jwt token stored in the local storage on the web browser to validate it.
This is what the local storage looks like
Here is the code for retrieving the jwt token
var verifyFn = {
verifyToken: function (req, res, next) {
const authHeader = localStorage.getItem("jwt_token");
console.log("THIS IS THE HEADER")
console.log(authHeader)
if (authHeader === null || authHeader === undefined ){
return res.status(401).send({ message: 'not authenticated BEARER TOKEN ISSUE' });
}
const token = authHeader
console.log("NEW TOKEN")
console.log(token)
jwt.verify(token, config.jwt.secret, { algorithms: ['HS256'] }, (err, decoded) => {
if (err) return res.status(401).send({ message: 'not authenticated' });
req.decodedToken = decoded;
console.log("DECODED TOKEN: " + req.decodedToken)
next();
});
}
However, whenever I try to run the server and browse to the admin page, there will be an error saying 'localstorage is not defined'. As such, I am not sure about how I can retrieve the jwt_token from the web browser to the server back end.
A server has no access to the browser's localStorage object, as it is accessible from the client only, and does not exist in the server context.
What is usually done is sending the token in an Authorization header. It looks like you are using Node, so consider the following example request using the fetch API on the client:
const jwtToken = localStorage.getItem('jwt_token')
fetch('your-api-url', {
method: 'request method here',
headers: {
Authorization: `Bearer ${jwtToken}`
},
body: JSON.stringify(your request body here)
}).then(response => ...)
In the server, you can then get the JWT token by looking at the request headers, something like this:
var verifyFn = {
verifyToken: function (req, res, next) {
let authHeader = req.headers['Authorization']
// the auth header will have Bearer prepended, so remove it
authHeader = authHeader.replace('Bearer ', '')
console.log("THIS IS THE HEADER")
console.log(authHeader)
if (authHeader === null || authHeader === undefined ){
return res.status(401).send({ message: 'not authenticated BEARER TOKEN ISSUE' });
}
const token = authHeader
console.log("NEW TOKEN")
console.log(token)
jwt.verify(token, config.jwt.secret, { algorithms: ['HS256'] }, (err, decoded) => {
if (err) return res.status(401).send({ message: 'not authenticated' });
req.decodedToken = decoded;
console.log("DECODED TOKEN: " + req.decodedToken)
next();
});
}

Authorizarion on json-server with a JWT

I am trying to make a node app which is using typicode json-server, I want to add authorization to the app, where GET request is open to all public, but PUT, POST & DELETE request require a JWT token and only then they can proceed on the api.
I have tried to make a small app, but I am not able to figure out the next part of authorization and how to use middlewares on node, as I am a frontend developer.
Here is the app that I have written.
const jsonServer = require('json-server')
const app = jsonServer.create()
const router = jsonServer.router('db.json')
const middlewares = jsonServer.defaults()
const morgan = require('morgan');
const jwt = require('jsonwebtoken');
const config = require('./config');
const bodyParser = require('body-parser');
app.set('Secret', config.secret);
app.use(morgan('dev'));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(middlewares)
app.use((req, res, next) => {
if (req.method === 'GET') {
console.log(req);
next();
} else {
if (req.path === '/login') {
getToken(req, res);
}
if (isAuthorized(req, res)) {
console.log("I am here");
next();
} else {
console.log("I am in error");
res.sendStatus(401)
}
}
})
app.use(router)
app.listen(3000, () => {
console.log('JSON Server is running on 3000')
})
function isAuthorized(req, res) {
console.log("sadasdasdasd");
var token = req.headers['access-token'];
console.log(token);
// decode token
if (token) {
console.log("Inside token");
jwt.verify(token, app.get('Secret'), (err, decoded) => {
console.log("Inside JWT fn");
if (err) {
console.log("Inside JWT fn err");
return res.json({ message: 'invalid token' });
} else {
console.log("Inside JWT fn success");
req.decoded = decoded;
return true;
}
});
} else {
// if there is no token
res.send({
message: 'No token provided.'
});
}
}
function getToken(req, res) {
if (req.body.username === "test") {
if (req.body.password === 123) {
const payload = {
check: true
};
var token = jwt.sign(payload, app.get('Secret'), {
expiresIn: 1440 // expires in 24 hours
});
res.json({
message: 'Authentication Successful ',
token: token
});
} else {
res.json({
error: 'Invalid Password',
});
}
} else {
res.json({
error: 'Please provide valid credentials',
});
}
}
You are doing in right way. But, have some issue in your isAuthorized middleware. In the middleware you have a asynchronous action (jwt.verify), then you can not use this function as a "helper function" as the official document of json-server (the function return boolean value).
Make isAuthorized become a middleware and you it like a middleware:
function isAuthorized(req, res, next) { // Pass 3 parmas to a express middleware
console.log("sadasdasdasd");
var token = req.headers['access-token'];
console.log(token);
// decode token
if (token) {
console.log("Inside token");
jwt.verify(token, app.get('Secret'), (err, decoded) => {
console.log("Inside JWT fn");
if (err) {
console.log("Inside JWT fn err");
return res
.status(401) // I think will be better if you throw http status is 401 to client
.json({ message: 'invalid token' });
} else {
console.log("Inside JWT fn success");
req.decoded = decoded;
return next(); // Only call "next" if everything is good, continue next jobs - handle secured requests
}
});
} else {
// if there is no token
return res
.status(401)
.send({
message: 'No token provided.'
});
}
}
Use the middleware
app.use((req, res, next) => {
if (req.method === 'GET') {
console.log(req);
next();
} else {
if (req.path === '/login') {
getToken(req, res);
}
isAuthorized(req, res, next); // Here
}
})

jwt tokens not working correctly after login (Advice needed on logic of code)

Hi I have been struggling significantly with making a login using react front end, npm express, npm mssql and npm jsonwebtokens.
I understand the logic behind this but cannot implement properly into my application. I have included the code in which I am getting stuck on and which is causing the issues.
This is my login route within my server.js (main npm packages used are mssql, express, jsonwebtokens,bodyparser)
This route is used when the logging form is submit (front end not important within this question).
This then checks if the database contains that email and password. If it does it prompts user "login successful" if not it prompts user "bad creds". If login is successful it assign a jwt token to it.
app.post("/login", async (req, response) => {
try {
await sql.connect(config);
var request = new sql.Request();
var Email = req.body.email;
var Password = req.body.password;
console.log({ Email, Password });
request.input("Email", sql.VarChar, Email);
request.input("Password", sql.VarChar, Password);
var queryString =
"SELECT * FROM TestLogin WHERE email = #Email AND password = #Password";
//"SELECT * FROM RegisteredUsers WHERE email = #Email AND Password = HASHBYTES('SHA2_512', #Password + 'skrrt')";
const result = await request.query(queryString);
if (result.recordsets[0].length > 0) {
console.info("/login: login successful..");
console.log(req.body);
jwt.sign({ Email }, "secretkey", { expiresIn: "30m" }, (err, token) =>
res.cookie("auth", token).json({ token })
);
} else {
console.info("/login: bad creds");
response.status(400).send("Incorrect email and/or Password!");
}
} catch (err) {
console.log("Err: ", err);
response.status(500).send("Check api console.log for the error");
}
});
// Verify Token
function verifyToken(req, res, next) {
// Get auth header value
const bearerHeader = req.headers["authorization"];
// Check if bearer is undefined
if (typeof bearerHeader !== "undefined") {
// Split at the space
const bearer = bearerHeader.split(" ");
// Get token from array
const bearerToken = bearer[1];
// verify the token and store it
jwt.verify(bearerToken, "secret", function(err, decodedToken) {
if (err) {
console.info("token did not work");
return res.status(403).send("Error");
}
// Set the token
req.token = bearerToken;
req.decodedToken = decodedToken;
next();
});
} else {
// Forbidden
res.sendStatus(403);
}
}
I then have a token verify method.
This is supposed to check the token and then if it is legit will store it. However when using route user-questions(will show in next block of code) it always throws the 403 error.
// Verify Token
function verifyToken(req, res, next) {
// Get auth header value
const bearerHeader = req.headers["authorization"];
// Check if bearer is undefined
if (typeof bearerHeader !== "undefined") {
// Split at the space
const bearer = bearerHeader.split(" ");
// Get token from array
const bearerToken = bearer[1];
// verify the token and store it
jwt.verify(bearerToken, "secret", function(err, decodedToken) {
if (err) {
console.info("token did not work");
return res.status(403).send("Error");
}
// Set the token
req.token = bearerToken;
req.decodedToken = decodedToken;
next();
});
} else {
// Forbidden
res.sendStatus(403);
}
}
This is the user question route in which on the first line I am trying to call the verify Token method when this fetch is called however it always throws the 403 error.
app.get("/user-questions", verifyToken, function(req, res) {
// if a request has made it to this point, then we know they have a valid token
// and that token is available through either req.token (encoded)
// or req.decodedToken
sql.connect(config, function(err) {
if (err) console.log(err);
// create Request object
var request = new sql.Request();
// query to the database and get the records
request.execute("dbo.ViewQuestions", function(err, recordset) {
if (err) console.log(err);
// send records as a response
res.json(recordset);
});
});
});

How to write middleware for graphql which will be call before every resolver

In every request I send token, and check it in express middleware
app.use(async (req, res, next) => {
const authorization = req.headers.authorization;
let token = null;
let user;
if (authorization) {
try {
token = jwt.verify(authorization, config.secret);
} catch (e) {
// dont work
throw new GraphQLError({ message: 'token damaged' });
}
if (token) {
const { _id } = token;
user = await User.findOne({ _id });
}
if (user) {
req.user = user;
}
}
next();
});
Token can be damaged, and I do the check:
try {
token = jwt.verify(authorization, config.secret);
} catch (e) {
throw new GraphQLError({ message: 'token damaged' });
}
So I need to send to client application Express Error, but it dont work, as expected,
are there any options to create graphql middlewares which take request arguments before calling every resolver? Now if I want throw error of damaged token I need write check in every resolver?
You can simply respond and return, without calling the next middleware:
try {
token = jwt.verify(authorization, config.secret);
} catch (e) {
res.statusCode = 401;
return res.end('{"errors": [{"message": "token damaged"}]}');
}

Categories

Resources