verify_jwt_token
var jwt = require('jsonwebtoken');
var config = require('./env/config.json')
module.exports = function(req,res,next) {
var token = req.body.token || req.query.token || req.headers['x-access-token'];
if (token) {
console.log("----------------------------------------");
console.log(token);
console.log("----------------------------------------");
console.log(config.jwt_secret);
console.log("----------------------------------------");
// verifies secret and checks exp
jwt.verify(token, config.jwt_secret, function(err, decoded) {
if (err) { //failed verification.
return res.json({"error": true});
}
req.decoded = decoded;
next(); //no error, proceed
});
} else {
// forbidden without token
return res.status(403).send({
"error": true
});
}
}
Routes
var user = require('../controller/user.controller.js');
var token_verify = require('../../config/verify_jwt_token.js')
module.exports = function (app) {
app.route('/register_user').post(user.register);
app.route('/login').get(user.login);
app.route('/auth',token_verify).get(user.auth);
}
I want to call j w t verification function from this route.I don't want to call from the controller. app.route('/auth',token_verify).get(user.auth); Calling from this route
Please help.
Thank you in advance.
This will work-ish:
const express = require('express')
const app = express()
function jwtVerify (req, res, next) {
console.log('verifying token...')
// logic
next()
}
app
.use(jwtVerify)
.route('/example')
.get((req, res) => res.json({ hello: 'World' }))
app.listen(3000)
The issue you will run into is that the middleware will execute for every route you define because the middleware is applied to the app instance. To fix this, you need to make use of the Router. Quick dirty example below:
app.js
const express = require('express')
const app = express()
const securedRoutes = require('./secured-routes')
function jwtVerify (req, res, next) {
console.log('verifying token...')
// logic
next()
}
app.use('/secured', jwtVerify, securedRoutes)
app.listen(3000)
secured-routes.js
const express = require('express')
const router = express.Router()
router.get('/', (req, res) => res.json({ message: 'Hello from secured routes' }))
module.exports = router
Related
I am learning a new way to authenticate all my APIs using the application-level middleware. I looked into multiple examples. I tried the following code as one of the ways.
Below is my code, I am writing firebase function with the help of necessary fields already there. I use "firebase serve" to host my functions locally.
const express = require('express')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')()
const cors = require('cors')({ origin: true })
const app = express()
const router = express.Router()
app.use(cors)
app.use(cookieParser)
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }))
app.use(async (err, req, res, next) => {
console.log('Middleware')
try {
const { authorization } = req.headers
if (!authorization) {
throw new ErrorHandler(401, "User is not unathorized")
}
if (!authorization.startsWith('Bearer')) {
throw new ErrorHandler(401, "User is not unathorized")
}
const split = authorization.split('Bearer ')
if (split.length !== 2) {
throw new ErrorHandler(401, "User is not unathorized")
}
const token = split[1]
const decodedToken = await admin.auth().verifyIdToken(token);
res.setHeader("email", decodedToken.email)
next()
} catch (error) {
console.log("END")
next(error)
}
});
router.get('/', (req, res) => {
res.end(`${Date.now()}`)
})
router.post('/data', async (req, res, next) => {
res.setHeader("Content-Type", "application/json")
console.log('DATA')
try {
// my other logic goes here
res.end()
} catch (error) {
next(error)
}
})
app.use('/api', router)
app.use((err, req, res, next) => {
if (err) {
handleError(err, res);
}
console.log(JSON.stringify(req.body))
});
exports.app = functions.https.onRequest(app)
I have created a cloud function named app. I am using API like this:
http://localhost:5000/app/api/data
I have written a middleware for authorizing all my APIs that are coming. Middleware is fetching bearer token and token is being verified with the help of firebase.
But when I call "/api/data" this API from postman or web the middleware is not called. For debugging purpose I used console.log to check.
My current flow is POSTMAN -> DATA
What I want is:
POSTMAN -> MIDDLEWARE(if authenticated) -> DATA
POSTMAN -> MIDDLEWARE(if not authenticated) -> END
Please let me know what is the issue with my code is.
Remove err parameter from the middleware, You are setting it as an error handler instead of a middleware, this is the reason the code is not getting executed,
Below code will execute the handler every time you access the /api route
const express = require('express')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')()
const cors = require('cors')({ origin: true })
const app = express()
const router = express.Router()
app.use(cors)
app.use(cookieParser)
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }))
app.use(async (req, res, next) => {
console.log('Middleware')
try {
const { authorization } = req.headers
if (!authorization) {
throw new ErrorHandler(401, "User is not unathorized")
}
if (!authorization.startsWith('Bearer')) {
throw new ErrorHandler(401, "User is not unathorized")
}
const split = authorization.split('Bearer ')
if (split.length !== 2) {
throw new ErrorHandler(401, "User is not unathorized")
}
const token = split[1]
const decodedToken = await admin.auth().verifyIdToken(token);
res.setHeader("email", decodedToken.email)
next()
} catch (error) {
console.log("END")
next(error)
}
});
router.get('/', (req, res) => {
res.end(`${Date.now()}`)
})
router.post('/data', async (req, res, next) => {
res.setHeader("Content-Type", "application/json")
console.log('DATA')
try {
// my other logic goes here
res.end()
} catch (error) {
next(error)
}
})
app.use('/api', router)
app.use((err, req, res, next) => {
if (err) {
handleError(err, res);
}
console.log(JSON.stringify(req.body))
});
exports.app = functions.https.onRequest(app)
GET http://localhost:5000/booksIdea/show 403 (Forbidden)
i check the token in the website https://jwt.io/ i got invalid signature so i guess why the problem came from but i ignore how to fix it
i searched abt this error and this is what i found : Receiving a 403 response is the server telling you, “I’m sorry. I know who you are–I believe who you say you are–but you just don’t have permission to access this resource. Maybe if you ask the system administrator nicely, you’ll get permission. But please don’t bother me again until your predicament changes.”
API GET function on front end:
import axios from 'axios'
export const ShowBooks = () => {
let token = localStorage.getItem("usertoken")
return axios.get("http://localhost:5000/booksIdea/show", {
headers: {
Authorization: `Bearer ${token}`, //here remove + in template litereal
},
})
.then(res => {
console.log("Success")
})
.catch(error => {
console.log(error)
})
}
backend app.js
const express = require('express')
var cookieParser = require('cookie-parser')
const app = express()
var cors = require('cors')
var bodyParser = require('body-parser')
const port = 5000
const routes = require("./routes");
const con = require('./db')
var cors = require('cors')
app.use(cors())
// database connect
con.connect(function(err) {
if (err) throw err;
console.log("Connected!");
});
//cookie
app.use(cookieParser())
//routes
// support parsing of application/json type post data
app.use(bodyParser.json());
//support parsing of application/x-www-form-urlencoded post data
app.use(bodyParser.urlencoded({ extended: true }));
app.use("/", routes);
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
here is routes
var express = require('express')
var router = express.Router()
var Controller = require('./controller')
var authController = require('./authController')
var BooksIdeaController = require('./BooksIdeaController')
router.post('/register',Controller.register);
router.post('/login',authController.login);
router.post('/booksIdea/:id',authController.verify,BooksIdeaController.addComment)
router.post('/booksIdea/addbook',authController.verify,BooksIdeaController.addBookIdea)
router.get('/booksIdea/show',authController.verify,BooksIdeaController.showBookIdea)
router.put('/booksIdea/edit/:id',authController.verify,BooksIdeaController.UpdateBookIdea)
router.delete('/booksIdea/delete/:id',authController.verify,BooksIdeaController.DeleteBookIdea)
module.exports = router;
authController
const con = require('./db');
var bcrypt = require('bcrypt');
let jwt = require('jsonwebtoken');
const express = require('express')
var cookieParser = require('cookie-parser')
const app = express()
module.exports.login=function(req,res){
var username=req.body.name;
var password=req.body.password;
con.query('SELECT * FROM users WHERE username = ?',[username], function (error, results, fields) {
if (error) {
res.json({
status:false,
message:'there are some error with query'
})
}else{
if(results.length >0){
bcrypt.compare(password, results[0].password, function (err, result) {
if (result == true) {
jwt.sign({user:results},'configSecret',(err,token)=>{
res.json({
token:token
})
});
// res.json({
// status:true,
// message:'successfully authenticated'
// })
} else {
res.json({
status:false,
message:"username and password does not match"
});
}
});
}
else{
res.json({
status:false,
message:"username does not exits"
});
}
}
});
}
module.exports.home=function(req,res){
res.send('hello');
}
//////
// if(password==results[0].password){
// }else{
//
// }
module.exports.verify = 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];
// Set the token
req.token = bearerToken;
// Next middleware
next();
} else {
// Forbidden
res.sendStatus(403);
}
}
How can I fix this error? thank you in advance for your help
Check your localstorage localStorage.getItem("usertoken")
Your token can be:
missing or undefined
incorrect token - probably a typo
I have set up express to use the following paths:
const profile = require("./api/profile")
const events = require("./api/events")
app.use("/api/events", events)
app.use("/api/profile", profile)
Inside the events and profile index.js files I have the following:
const router = require('./../../modules/router.js')
router.get('/', (req, res) => {
})
module.exports = router
My router.js file:
const express = require("express")
const cookieParser = require('cookie-parser')()
const cors = require('cors')({origin: true})
const router = express.Router()
const firebase = require("./firebase.js")
// https://github.com/firebase/functions-samples/tree/master/authorized-https-endpoint
// Must have header 'Authorization: Bearer <Firebase ID Token>'
const validateFirebaseIdToken = (req, res, next) => {
if ((!req.headers.authorization || !req.headers.authorization.startsWith('Bearer ')) &&
!req.cookies.__session) {
res.status(403).send({ "error": 'Unauthorized'})
return
}
let idToken
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
// Read the ID Token from the Authorization header.
idToken = req.headers.authorization.split('Bearer ')[1]
} else {
// Read the ID Token from cookie.
idToken = req.cookies.__session
}
firebase.admin.auth().verifyIdToken(idToken).then((decodedIdToken) => {
req.user = decodedIdToken
return next()
}).catch(error => {
res.status(403).send({"error": 'Unauthorized'})
})
}
router.use(cors)
router.use(cookieParser)
router.use(validateFirebaseIdToken)
module.exports = router
For some reason, the router mixes up the paths /api/events/ and /api/profile/ whenever I call them. For all other paths it works fine. How can I stop this from happening?
If you are using the same router for both events and profile, it could be the source of your issue.
Have you tested to create one router for each module?
Maybe try something like this for both events and profile:
const router = require('express').Router()
router.get('/', (req, res) => {
})
module.exports = router
I am building an API backend with Express (v4) and facing an issue that my middleware function is not called
on sub-paths of my route. E.g. it is called for /movie but not for /movie/search.
I have split my routes into separate files. Below is the code, shortened to the relevant parts.
Any help is appreciated!
app.js
var express = require('express');
var app = express();
var router = require('routes')(app);
/routes/index.js
module.exports = function(app) {
app.use('/movie', check_authentication, require('movie'));
};
/routes/movie.js
var Movie = require(../models/movie');
// Middleware is working for this route (/movie?movie_id=123)
router.get('/', function(req, res) {
Movie.findById(req.query.movie_id)
.then(function(movie) {
res.status(200).json(movie);
}, function(err) {
res.status(400).send(err);
});
});
// Middleware is NOT working for this route (/movie/search?keyword=matrix)
router.get('/search', function(req, res) {
Movie.findById(req.query.keyword)
.then(function(movie) {
res.status(200).json(movie);
}, function(err) {
res.status(400).send(err);
});
});
/routes/check_authentication.js
var express = require('express');
var router = express.Router();
var firebaseAdmin = require('firebase-admin');
var path = require('path');
var config = require(path.resolve(__dirname, '../config/config.json'));
firebaseAdmin.initializeApp({
credential: firebaseAdmin.credential.cert(path.resolve(__dirname, '../config/' + config.firebase.serviceAccount)),
databaseURL: config.firebase.databaseURL
});
// AUTHENTICATION MIDDLEWARE
// needs to be included in any request which requires authorization
// =============================================================================
router.all('/', function(req, res, next) {
// check if authorization header is present
var token = req.headers['authorization'];
if (typeof token === 'undefined') {
res.status(403).json({ Error: 'Unauthenticated' });
}
else {
firebaseAdmin.auth().verifyIdToken(token).then(function(decodedToken) {
req.email = decodedToken.email;
next(); // all good. go ahead with the request
}).catch(function(error) {
res.status(403).json({ Error: 'Unauthenticated' });
});
}
});
module.exports = router;
It seems I found the problem.
Changing the middleware to trigger on * fixes it.
router.all('*', function(req, res, next)
Maybe someone can confirm that this is the way to go.
The check_authentication module should export the middleware function, not a router.
module.exports = function(req, res, next) {
// check if authorization header is present
// ...
});
For example, in Meteor, there's something like
Router.plugin('ensureSignedIn');
Router.plugin('ensureSignedIn', {
except: ['home', 'atSignIn', 'atSignUp', 'atForgotPassword']
});
So unsigned user cannot access other routes except above four.
How to do this in express.js? I'm using passport.js also.
I'm not familiar with Meteor, but you can do something like the following, assuming you want to make pages available to only authenticated users (passport).
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated())
return next();
else
// Return error content: res.jsonp(...) or redirect: res.redirect('/login')
}
app.get('/account', ensureAuthenticated, function(req, res) {
// Do something with user via req.user
});
The ensureAuthenticated function is just an example, you can define your own function. Calling next() continues the request chain.
I should use middleware for protect my routes, even to protect certain verbs in the same route:
for example: in my endpoint/route.js
// the require sentences are omitted
const express = require('express');
const { /*controllerFunctions*/ } = require('./controller');
const {routeGuard} = require('/*must create a route guard*/');
const router = express.Router();
router.route('')
.get(getAllResources)
;
router.route('/:id') //
.get(validateParam,getOneResource);
router.use(routeGuard);
router.route('/:id')
.post(validateParam,validateBody,postResource)
.patch(validateParam,validateBody,patchProblemById)
.delete(validateParam,deleteResource)
;
module.exports = router;
and my routeGuard file should be like this:
const { promisify } = require('util');
const jwt = require("jsonwebtoken");
const AppError = require('./appError');
const {User} = require('./../endpoints/users/model');
const wrapper = require('./try-wrapper');//try catch wrapper
module.exports.routeGuard = wrapper(async function (req, res, next){
// the err message is the same on purpose
const notAllowed = new AppError('Unauthorized: Invalid or Nonexistent credentials',401);
let token = null;
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')){
token = req.headers.authorization.split(' ')[1];
}
if (!token) return next(notAllowed );
const payload = await promisify(jwt.verify)(token,process.env.KEY);
const user = await User.findById(payload.id);
if (!user) return next( notAllowed);
if ( ! user.hasSamePasswordSince(payload.iat) )return next( notAllowed );
req.user = user; // further use...
next();
});