Trying to decode jwt token from server side - javascript

I have created a CLI with which I consume a data from a rest api I build with node.js and express.js. In the cli the user has to login and after that when he performs a query his data are passed as a header using jwt. This I have done with the following code:
The Login.ts file has this part of the code for the header creation:
await connection.query(`SELECT user,pass,email,quota,apikey,privileges FROM users WHERE user=?`,[`${flags.user}`], function (err, result, fields) {
if (err) throw err;
//console.log(`${flags.user}`);
//console.log(result[0].pass);
var u=result[0].user;
var p=result[0].pass;
var e=result[0].email;
var q=result[0].quota;
var a=result[0].apikey;
var p=result[0].privileges;
const password=result[0].pass;
if(bcrypt.compareSync(`${flags.passw}`, password)) {
var fs=require('fs');
var privateKey = fs.readFileSync('private.key');
var jwt=require('jsonwebtoken');
var token = jwt.sign({user:`${flags.user}`,passw:`${flags.passw}`,email: e, quota: q,apikey: a,privileges: p }, privateKey, { algorithm: 'RS256' });
fs.writeFileSync("temptoken.txt",token);
} else {
console.log("Wrong username or password\n");
}
});
After the login the user can perform various queries, where in their code they perform an
axios.get where I pass the header like this:
const axios = require('axios');
const {flags} = this.parse(ActualTotalLoadCommand);
var fs=require('fs');
var token = fs.readFileSync('temptoken.txt');
axios.defaults.headers.common['Authorization']=token;
From my server side file where I have the file entry.routes.js how can I capture the token and then decode it to test for example if the user who performed the query is a valid user?
The entry.routes.js looks like this:
module.exports = app => {
const entry = require("../controlers/entry.controller.js");
// Retrieve a single Entry with Id
var fs=require('fs');
var privateKey = fs.readFileSync('/home/vangelis/softeng/energy/private.key');
var jwt=require('express-jwt');
app.use(
jwt({
secret: privateKey,
credentialsRequired: false,
getToken: function fromHeaderOrQuerystring (req) {
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
return req.headers.authorization.split(' ')[1];
} else if (req.query && req.query.token) {
return req.query.token;
}
return null;
}
}));
app.get("/entry/:Id", entry.findOne);
app.get("/energy/api/ActualTotalLoad/:AreaName/:Resolution/date/:Year-:Month-:Day", entry.findTwo);
As you can see I tried using express-jwt, but I can't make it work.

In your code above you create the header with:
axios.defaults.headers.common['Authorization']=token;
which will result in
Authorization: <the token>
but in the code to read the header :
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer')
you expect a header like this:
Authorization: Bearer <the token>
which is the standard way. So you should add Bearer to the line to create the header.
Beside that, I see you're putting the (encrypted) password into the token. That's something you should avoid. There'sno good reason to do it. You have authenticated the user before you created the token and now, when you receive the token, you verify the authenticity of that token by it's signature.

Related

How do I make node.js using express find a JSON Web Token (JWT) inside of a response header cookie in user's browser?

