Mean.js req.isAuthenticated is showing fail? - node.js

i have downloaded meanjs version#0.1.12.here i have used two servers for front end i hvae used angular with ionic its running in localhost:3000,for backend i have used meanjs.in that meanjs i have created signup,signin and articles.when ever i am using meansjs as a backend and front end it's working fine .but when i connect to another server(localhost:3000) signup and signin working fine but when ever i am creating articles i am getting 401 unauthorized bcoz of that req.isAuthenticated() function.when ever i create article module req.isAuthenticated() getting fail.req.isAuthenticated() i dono what should i pass for this function i have included my code anyone help me out
now i am passing data like this
$http.post('http://192.168.1.14:3000/articles', credentials).success(function(response,data,errorResponse) {
// If successful we assign the response to the global user model
//$scope.authentication.user =response;
console.log(response);
console.log(data);
// And redirect to the index page
$location.path('/tab/account');
}, function(response,data,errorResponse) {
$scope.error = errorResponse.data.message;
console.log($scope.error);
console.log(data);
});
routes:
app.route('/articles')
.get(users.requiresLogin,articles.list)
.post(users.requiresLogin,articles.create);
login checkup
/**
* Require login routing middleware
*/
exports.requiresLogin = function(req, res, next) {
//console.log(req.isAuthenticated());
console.log(req);
if (!req.isAuthenticated()) {
return res.status(401).send({
message: 'User is not logged in'
});
}
next();
};
/**
* User authorizations routing middleware
*/
exports.hasAuthorization = function(roles) {
var _this = this;
console.log('sss');
return function(req, res, next) {
_this.requiresLogin(req, res, function() {
if (_.intersection(req.user.roles, roles).length) {
return next();
} else {
return res.status(403).send({
message: 'User is not authorized'
});
}
});
};
};

I think I had the same problem. Make sure to check your policies folder on the server side.
roles: ['user'],
allows: [{
resources: '/articles',
permissions: ['get', 'post']
}, {
resources: '/articles/:articlesId',
permissions: ['get']
}, {
resources: '/articles',
permissions: ['post']
}]
Add the resource path /articles and permissions.

Related

How to add custom middleware to express-openapi-validator using Swagger 3

