Looking at the following express code, how can I create a token to feed Authorization?
If I comment on this code, the application runs fine.
app.use((req, res, next) => {
const token = req.get('Authorization')
if (token) {
req.token = token
next()
} else {
res.status(403).send({
error: 'Please provide an Authorization header'
})
}
})
Here is
app.get('/', (req, res) => {
fetch(url, { headers: { 'Authorization': 'The token I need to generatet' }})
The ideal approach would be to generate a token on /login and send it to client.
Using a package like jsonwebtoken
Example method to generate a token:
const jwt = require('jsonwebtoken');
function generateToken(userId){
const privateKey = "Some Strong Secret String";
const token = jwt.sign({ userId }, privateKey, function(err, token) {
console.log(token)
});
}
To verify if token is valid (inside the if{})
jwt.verify(token, privateKey, function(err, decoded) {
if (err) {
/*
err = {
name: 'TokenExpiredError',
message: 'jwt expired',
expiredAt: 1408621000
}
*/
}
});
Related
I am a beginner with node js. I want to make an authentication server using jwt (jsonwebtoken).
The problem is when I test my end point "/api/posts?authorisation=Bearer token..." in postman with method POST with the right token, it gives me forbidden.
Here is my code:
const express = require('express')
const jwt = require('jsonwebtoken')
const app = express()
app.get("/api", (req, res) => {
res.json({
message: "Hey there!!!"
})
})
app.post('/api/posts', verifyToken, (req, res) => {
jwt.verify(req.token, "secretkey", (err, authData) => {
if (err) {
res.sendStatus(403) //forbidden
res.send(`<h2>${err}</h2>`)
} else {
res.json({
message: "Post Created...",
authData
})
}
})
})
app.post('/api/login', (req, res) => {
const user = {
id: 1,
username: "John",
email: "john#gmail.com"
}
jwt.sign({ user: user }, "secretkey", (err, token) => {
res.json({
token
})
})
})
function verifyToken(req, res, next) {
const bearerHeader = req.headers["authorization"]
if (typeof bearerHeader !== "undefined") {
const bearerToken = bearerHeader.split(" ")[1]
req.token = bearerToken
next()
} else {
res.sendStatus(403) //forbidden
}
}
app.listen(5000, () => {
console.log("Server is running :)")
})
I expected it to work because I brought it from a tutorial.
Your code works
The problem is in your request invocation:
According to the oauth2 spec, the Authorization token should be a header and your code expect that
So the token should be sent as http header, not as a query param like foo/bar?authorization=Bearer token...".
Here some samples
Postman
Axios (javascript)
let webApiUrl = 'example.com/getStuff';
let tokenStr = 'xxyyzz';
axios.get(webApiUrl,
{ headers: { "Authorization": `Bearer ${tokenStr}` } });
Advice
Read about oauth2 and jwt
Perform the token validation in the middleware to avoid the validation on each route
Have a problem when trying to verify the token (it was working fine before i added some data to it before generating it) .. but now it does not seem to be working !
This is how i generate the token when user send a POST request (login)
require('dotenv')
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs')
const Role = require('../models/Role');
const Section = require('../models/Section');
const User = require('../models/User');
// Login !
router.post('/', async (req, res) => {
let sections_fetched = [];
// Validate data
// Check username
const user = await User.findOne({username: req.body.username });
if(!user) return res.status(400).send('Wrong user login credentials !');
// Check password
const is_pass_valid = await bcrypt.compare(req.body.password , user.password);
if (!is_pass_valid) return res.status(400).send('Wrong user login credentials !');
// Get role Object:
const _role = await Role.findOne({_id:user.role , is_deleted:false});
if (!_role) res.json("Failed fetching role !");
// loop through sections
for (let index = 0; index < _role.sections.length; index++) {
const tmpRole = await Section.find({_id: _role.sections[index], is_deleted:false});
sections_fetched.push({access:tmpRole[0].access , name:tmpRole[0].name});
}
// create jwt token
const token = jwt.sign({username:user.username, role:{name:_role.name, sections:sections_fetched}}, 'secret', {expiresIn : '24h'}, process.env.JWT_TOKEN_SECRET);
res.json({token:token});
});
this is my JWT verification middleare :
require('dotenv')
const jwt = require('jsonwebtoken');
module.exports = function (req, res, next) {
const token = req.header('auth-token');
if (!token) return res.status(401).send('Access Denied !');
console.log(process.env.JWT_TOKEN_SECRET);
console.log(token);
try
{
const verified = jwt.verify(token, process.env.JWT_TOKEN_SECRET);
req.user = verified;
next();
}
catch (error)
{
res.status(400).send('Invalid token !');
}
}
and this is a simple example of listing users (using the JWT verification middleware ! ) :
const verifyToken = require('../middlewares/verifyToken'); // my jwt middleware to verify !
// Listing All users
router.get('/', verifyToken, async (req, res) =>
{
try
{
const users = await User.find({is_deleted:false});
res.json(users);
}
catch (error)
{
console.log("err ->\n"+error);
res.json({message: error});
}
});
what is 'secret in the below line? seems you are adding a secret key twice, replace the hardcoded word 'secret' with token from env
const token = jwt.sign({username:user.username, role:{name:_role.name, sections:sections_fetched}}, 'secret', {expiresIn : '24h'}, process.env.JWT_TOKEN_SECRET);
send a bearer token and your middleware should like this
require('dotenv')
const jwt = require('jsonwebtoken');
module.exports = (req, res, next) => {
try {
const token = req.headers.authorization.split(' ')[1]; // Authorization: 'Bearer TOKEN'
if (!token) {
throw new Error('Authentication failed!');
}
const verified = jwt.verify(token, process.env.JWT_TOKEN_SECRET);
req.user = verified;
next();
} catch (err) {
res.status(400).send('Invalid token !');
}
};
Please make sure then when generating the token you pass a valid algorithm. I stored the algorithm in an environment variable but used none which is not a valid algorithm. Thus even though the token got created, I couldn't verify it using the same secret. Spent hours trying to fix this. I hope this was helpful :D
sign(payload, JWT_SECRET, {
algorithm: JWT_ALGORITHM,
expiresIn: '1d'
});
You described that you have changed the contents.
A signature represents the integrity of the contents, to ensure the content that was signed has not been modified, and you are modifying the contents making the signature invalid. This error you have is accurate for what you have done.
You must create a new signature when the signed contents are changed.
For Sign:
jwt.sign(
{
username:user.username,
role:{
name: _role.name,
sections: sections_fetched
}
}, 'secret', {
expiresIn : '24h'
}, process.env.JWT_TOKEN_SECRET,
function(err,res) {
if (err) {
callback(res);
} else {
callback(res);
}
}
);
To Verify:
jwt.verify(req,'SecretKey', function (err, res) {
if (err) {
callback(res);
} else {
callback(res);
}
});
Hlo
this error occur when secretkey does't match with the key thats provided during when you verifing token
you can check you token on jwt website thats help you to get error main reason
How is the best way to create a token auth in nodejs for access to api by front-end application?
If you have to create a authentication token you can refer JWT-Token:
Token Creation:
const token = jwt.sign({username},'my_secret_key',{ expiresIn: 60*60*24 });
res.json({
"success":true,
"data":data,
"token":token
});
Token verification:
const jwt = require('jsonwebtoken');
module.exports = function checkToken(req, res, next) {
var token = req.headers['token'];
if(token) {
jwt.verify(token, 'my_secret_key',(err,decode)=>{
if(err) {
res.json({"status":500,
"message":"INVALID TOKEN",
"error":err.message
});
} else {
next();
}
})
} else {
res.json({"status":500,
"message":"NO TOKEN PROVIDE",
"error":"token must be provide in header for endpoint access"
});
}
}
You can refer link here
I am using JWT-simple for authenticating my express routes.
server side:
var jwt = require('jwt-simple');
var bcrypt = require('bcrypt');
var passport = require('passport');
require('../passport')(passport);
/* Create an Account */
router.post('/signup', function (req, res, next) {
var verifyCode = Math.random().toString(36).slice(-8);
var userData = {
name: req.body.name,
email: req.body.email,
phone: req.body.contact,
password: req.body.password,
verify_code: verifyCode,
status: 0
};
loginService.createUser(userData, function (err, data) {
if (err) {
res.status(500).json({error: true, data: {message: err.message}});
} else {
var token = jwt.encode(data, "secret");
res.json({success: true, data: {token: 'JWT ' + token}});
}
});
});
/* GET the info of an API using the jwt token data */
router.get('/info', passport.authenticate('jwt', {session: false}), function (req, res, next) {
var token = tokenRetrive.getToken(req.headers);
if (token) {
var decoded = jwt.decode(token, configVar.config.secret);
UserService.getContentUserById(decoded.id, function (err, user) {
if (err) {
res.status(500).json({error: true, data: {message: err.message}});
} else {
if (!user) {
res.send({success: false, msg: 'Authentication failed. User not found.'});
} else {
if (!user) {
return res.status(403).send({success: false, msg: 'Authentication failed. User not found.'});
} else {
res.json({success: true, data: user.toJSON()});
}
}
}
});
} else {
return res.status(403).send({success: false, msg: 'No token provided.'});
}
});
client side
var signup = function(user) {
return $q(function(resolve, reject) {
$http.post(API_ENDPOINT.url + '/signup', user).then(function(result) {
if (result.data.success) {
storeUserCredentials(result.data.data.token);
resolve(result.data);
} else {
reject(result.data.msg);
}
});
});
};
function storeUserCredentials(token) {
window.localStorage.setItem(TOKEN_KEY, token);
var loggedIn_user_Data = jwt_decode(token);
$http.defaults.headers.common.Authorization = token;
}
Using REST client (POSTMAN) when I pass the header info to the API I use
API : localhost:8080/info
Key
Authorization
Content-Type
Value
JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiYXR1bCIsImVtYWlsIjoidHJlZUB0cmVlLmNvbSIsInBob25lIjpudWxsLCJwYXNzZHJlc3MiOm51bGwsImNvdW50cnkiOm51bGwsInN0YXRlIjpudWxsLCJwaW5jb2RlIjpudWxsLCJvcmdfaWQiOjAsInJvbGVzIjpudWxsLCJjcmVhdGVfZGF0ZSI6IjIwMTctMDUtMThUMTk6NTE6MDYuMDAwWiIsImxhc3RfbG9naW4iOiIyMDE3LTA1LTE4VDE5OjUxOjA2LjAwMFoiLCJhdmF0YXJfdXJsIjpudWxsfQ.umxBRd2sazaADSDOW0e8rO5mKDpQYIK1hsaQMZriZFE
application/json
The above API gives me the data only if the correct token is passed and seems working fine.
However in client side I can get the token retrieve using jwt-decode, without the use of any secret in client side, what if the token is caught by middle man, How can the security be enhanced?
Is there something I am missing to have correct use of JWT for my node api routes?
Some places I see the Authorisation is passed as bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiYXR1bCIsImVtYWlsIjoidHJlZUB0cmVlLmNvbSIsInBob25lIjpudWxsLCJwYXNzd29yZCI6IiQyYSQxMCRIQVJPTy5PUEdYWFBvVktXOVhmYnZldk
When I try to use bearer I get error to get the info after authenticating.
What is this bearer and JWT being passed in value to header?
I am using passport-jwt
var JwtStrategy = require('passport-jwt').Strategy;
To use JWT tokens, you have to use SSL (https). Without it, you won't have protection at all.
JWT tokens are signed (check the site). So if someone (middle man) try to change it, it will be invalidated.
JWT and Bearer are basic the same thing. They are just the auth scheme for the authorization header.
The 'JWT' auth scheme is the default of the passport-jwt.
If you want to change it, you can use a different jwtFromRequest value.
See:
new Strategy({ ... jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme('Bearer') ... }, verifyFunction)
Hope its clear.
strong textI am building node.js + mongodb rest api. I use jwt user auth and I have a problem. I need to get details of authenticated user (user_id, name), think they can be obtained from token, but I dont know how to do this. How is it possible to do ?
UPDATED
I am doing a post request
router.route('/articles')
.post(function (req, res) {
var article= new Article();
article.user_id = ???; // here needs user_id
article.imdb_id = req.body.imdb_id;
article.title = req.body.title;
article.thumb = req.body.thumb;
article.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Added' });
});
});
I need to insert into articles collection authors id (user_id), but I dont know how to get the authenticated user_id.
Tried to do this:
var token = req.body.token || req.query.token || req.headers['x-access-token'];
if (token) {
jwt.verify(token, app.get('superSecret'), function(err, decoded) {
if (err) {
return res.json({ success: false, message: 'Failed to authenticate token.' });
} else {
req.decoded = decoded;
console.log(decoded);
next();
}
});
decoded returns all info about user (name, password, _id). Is it possible to get only user_id and name from here?
When you sign a JSON web token you can pass it a user object. Here you can store whatever user data you need. This object is then signed and encoded and set as the token. When you send a request to your API passing the JWT in the auth header your validation function should return this user object back to you if the JWT is valid.
I like to use the Hapi framework for creating my Restful APIs so I will give an example using Hapi.
In your server.js file you need to register the hapi-auth-jwt2 package:
server.register(require('hapi-auth-jwt2'), (err) => {
if (err) {
throw err;
}
server.auth.strategy('jwt', 'jwt', {
key: config.jwt.secret,
validateFunc: auth.validate,
verifyOptions: { algorithms: ['HS256'] }
});
server.auth.default('jwt');
});
Your validation function:
export default {
validate: (tokenObject, req, callback) => {
validateToken(tokenObject.user_id, (err, user) => {
if (err) {
callback(Boom.unauthorized('User is unauthorized.'), false);
} else {
req.user = user;
callback(null, true);
}
});
}
};
The validateToken function should take the user id that you got from the token and query for the user. If a user is found then you know the token is valid and you can return and store the rest of the user information.
To create a token I use "jsonwebtoken" package:
generateToken: (user_id, name, callback) => {
'use strict';
callback(null, JWT.sign({
user_id: user_id,
name: name
}, config.JWT.SECRET, {
expiresIn: 86400
}));
}
Let's say you need to verify if the token sent from user In the headers already In your Database or not (we're going to call it protect)
const {promisify} = require('util');
const jwt = require('jsonwebtoken');
const User = require('./../models/userModel');
...
exports.protect = catchAsync(async(req, res, next) => {
// 1) Getting token and check if it's there in headers
let token;
//authorization is the name of the header token
if (req.headers.authorization) {
token = req.headers.authorization;
}
if (!token) {
return next(new AppError('You are not logged in! Please Login To get Access.', 401));
}
// 2) Verification Token is a valid token
const decoded = await promisify(jwt.verify)(token, process.env.JWT_SECRET);
// WE CAN GET THE USER ID FROM DECODED
// 3) Check if user still exists not deleted
const currentUser = await User.findById(decoded.id);
if (!currentUser) {
return next(new AppError('the user does not exist.', 401));
}else{
// WHAT EVER YOU WANT TO DO AFTER CHECKING USER FOUND IN DATABASE
})