I have a question on how to search for my JWT token inside of a user's browser cookies.
Below I have some code that searches the user's browser for cookies in the response header, but I am not sure how to make the code more specific and search for the JWT token within the cookie and verify that it is an actual JWT token that was a assigned to that user.
const jwt = require('jsonwebtoken');
const router = require('express')();
const cookieParser = require('cookie-parser');
router.use(cookieParser());
module.exports = function(req,res,next){
const token = req.header('Cookie');
if (!token) {
return res.status(403).send('Access Denied');
}
try{
const verified = req.header('Cookie');
req.user = verified;
// const verified = jwt.verify(token, process.env.TOKEN_SECRET);
// req.user = verified;
next();
} catch (err) {
res.clearHeader;
res.status(403).send('Invalid Token');
}
};
I hope I didn't misunderstand your question and waste a bunch time.
Short Answer: How to retrieve information
Use req.body or req.headers. If something will contain the token or authentication details, then it's one of these two.
Full Auth Walkthrough:
To get the JSON Web Tokens you first have to generate them. Wouldn't recommend implementing your own token authentication though. I'll show how to create a whole authentication system here step by step.
For simplicity, let's say we have an exported route in a file auth.js, this route will be a sub-route domain.com/auth, an array of all active refreshTokens and the jwt:
const express = require("express")
const jwt = require("jsonwebtoken")
let route = (exports.route = express())
let refreshTokens = []
What we will do is generate a long-lasting refresh token, which users will be able to use to generate a smaller 15-minute access token. Afterwards, you generate a new access token with the refresh token and so on. But to get the refresh token you need to login or register. Users can also logout killing the refresh token.
route.post("/token", async (req, res) => {
// Input: Refresh Token
// Output: Access Token Generation
})
route.post("/login", async (req, res) => {
// Input: User, Password
// Output: Refresh Token
})
route.delete("/logout", async (req, res) => {
// Input: Token to Remove
})
Let's start with the end. You have a refresh token, you won't to destroy it. Simply filter the array against this token and submit a status. The token becomes unusable after it's cleared from the array, that's the goal here.
route.delete("/logout", async (req, res) => {
refreshTokens = refreshTokens.filter((token) => token != req.body.token)
res.sendStatus(204)
})
With me so far? Now let's jump back to the start. If you log in with an email and password, if they're wrong respond with an error message, if they're correct receive the tokens.
route.post("/login", async (req, res) => {
const username = req.body.username
const password = req.body.password
// This is just a quick demonstration,
// you would have to use the bcrypt hash
// or other hash/salt methods. DO NOT
// STORE passwords plaintext
// Not existent user = Unauthorized
if (username != 'admin') return res.sendStatus(401)
// Wrong Password = Forbidden
if (password != 'abc123') return res.sendStatus(403)
const user = {
id: 0,
username: username,
password: password
}
const accessToken = generateAccessToken(user)
const refreshToken = generateRefreshToken(user)
let result = {
success: true,
accessToken: accessToken,
refreshToken: refreshToken,
}
res.send(result)
})
Now how do we sign the JSON web tokens? Let's take a look at the two methods used here:
function generateAccessToken(content) {
return jwt.sign(content, process.env.ACCESS_TOKEN_SECRET, {
expiresIn: "15m",
})
}
function generateRefreshToken(content) {
const token = jwt.sign(content, process.env.REFRESH_TOKEN_SECRET)
refreshTokens.push(token)
return token
}
Both use some sort of environment tokens, but why? That's the token you will have to generate once for the back end. It will be used as a public key. We simply generate the access tokens for 15 minutes and push the refresh tokens to the array.
route.post("/token", async (req, res) => {
const refreshToken = req.body.token
if (refreshToken == null) return res.sendStatus(401)
if (!refreshTokens.includes(refreshToken)) return res.sendStatus(403)
jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET, (err, user) => {
if (err) return res.sendStatus(403)
res.json({ accessToken:
generateAccessToken({
id: 0,
username: user.name,
password: user.password
})
})
})
})
We verify the refresh token, if it exists and it is valid, return a new access token for 15 minutes. That's it for the token part, you can login (create refresh token), retrieve an access token and logout (kill refresh token)
How to Use: Authenticate and Authorize
Admin pages should return 403 while the forum board should be different whether you're logging as a guest or an actual user. The first one is authentication, the second authorization.
Let's create two functions for each. Express is quite handy with the next() function
exports.authenticate = function (req, res, next) {
const authHeader = req.headers["authorization"]
const token = authHeader?.split(" ")[1]
jwt.verify(token || "", process.env.ACCESS_TOKEN_SECRET, (err, user) => {
req.user = err ? {} : user
next()
});
};
exports.authorize = function (req, res, next) {
const authHeader = req.headers["authorization"]
const token = authHeader?.split(" ")[1]
if (token == null)
return res.sendStatus(401)
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
if (err) return res.sendStatus(403)
req.user = user
next()
})
}
Now you're done with the whole authentication system (aside some cleanup's) and probably the registration system. Let's make use of it.
Client side you can create a REST api like so:
POST http://localhost:8081/auth/login
Content-Type: application/json
{
"username": "admin",
"password": "abc123"
}
# Returns refresh and access token.
###
DELETE http://localhost:8081/auth/logout
Content-Type: application/json
{
"token": "REFRESH_TOKEN"
}
# Logs out a user.
###
POST http://localhost:8081/auth/token
Content-Type: application/json
{
"token": "REFRESH_TOKEN"
}
#
# This is how you can provide the access token
# when making a request to say a forum api
#
GET http://localhost:8081/forum/api/board/0
Authorization: Bearer ACCESS_TOKEN
Usage:
route.get("forum/board/:id", authenticate, async (req, res) => {
res.send(req.user)
})
Expected Output when going to localhost:8081/forum/board/7 authenticated:
{id:0,username:"admin",password:"abc123"}
Otherwise:
{}
Nevertheless, do not try implementing your own authentication. Really, you shouldn't.
Source
https://www.youtube.com/watch?v=mbsmsi7l3r4