I've got a Node app using express-openapi-validator that takes a an api spec file (which is a .yml file), with request and response validation. The express-openapi-validator package routes the request to a handler file (defined in the spec). This is what one of the handlers might look like:
function getUsers(req, res) {
const { 'x-user-id': userId } = req.headers
res.status(200).json(`Your userId is ${userId}`)
}
I've got an API key feature, where users can get a new API key, and the other endpoints that need the caller to have the API key in the request headers to validate the request.
I know it should be possible to use middleware to validate the request, but I can't figure out how to use custom middleware with the express-openapi-validator package on select endpoints.
For eg:
GET /apikey = does not require api key
GET /resource = requires api key
How do I configure this?
Here's what the openapi validator code in my app.js looks like:
new OpenApiValidator({
apiSpec,
validateResponses: true,
operationHandlers: path.join(__dirname, './handlers'),
})
.install(app)
.then(() => {
app.use((err, _, res) => {
res.status(err.status || 500).json({
message: err.message,
errors: err.errors,
});
});
});
I actually ended up finding a solution for this myself.
First of all, I'm using version 4.10.5 of express-openapi-validator, so the code above is slightly different.
Here's what it looks like now:
// index.js
app.use(
OpenApiValidator.middleware({
apiSpec,
validateResponses: true,
operationHandlers: path.join(__dirname, './handlers'),
validateSecurity: {
handlers: {
verifyApiKey(req, scopes) {
return middleware.verifyApiKey(req)
},
bearerAuth(req, scopes) {
return middleware.verifyToken(req)
}
}
},
}),
);
app.use((err, req, res, next) => {
res.status(err.status || 500).json({
message: err.message,
errors: err.errors,
});
The way I ended up using middleware in my routes is below:
I've added a securitySchemes section in my swagger.yml file, like so:
components:
securitySchemes:
verifyApiKey:
type: apiKey
in: header
name: x-api-key
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
There's a bit more information about it here: https://swagger.io/docs/specification/authentication/
On each route that needs the middleware, I'm adding a security section, like so:
/team:
post:
security:
- bearerAuth: []
description: Create a new team
operationId: createTeam
x-eov-operation-id: createTeam
x-eov-operation-handler: team
As you can see in my code above (in the index.js file), I've got a validateSecurity key, with a handlers key that then has the correlating keys that are in my swagger.yml (verifyApiKey and bearerAuth). These functions get the request and scope to check if they're valid. These functions return a boolean value, so true means that the middleware lets the request through, and false means a 403 response will be returned.
validateSecurity: {
handlers: {
verifyApiKey(req, scopes) {
return middleware.verifyApiKey(req)
},
bearerAuth(req, scopes) {
return middleware.verifyToken(req)
}
}
},
Please respond if I've got anything above wrong, or if the explanation can be clearer. If you have questions, please post them below.
You can simply pass array of handlers instead of just 1 function, like in express.
So in you code, the getUsers function that probably is what the x-eov-operation-id refers to, would be an array of 2 functions:
const getUsers = [
apiKeyMiddleware,
(req, res) => {
const { 'x-user-id': userId } = req.headers
res.status(200).json(`Your userId is ${userId}`)
}
];
I was in a similar situation as you, using OpenAPI/Swagger packages like that limited my ability to add specific middleware per endpoint, so my solution was I created an npm module called #zishone/chaindler.
You can use it like this:
const { Chain } = require('#zishone/chaindler');
function getUsers(req, res) {
const { 'x-user-id': userId } = req.headers
res.status(200).json(`Your userId is ${userId}`)
}
function postUsers(req, res) {
// ...
}
function mw1(req, res, next) {
next()
}
function mw2(req, res, next) {
next()
}
module.exports = {
getUsers: new Chain(mw1, mw2).handle(getUsers),
postUsers: new Chain(mw1).handle(postUsers)
}
Basically it just chains the middlewares then calls them one by one then call the handler/controller last.

401 Unauthorized Request Discord API with OAuth

I'm wanting to allow users of my site that use Discord to be able to "automatically" join my guild.
I have everything done except I always get a 401: Unauthorized from Discord's API using the following;
router.get("/cb", passport.authenticate("discord", { failureRedirect: "/" }), async function(req, res) {
const data = { access_token: req.user.accessToken };
axios.put(`https://discordapp.com/api/v8/guilds/${config.CyberCDN.server_id}/members/${req.user.id}`, {
headers: {
"Content-Type": "application/json",
"Authorization": `Bot ${config.CyberCDN.bot_token}`
},
body: JSON.stringify(data)
}).then((success) => {
console.log(`[DASHBOARD] ${req.user.username}#${req.user.discriminator} - Logging in...`);
console.log(success.config.data)
console.log(success.response.status)
return res.status(200).redirect("/");
}).catch((error) => {
console.log(`[DASHBOARD] ${req.user.username}#${req.user.discriminator} - Failed Logging in...`);
console.log(error.config.data.replace(config.CyberCDN.bot_token,"TOKEN"))
console.log(error.response.status)
return res.status(403).redirect("/");
});
});
I don't understand how when everything I have done is correct;
I have even asked in the Discord-API server regarding this matter with the same issue,
I did however have it working ONE TIME and now it's broke again, I have 0 clue how it broke.
My scopes are as follow "oauth_scopes": ["guilds.join"]
I found a better solution to this problem I had:
const DiscordOauth2 = require("discord-oauth2");
const discord = new DiscordOauth2();
/**
* Other required stuff for express.js goes here...
*/
router.get("/login", passport.authenticate("discord"));
router.get("/cb", passport.authenticate("discord", { failureRedirect: "/forbidden" }), async function(req, res) {
req.session.user = req.user;
res.redirect('/');
});
router.get("/support", authOnly, async function(req, res) {
discord.addMember({
accessToken: req.session.user.accessToken,
botToken: config.CyberCDN.bot_token,
guildId: config.CyberCDN.server_id,
userId: req.session.user.id,
roles: [config.CyberCDN.site_role]
}).then((r) => {
if(r) {
let date = new Date(r.joined_at);
res.status(200).json({ status: "Joined Server" });
const embed = new Embed()
.title(`New User Joined Via Site\n${r.user.username}#${r.user.discriminator}`)
.colour(16763904)
.thumbnail(`https://cdn.discordapp.com/avatars/${r.user.id}/${r.user.avatar}.webp?size=128`)
.footer(`User joined at: ${date.toLocaleDateString()}`)
.timestamp();
dhooker.send(embed);
console.log(r)
}else{
res.status(401).json({ status: "Already In There?" });
}
});
});
Basically through browsing my initial 401: Unauthorized error stumbled across a nice little OAuth2 NPM For Discord called discord-oauth2 developed by reboxer and numerous other people, which can be found here.
The helpful part was documented further down the README.md of that repo, in relation to my problem. Relation found here
I have also contributed that they add the removeMember feature also.

Node-Restful with Json web tokens

I am trying to build a simple web token protected api in nodejs. I have been following this tutorial authenticate a node js api with json web tokens and have been implementing the steps in my app. I now have an api running that allows me to get/post/put/delete and a route that generates a webtoken for the user and shows it in plain text (for dev purposes). I am using node-restful for the api's but I am having some trouble understanding how I would actually verify if the client is sending the webtoken in their request, before allowing these get/post/put/delete requests.
Here is my router. Where I define the allowed requests:
const express = require('express')
const router = express.Router()
// Models - Load models here
var userModel = require('./models/User')
// Controllers - Load controllers here
const userController = require('./controllers/userController')
// Routes - Define routes here
router.post('api/authenticate', userController.authenticate) //Route that generates the webkey and shows it in the response
// Configure the endpoint that node-restful will expose. Here I want to first check if the user is sending his or her api key. Before allowing these methods.
userModel.methods(['get', 'put', 'post', 'delete'])
userModel.register(router, '/api/users')
// Export the router object
module.exports = router
Here is my userController where the token is generated.
// Dependencies
const User = require('../models/User')
const jwt = require('jsonwebtoken')
const config = require('../config.js')
module.exports = {
authenticate: function(req, res, next) {
// find the user
User.findOne({username: req.body.name}, function(err, user) {
if (err) throw err;
if (!user) {
res.json({
success: false,
message: 'Authentication failed. User not found.' });
} else if (user) {
// check if password matches
if (user.password != req.body.password) {
res.json({
success: false,
message: 'Authentication failed. Wrong password.' });
} else {
// if user is found and password is right
// create a token
var token = jwt.sign(user, config.secret, {
expiresIn: 60*60*24 // expires in 24 hours
});
// return the information including token as JSON
res.json({
success: true,
message: 'Enjoy your token!',
token: token
});
}
}
})
}
}
And here is my user model.
// Dependencies
const restful = require('node-restful')
const mongoose = restful.mongoose
// Schema
const userSchema = new mongoose.Schema({
username: String,
password: String,
email: String
})
// Return the model as a restful model to allow it being used as a route.
module.exports = restful.model('User', userSchema)
Is there some way I can protect these endpoints, using the same manner of syntax as I am currently using to expose them? I believe I would have to check for the web token before defining the methods:
userModel.methods(['get', 'put', 'post', 'delete'])
userModel.register(router, '/api/users')
If I simply remove the methods themselves, the user will not be able to get the page and is shown a: "Cannot GET /api/users" error. What if I wanted to show a custom error? For example: "No web token provided. Register to authenticate" etc etc? Any help is much appreciated. Thank you in advance.
I now have a function that checks for the token before serving a page. It seems to work for now. Currently I am passing the token manually in postman as a header: x-access-token. How would I catch the token upon generation and automaticly make the client send it on future requests? Here is the function that checks for the token and the protected route.
Great. I kept working while waiting for any answers and completed this step. I can now generate the token and using postman pass that to a secured route I created. It works perfectly, but I am struggeling to understand how I am going to save the token on the client side and pass that on every request. I still generate the token, the same way as above. I can verify the token by manually passing it in my header as x-access-token, but how would I do this automaticly?
Update
Here is the function that checks the token and a protected route that utilizes that function:
// Routes - Define routes here
function getToken(req, res, next) {
var token = req.body.token || req.query.token || req.headers['x-access-token'];
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, config.secret, function(err, decoded) {
if (err) {
return res.json({ success: false, message: 'Failed to authenticate token.' });
} else {
// if everything is good, save to request for use in other routes
req.decoded = decoded;
console.log(decoded);
next();
}
});
} else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
}
router.get('/entries', getToken, entryController.get)
I found this question save-token-in-local-storage-using-node Which solved the last piece of the puzzle.
You can simply write a middleware for this kind of purpose. Clients will generally send tokens in header, so that you can get the header information and verify it. Your middleware will be something like this.
module.exports = (req, res, next) => {
if (!req.headers.authorization) {
return res.status(401).json({
success: false,
message: "You are not authorized for this operation."
})
}
// get the authorization header string
const token = req.headers.authorization
// decode the token using a secret key-phrase
return jwt.verify(token, config.secret, (err, decoded) => {
// the 401 code is for unauthorized status
if (err) {
return res.status(401).json({
success: false,
message: "You are not authorized for this operation."
})
}
const username = decoded.username
// check if a user exists
return User.findOne({username: username}, (userErr, user) => {
if (userErr) {
return res.status(500).json({
success: false,
message: "Error occured while processing. Please try again.",
err: userErr
})
}
if ( !user ) {
return res.status(401).json({
success: false,
message: "You are not authorized for this operation."
})
}
return next()
})
})
}
For the security reasons it is better to store JWTs in your application associated with the user. Complete explanation can be found here.
Update:
You can save the token in cookie and parse the cookie to find out the token and then verify that.