Authorization header value returns undefined in SuperTest

So I am writing tests using Mocha, Supertest and Chai. All my API's require an Authorization header which can be gotten from req.headers["authorization"]. This is the current setup of what my test looks like.
...
describe("Upload media files", () => {
it("uploads a file successfully", async () => {
const imagePath = path.join(__dirname, "../../fixtures/profile.jpeg");
const res = await app.post("/api/v1/account/upload") //app is global
.set("Authorization", "ey83hfjksksls...") //right here
.set("content-type", "multipart/form-data")
.attach("media", imagePath);
expect(res.status).to.eql(200);
expect(res.body.data).not.to.be.null;
expect(res.body.data).to.match(/https:/);
});
});
My tests always fail because a 401 is always returned for some reason that I do not know. Here's the function that handle's the decoding of the JWT
async function decodeToken() {
const sessionUser = req.session.userId;
const token = req.headers["authorization"] // token value is present here.
if (!token && !sessionUser) {
return res.status(401).json({
error: "Access denied, no valid credentials.",
});
}
if (token) {
const secret = sails.config.custom.jwtSecret || process.env.JWT_SECRET;
const decoded = jwt.verify(token, secret);
req.me = decoded;
return proceed();
}
const user = await User.findOne({
id: sessionUser,
});
req.me = user;
return proceed();
}
From the function above, when I do a console.log of the token variable, I do get a long string returned which shows that the token is being generated and passed into the .set('Authorization', 'eyeur9339..') header, but the test still fails. I don't know what to do anymore. Any help is appreciated, thank you.
if you use jwt for authorization, use Bearer before token so you should write Bearer, like this :
Bearer 5d5bd7f7e35a86541686f96c9cdd72ed67f5ba223811634e0319af224164823edc2d0090d1f6c2c3b1dec842ea783c71feb443ac2d26e
and for get token from header do like this :
const token = req.headers.authorization.split(' ')[1]
const decodedToken = jwt.verify(token, secret)

how to send jwt token to a middleware in a get request in express node.js

Js and web development I've tried searching the web crazy but I couldn't find a solution that could help me...
I have completed creating a project for a small lab...now I'm trying to create its login page and creating a web token using JWT...
I manage to successfully create a user and hash user password using bcrypt.... and successfully create an access token and refresh token....
I have also created a middleware that will authenticate the token
now I don't know how to send the token to that middleware
This is the authenticate token function
function authenticateToken(req, res, next)
{
try {
// header contains the token
// format
// Bearer Token
// inside autherization header
var authHeader = req.headers['authorization'];
var token = authHeader && authHeader.split(' ')[1]
if (token == null) {
// Meaning the user has not send a token.
// return res.sendStatus(401);
res.redirect('/login/');
}
// req.token = token;
// let headers = new Headers({ 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token });
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user)=>{
if (err) {
console.log("invalid token");
res.redirect('/login/');
return res.sendStatus(403);
// invalid token
}
req.user = user;
next();
});
} catch (error) {
return res.send(error.message);
}
}
I will not post all the data as its not relevant as it will populate the text area and will increase the difficulty level in understanding.... I will only share the part where I'm stuck.
this is the part where I check if the user exists and password is correct after successful authentication then I want to redirect to the dashboard page...or the main page
I cant send the access token to the route with the middleware of user authentication
router.post('/authenticate', (req,res,next)=>{
// console.log("Authenticate");
// console.log(req.body);
// console.log("Authenticate");
var email = req.body.email;
var password = req.body.password;
var sqlQuery = "select * from user where email = '"+email+"' and display = 'yes' ;;";
try {
con.query(sqlQuery,(error,result)=>{
if (!error) {
// console.log(result);
var oriPassword = result[0].PASSWORD;
var user =
{
id : result[0].ID,
name : result[0].LASTNAME,
mobileNo : result[0].MOBILENO,
};
bcrypt.compare(password, oriPassword,(err,res)=>{
if (!err) {
var accessToken = generateAccessToken(user);
var refreshToken = jwt.sign(user, process.env.REFRESH_TOKEN_SCRET);
sqlQuery = "update user set AccessToken = '"+accessToken+"' ,refreshtoken =
'"+refreshToken+"' where id = "+user.id+";";
con.query(sqlQuery,(error,result)=>{
if (!error) {
console.log("RefreshToken Inserted.");
console.log({accessToken:accessToken, refreshToken:refreshToken});
req.headers.authorization = accessToken;
} else {
console.log(error.message);
}
});
}
else {
}
});
console.log("redirecting to login user");
// console.log("Response Header");
// console.log(res.header.authorization );
res.redirect('/login/loginUser');
// res.send({accessToken:accessToken, refreshToken:refreshToken});
} else {
console.log(error.message);
}
});
} catch (error) {
console.log(error.message);
}
});
the route I want to go
router.get('/loginUser',authenticateToken,(req,res,next)=>{
// console.log(req.user);
// res.render("pages/dashboard/index");
// res.redirect("/");
res.send("Success");
console.log("Login SuccessFull..");
});
please help me I'm stuck in this form 3 days...
From what i get, you want to send some data(in this case, access token) to a certain route. You can always use query strings. Check out how it is used here.
However, I am not sure if passing around tokens in non-public api is secure.
You can parse request header to the route with the token like this.
And you can access that token in the middleware function by using this function.
function getTokenFromHeader() {
if (
(req.headers.authorization &&
req.headers.authorization.split(' ')[0] === 'Token') ||
(req.headers.authorization &&
req.headers.authorization.split(' ')[0] === 'Bearer')
) {
return req.headers.authorization.split(' ')[1];
}
return null;
}