Sails.js route redirect with a custom policy

Situation I want to achieve:
Request to /register runs AuthController.register
Request to /facebook runs AuthController.register but applies a facebook policy before.
I have created a policy in
/api/policies/facebook.js
like this
var graph = require('fbgraph');
module.exports = function(req, res, next) {
facebook_token = req.query.facebook_token;
if(!facebook_token){
res.send('401',{error:"Missing facebook token"});
}
graph.setAccessToken(facebook_token);
graph.get("me",function(err,graph_res){
if(err){
res.send('401',{error:"Facebook authentication error"});
return;
}
else{
next();
}
});
};
Set it up policies in
/config/policies.js
like this
module.exports.policies = {
'auth': {
'facebook': ['facebook']
}
}
I set up my routes like this
module.exports.routes = {
'post /register': 'AuthController.register',
'post /facebook': 'AuthController.register',
};
Now the code in facebook policy doesn't get called. How would I accomplish something like this?
I'm not sure if policies can work the way you have intended them to. In your current /config/policies.js you're telling Sails to run the facebook.js policy whenever the AuthController action facebook is called. Since you have no such action defined in the controller, the policy never gets run. To policies, it doesn't matter which way the request came from, what matters is which controller action the request is trying to access.
What you could do, however, is to run the policy on every call to AuthController.register, and add a line in the policy file to check whether the request came from /facebook or not.
/config/policies.js:
module.exports.policies = {
auth': {
'register': ['facebook']
}
}
/api/policies/facebook.js:
module.exports = function(req, res, next) {
if (req.route.path === '/facebook') {
facebook_token = req.query.facebook_token;
if(!facebook_token){
res.send('401',{error:"Missing facebook token"});
}
graph.setAccessToken(facebook_token);
graph.get("me",function(err,graph_res){
if(err){
res.send('401',{error:"Facebook authentication error"});
return;
}
else{
next();
}
});
}
else return next();
};

sails session writing bug

I'm using sails 0.10.4 and stumbled with one pretty annoying bug. When user logs in I write his data into the req.session.user then in policies I can retrieve his data such as his role, password etc. But the req.session.user becomes undefined when I go out of the login action. Do you have any ideas how to handle this? Here's the code:
api/controllers/User.js :
module.exports = {
login: function (req, res) {
Users.findOneByEmail(req.param('email'))
.exec(function (err, user) {
if ((err) || (!user)) {
res.send({
error: 'User not found'
});
return;
}
if (!passwordHash.verify(req.param('password'), user.password)) {
res.send({
error: 'Incorrect passwpord'
});
return;
}
req.session.user = user;//I write user into the session
res.send({
user: user
});
});
}
}
api/policies/isLoggedIn.js
module.exports = function (req, res, next) {
if (req.headers.authentication) {
var credentials = JSON.parse(req.headers.authentication);
if(req.session.user.login === credentials.login)//User doesn't exist in session
return next();
}
}
In a testing environment , this issue can happen when testing with Supertest and not defining an agent
var agent = request.agent(app);
agent.post('/api/login',{email:'foo#bar.com',password:'foobar})
.end(function(err,res){...; done();});
It is the correct way to work with sessions, simply using request.post would not work as it would reinit the session variable as soon as the response is sent, even if we are chaining requests inside the same test.
Learnt it the hard way, so I hope it can help some lost developper.

Resources