How to set the token to local storage or cookies so that i can allow user to access certain web pages

I am trying to build an authentication system so, i used node , mysql,express for that so now i am simply saving and checking user exist in database can access but now i added JWT to it, so now i want this JWT token to store in localstorage or in cookies so, can someone guide me how can i do so
this is my authentication controller.js
var Cryptr = require('cryptr');
cryptr = new Cryptr('myTotalySecretKey');
var express = require('express');
const ap = express();
var jwt = require('jsonwebtoken');
var connection = require('./../config');
module.exports.authenticate = function (req, res) {
var email = req.body.email;
var password = req.body.password;
connection.query('SELECT * FROM users WHERE email = ?', [email], function (error, results, fields) {
if (error) {
res.json({
status: false,
message: 'there are some error with query'
});
} else {
if (results.length > 0) {
decryptedString = cryptr.decrypt(results[0].password);
if (password == decryptedString) {
jwt.sign({ email, password },
'secretkey',
{ expiresIn: '10days' },
(err, token) => {
console.log('token:' + token);
module.exports = token;
console.log(token);
res.redirect('/home.html');
}
);
} else {
res.redirect('/login.html');
console.log("Wrong Input");
}
}
else {
res.redirect('/login.html');
}
}
});
};
now i want to pass the token value to the local-storage or cookies so that i can restrict someone from acessing a page, i am reallly new to node js so any help would be appriciated
First I should notify you that do not put any secret things like password in jwt payload because the values of the payload could be accessed easily, you can try to copy paste a jwt in jwt.io site and see the payload.
set jwt in cookie like below, this will use express cookie method that does set Http Set-Cookie header:
res.cookie('jwt', generated_cookie)
.redirect('/home.html');
Also if you want to use localStorage you can set jwt in header and then in your code get the jwt from the header of login request and save it in localStorage and after that you should pass it as header in all other request, but this approach is a better solution for api calls like when you use react or vue ...
res.set({x-token: generated_token});
// In your code get
// get token from response
localStorage.setItem('token', token);
// now whenever calling api pass token as header
I show you one solution using jwt token, you choose another way:
Back-end file e.g. api.js
let jwt = require('jsonwebtoken')
let secret = 'yourSecret'; //secret key necessary to encode token
let Cryptr = require('cryptr');
let cryptr = new Cryptr('myTotalySecretKey');
module.exports = function(router,upload) {
function tokenAuth(req, res, next){
let token = req.body.token || req.body.query || req.headers['x-access-token']
if(token){
jwt.verify(token, secret, function(err,decoded){
if(err){
res.json({ authenticated: false, message:'Invalid token'})
} else {
req.decoded = decoded;
next()
}
})
} else {
res.json({success:false, message:'No token provided'});
}
}
router.post('/authenticate', function(req, res){
connection.query('SELECT * FROM users WHERE email = ?', [email], function (error, results, fields){
if(error) {
res.json({ success:false, message: err })
}
if(!results.length){
res.json({success:false, message:'User no found'})
} else if (results.length>0){
if(!req.body.password){
res.json({success:false, message:'Password was not provided'});
} else {
var validPassword = cryptr.decrypt(results[0].password);
if(validPassword === req.body.password){
res.json({success:false, message:'Incorrect password'})
} else {
var token = jwt.sign({username: results[0].username, email: results[0].email}, secret, {expiresIn: '24h'})
res.json({success:true, message:'You have logged in correctly!', token: token })
}
}
}
})
})
//If you want create a route for authenticated users for example comment posts, you can use our `tokenAuth function`
router.post('/post/comment',tokenAuth,function(req,res){
//access only for authenticated users
}
return router
}
This tokenAuth function we'll be use in paths restricted to authenticated users
server file e.g. server.js
const express = require('express');
const app = express();
const port = process.env.PORT || 80;
const http = require('http').Server(app);
const routes = require(path_to_api.js)(router);
app.use('/myApi', routes)
//***Here you should implement more details about your project such as routes, body parsers and other middlewares*****//
//Connect to your database
http.listen(port, ()=> console.log(`Server running on ${port}`))
Front-end file e.g. controller.js
function(login){
return fetch('/myApi/authenticate',{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(login)
}).then(result=>result.json()).then(data=> window.localStorage.setItem('token', data.token))
}
//`login` argument should be an object and should be like {username: 'user username', password: 'user password'}
In order to make a user store cookies, you can use the Set-Cookie header. From MDN:
Set-Cookie: <cookie-name>=<cookie-value>
In order to pass a header using Express, you can use res.set(), e.g. res.set("Set-Cookie", "Token=" + token). I also suggest you use the HttpOnly cookie directive, since it seems from your post that you don't access this token directly via Javascript and you simply want to check it when the client requests a webpage: res.set("Set-Cookie", "Token=" + token + "; HttpOnly").
The client will send the Cookie header to you when it requests a resource. You can check this header using req.header('Cookie'), and the output will be "Token=<token>" if the user is authenticated. You can then check this token for authenticity.

Jwt cannot be parsed, Okta

I am trying to set up Okta authentication on my React App.
On the client side I am able to authenticate successfully and I get the access token. However when I try to authenticate a backend service using OktaJwtVerfier, I get the error message:
'Jwt cannot be parsed. SyntaxError: Unexpected token in JSON at position 0'
I have develop a very simple test program to test the verification of the token, so basically I get authenticated on the browser, I copy paste the jwt token in my small script to test authentication, and it fails with the message above, what am I doing wrong?
const OktaJwtVerifier = require('#okta/jwt-verifier');
const oktaJwtVerifier = new OktaJwtVerifier({
issuer: "https://dev-XXXXX.oktapreview.com/oauth2/default",
clientId: "XXXXXX",
assertClaims: {
'aud': 'api://default',
'cid': "XXXXXX",
},
});
const accessToken = 'Bearer eyJraWQiO.....';
oktaJwtVerifier.verifyAccessToken(accessToken).then((jwt) => {
console.log('auth succesfulll', jwt);
}).catch((e)=> {
console.log(e);
})
The comment by #jps is correct. Your header has a value of Bearer XXXX, where XXXX is the actual JWT string to parse.
Here's an example from the Okta project of how they do it in an Express app:
const authHeader = req.headers.authorization || '';
const match = authHeader.match(/Bearer (.+)/);
if (!match) {
res.status(401);
return next('Unauthorized');
}
const accessToken = match[1];
You can see the code in its full context here.
your code could be modified as follows:
const headerValue = 'Bearer eyJraWQiO.....';
const match = headerValue.match(/Bearer (.+)/);
if (!match) {
throw new Error('your error message here')
}
const accessToken = match[1];
oktaJwtVerifier.verifyAccessToken(accessToken).then((jwt) => {
console.log('auth succesfulll', jwt);
}).catch((e)=> {
console.log(e);
})

Categories

Resources