Simple Express JS API token - node.js

I'm wonder how I can implement a simple API auth token without need for users? I just want one token that I can authenticate by adding it as a parameter when I call my API.
All the current examples on Google seem to be over engineered for my needs. I have some data stored in MongoDB and I simply serve this data like so:
app.get("/", (req, res) => {
Car.find((err, cars) => {
if(err){
throw err;
}
res.json({"cars": cars});
});
});
Is it possible to add some simple middleware that checks my environment file for an element with the name of api_token. Then check that the api_token in my env file matches the parameter that has been passed as a URL query.
Is there a way to do this? I'm aware that you can't use URL queries on a GET route so I am unsure how this would work.

Sure, use middleware: https://expressjs.com/en/guide/using-middleware.html
For your case, it can be as simple as the following:
// checkForApiToken.js
module.exports = (req, res, next) => {
const apiToken = req.header("api-token");
if (process.env.API_TOKEN !== apiToken) {
next(new Error("Unauthorized."));
return;
}
next();
}
The logic is simple:
Retrieve API-TOKEN value from the header.
Check it matches what I've defined in my env.
Does not match, throw an error by passing an error object into the next function.
Matches so I call next() with no error to proceed to the next request handler.
You would then use it like so:
app.get("/", checkForApiToken, async (req, res) => {
const cars = await Car.find().exec();
res.json({ cars });
});

Remember, Tokens are responsible for at least 2 API security mandatory things, authenticate and authorize. You don't need to authenticate users, but you need to be sure that the token you received is a Token and not a "HEADER".
If you use a static token,or anything else, first time i get your token your security is down. You need to specify AT LEAST when this token will die, and if it is a valid one based on some random assignment. You can't check for it's presence, you need to check if it is valid.
Javascript has an amazing convention background, whenever you have the opportunity, follow the convention. It is easier as it seems to implement a JWT based.
Just follow this : https://github.com/auth0/node-jsonwebtoken
and implement it in your middleware as you wishh.
Easily as this /
jwt.sign({
exp: Math.floor(Date.now() / 1000) + (60 * 60),
data: 'foobar'
}, 'secret');
jwt.verify(token, 'shhhhh', function(err, decoded) {
console.log(decoded.foo) // bar
});
You can always redo the concepts by using a "Web HEADER" and calling it a "TOKEN". But as i said, it is a "Web Header" not an "WEB TOKEN".

Related

JWT node protected data

I'm currently working on a MEAN full stack web project for a little marketplace app. This project's build in 3 parts :
- server -> node.js express mongoose
- front web -> angular 4
- front mobile -> ionic
I've to build this simple API REST, with a classic CRUD, but I have to use JWT to secure my adverts (for the market place).
An user will be able to delete or modify only the advertisements which he himself create, using JWT verification.
Currently, I have a token verification's middle-ware, but it does not prevent a user from deleting an ad created by another user.
I'm calling my middle-ware as I understood on tutorials, it can be change.
And after a lot of research, i only found information about authentication with JWT, then if someone can help my, thanks.
//my token verification's middle-ware
function verifyToken(req, res, next) {
var token = req.headers['x-access-token'];
if (!token)
return res.status(403).send({ auth: false, message: 'No token provided.' });
jwt.verify(token, config.secret, function(err, decoded) {
if (err)
return res.status(500).send({ auth: false, message: 'Failed to authenticate token.' });
// if everything good, save to request for use in other routes
req.userId = decoded.id;
next();
});
}
//an example of middle-ware call
router.delete('/:id',VerifyToken, (req, res) => {
advertModel.findById(req.params.id, (err, advert) => {
if(!advert){
res.json({message:"No advert corresponding"})
}
advert.remove((err) => {
if(err){
console.log(err);
}
res.json({message: 'Successfully deleted'});
});
});
});
This application is still under construction, then if you have any comments that would allow me to improve the few pieces of code that you see, go.
jwt token when comes with a request, if that token is valid it just pass the request to next with that user credential, but if the token is not valid, it stops the request lifecycle. But it does not have anything to do with the things you are trying to do.
You can write a simple conditional in your controller code like this
if(req.user.id !== youradd.user_id){
return ('with valid message and http code')
#shahinmahmud is right. Basically there are two parts to what you are doing. Authentication and Authorization. Authentication is done by JWT token validation. Authorisation is to restrict access based on the user. In your case, if it's just access to one resource, a simple if-else will do. Otherwise you need to look into some user management libraries.
This definition should probably help

Migrating Node JS code to Apollo server

I am setting up Apollo Server on my Node app and wondered about moving the functionality over to Apollo.
I have business logic like this:
router.post(
'/login',
(req, res, next) => {
if (!req.body.email || !req.body.password) {
return 'You must send the username and the password.';
}
Users.findOne({ email: req.body.email })
.then(user => {
bcrypt.compare(req.body.password, user.password, (err, success) => {
req.user = user;
next();
});
})
},
auth.createToken,
auth.createRefreshToken,
auth.logUserActivity,
(req, res) => {
res.status(201).send({
success: true,
authToken: req.authToken,
refreshToken: req.refreshToken
});
}
);
It follows Node router architecture where I add the found user object to req object, which passes the user to the next functions - createToken etc.. using the next() function. This was ok for my server before trying to introduce GraphQL/Apollo, but now I want all this logic to be easily accessible to the Apollo resolvers.
I often hear that people are having an easy time turning their server from REST/non-GraphQL into a GraphQL server, but at the moment it's looking like it's going to be a bit of a job to go through all the logic and separate everything in to their own functions which take parameters directly rather than using the req object.
Is this a correct assumption? Or am I missing something?
Thanks!
Migrating the code you have shown above would be a very easy task. Once you build your graphql server and create your schema, etc. Then all you need to do is create login mutation. Then your resolver would handle the logic you have shown above. Then, instead of pulling the values from from req.body they would be function parameters.
A good pattern I am currently following is creating a login method on the model itself. Then the resolver calls the method on the schema (Here is an example of a project I'm doing it on now: Login method. Then here is an example of what the resolver looks like: Resolver
Hopefully that helped!

I am wondering how to communicate between controllers

I want to invoke the user creation API after confirming the token internally in the server when I click the authentication link in the e-mail to implement the membership method using e-mail authentication.
//emailcontroller.js
router.get('/register/token', function(req, res) {
// check token
if(check(req.params.token)) {
request('http://localhost:8080/api/user', function(data) {
});
}
});
//usercontroller.js
router.post('/api/user', function(req, res) {
var user = new User();
user.userId = req.body.userId;
user.userPw = req.body.userPw;
user.save();
});
I want to invoke the user creation API after confirming the token internally in the server when I click the authentication link in email in order to implement membership method using email authentication.
As mentioned above, the email controller and the user controller are divided and each is routed. I want to modularize the code so that I want to call the existing user creation API to use it for general purpose rather than creating and exports common functions for a specific controller.
/*I do not want to implement it this way.*/
//emailController.js
router.get('/register/token', function(req, res) {
// check token
if(check(req.params.token)) {
userContoller.createUserFromEmail(userId, userPw);
}
});
//userController.js
exports.createUserFromEmail = function(userId, userPw) {
var user = new User();
user.userId = userId;
user.userPw = userPw;
user.save();
}
However, I have never seen communication between controllers in many examples. So I do not know if the way I thought was right. Rather, I think the cost of calling api internally on the server might be higher.
I want to know the correct pattern for communication between controllers. Please bear in mind that there is only a stack overflow when raising a question.
You got the right idea about exposing your API functionality as stand-alone functions (or classes). To avoid duplication, just call your internal methods from within your route handlers. So in your example:
router.post('/api/user', function(req, res) {
createUserFromEmail(req.body.userId, req.body.userPw);
});
In my own projects, I use classes to create my API. First I define a class with just the functionality and then I expose the methods in the route handlers:
export default class User {
read() {
}
create() {
}
update() {
}
delete() {
}
}
const user = new User();
router.get('/user/:id', (req, res) => user.read(req.params.id));
router.post('/user', (req, res) => user.create(req.body.data));
router.put('/user/:id', (req, res) => user.update(req.params.id, req.body.data));
router.delete('/user/:id', (req, res) => user.delete(req.params.id));
This should give you an idea of what you can do. You can write custom middleware and class decorators to reduce the boilerplate.
From your question what I understood:
You want to validate internally the token passed in query parameter, before doing anything else in the user controller.
I believe you are using express, and with express comes middlewares.
From docs:
Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named next.
What I usually do and a generally good practice is, pass the token in create user api and attach to email body.
for example:
api/user?token=somerandomstringloremispum
Route file:
router.post('/user', validateEmail, userController.create);
here validateEmail is a middleware function and will be invoked before create method of userController.
Now in your validateToken method, you can simply validate your token like:
function validateEmail (req, res, next) {
if(!valid(req.query.token)) {
//return with appropriate invalid token msg using res.json() or however you like
}
// if validated call `next middleware` like so:
next();
// this will allow `create` method of userController be invoked
}

Save Token in local Storage using node

I'm using JWT ("jsonwebtoken": "^5.4.0") with express 4 and jade.
I'm able to create the right Token, but How can i Pass this token in each call?
Where I have to store this token ? in headers or in localStorage?
For now I'm using CURL with Postman, and Set token in header in
x-access-token
Have I Do create a middleware that retrieve a token from Database and use this in each call?
thanks
You do not need to save and check the token from the database. This token such a mechanism can be decoded with only your-server, and if it was done that the token is valid. The code that you want to do should look like.
var cookieParser = require('cookie-parser')
app.use(cookieParser())
app.get('/login', function(req, res, next) {
var user = {name:'test'}; //!! find the user and check user from db then
var token = jwt.sign(user, 'secret', {
expiresInMinutes: 1440
});
res.cookie('auth',token);
res.send('ok');
});
app.use(function(req, res, next) {
var token = req.cookies.auth;
// decode token
if (token) {
jwt.verify(token, 'secret', function(err, token_data) {
if (err) {
return res.status(403).send('Error');
} else {
req.user_data = token_data;
next();
}
});
} else {
return res.status(403).send('No token');
}
});
Here you can find very nice article : https://scotch.io/tutorials/authenticate-a-node-js-api-with-json-web-tokens
I would recommend checking this out if you want local storage: https://www.npmjs.com/package/node-localstorage
But, with that said, you guys and girls wouldn't believe how long it took me to find res.cookie('auth' token) from the above answer. I scoured Google for hours, Passport docs, Express docs, GraphQL and authentication/authorization docs in an effort to find out how to get the token to the API in a stateless manner.
I already built JWT token security and secured my GraphQL resolvers with it, but then, I opted to use EJS along with graphql-request (approx same as Apollo Client), so I needed to find a way to pass the token to my middleware without using a server side session.
Storing a JWT token in cookies is fine especially if you take extra precautions such as signing the cookie, and I recall there are also options you can include that keep the cookie secure, so that other sites cannot see it if the "browser" allows access to cookies. If a cookie is signed with your server secret, the data inside the cookie simply cannot be altered and still be valid. The risk is always still someone leaking their token/cookie, and if that bothers you, do research into refresh tokens. However, API tokens are generally and should be kept tightly secret and safe. Your biggest annoyance will more likely be the requirement to maintain a blacklist of JWTs that expire a year from now if you set expiry to 1y.
I am just including my findings here because this question is actually a rare resource it seems...
Here is my Express middleware for authentication:
// AUTHENTICATION
app.use(async (req) => {
try {
const token = req.headers.authorization || req.cookies.auth
const { person } = await jwt.verify(token, SECRET)
req.person = person
return req.next()
} catch (e) {
return req.next()
}
})
You can see I am setting the token from the header with cookie as fallback. This supports my needs fine and allows me to use really any client with stateless security.
My logged in user is available as req.person in my views and GraphQL resolvers. If req.person is not set, the user is treated as not-logged-in.
I am using return req.next() which is important to note because calling next() without parameters is treated as "clean go-to next middleware and/or proceed to process request". If you include any string or object parameter, it will throw an error that can bubble down to your error handling middleware. You can try it yourself. Put return next('You are not authenticated.') in the catch block and you will see it halt the request before your route.
I use return next() because I handle authorization in the routes and in my resolvers. It allows more flexibility such as facilitating register and login mutations to be accessed by non-authenticated users.
Here is my GraphQL endpoint (I am using Apollo Server):
app.use('/graphql', bodyParser.json(), graphqlExpress((req) => {
const context = {
person: req.person
}
return {
schema,
context,
rootValue: null
}
}))
In my GraphQL resolvers, the third parameter of every query has context.person populated with req.person which comes from the above Authentication middleware.
That is really all a person needs to know.
Here is how I am using the NPM package called graphql-request:
https://www.npmjs.com/package/graphql-request
app.get('/allpeople', async (req, res) => {
try {
const client = new GraphQLClient(GRAPHQL_ENDPOINT, {
headers: { Authorization: req.headers.authorization || req.cookies.auth }
})
const query = `query allPeople($serialNumber: String!) {
allPeople(serialNumber: $serialNumber) {
id
created
status
email
}
}`
const variables = {
serialNumber: req.person
}
const response = await client.request(query, variables)
res.render('allpeople/list', { people: response.allPeople })
} catch (e) {
throw [`allPeople`, `${JSON.stringify(error, null, 2)}`]
}
})
I include this code because there are no "more advanced" example usages of graphql-request, and I like it so far. It is very concise and could easily be swapped out for Apollo Client if you venture into React.js. My examples here are also very relevant for anyone researching createNetworkInterface and new ApolloClient().

Node.js API - Allow users to only update and delete their own object

I am trying to build a RESTful API using Node.js w/ Express. I am fairly new to the MEAN stack, and want to use best practices. The concept I'm having trouble grasping and implementing is the following:
Restricting routes like PUT and DELETE on a user object, to only allow requests from users who 'own' this object.
One possibility I've thought of:
Creating secret token for users that matches token in DB
So when creating a user I assign them a token, store this in the DB and attach it to their session data.
Then my middleware would look something like:
router.put('/api/users/:user_id', function(req, res, next) {
// already unclear how this token should be transfered
var token = req.headers['x-access-token'] || req.session.token;
// update user (PUT /api/users/:user_id)
User.findById(req.params.user_id, function(err, user) {
if (err) {
res.send(err);
} else if (user.token != token) {
res.json({ sucess: false, message: 'User not same as authenticated user.' });
} else {
// set new information only if present in request
if (req.body.name) user.name = req.body.name;
if (req.body.username) user.username = req.body.username;
...
// save user
user.save(function(err) {
if (err) res.send(err);
// return message
res.json({ message: 'User updated.' });
});
}
});
Questions I have regarding best practice
Is the scenario I thought of at all plausible?
What data should I use to create a unique token for a user?
Is storing the token in the session the best solution?
Sidenote
This is a learning project for me, and I am aware of libraries like Passport.js. I want to learn the fundamentals first.
I have a repo for this project if you need to see some of the surrounding code I'm using: https://github.com/messerli90/node-api-ownership
Edit
I would accept a good RESTful API book recommendation, where these points are covered, as an answer.
Edit 2
I actually found a lot of the answers I was looking for in this tutorial: http://scottksmith.com/blog/2014/05/29/beer-locker-building-a-restful-api-with-node-passport/
I was trying to do this without the use of passport.js but a lot of the concepts covered in the article made some of the mechanics of an authorized API clear to me.
If I understand your question, this is an API, and the client (not a browser) is passing the secret token (api key) in the request, in a header. Seems reasonable. Of course, you must require https to protect the api key. And, you should have a way for users to revoke/regenerate their API key.
So far, I don't think you need to store anything in the session. It seems like storing the token in the session just complicates things. Presumably, if you are going to establish a session, the client has to include the token in the first request. So, why not just require it on each request and forget the session? I think this makes life simpler for the api client.
A 'bit' too late, but if someone is still looking for an answer, here is how i did it:
router.put('/', function(req, res) {
var token = req.headers['x-access-token'];
if (!token) return res.status(401).send({auth:false, message:'No token provided'});
jwt.verify (token, process.env.SECRET, function (err, decoded) {
if(err) return res.status(500).send({auth:false, message:'failed to auth token'});
User.findByIdAndUpdate({_id: decoded.user_id}, req.body, function(err, user) {
if (err)
res.send(err);
res.json({username: user.username, email: user.email});
});
});
});
Just pass the user id that is stored in the token to the mongoose function. This way the user who sent the request can only update or delete the model with his ID.
Reading material:
Implementing Access Control in Node.JS
Found this super clear article on how to allow users to only delete replies they own. Hope it helps.
What worked for me:
.delete(requireAuth, async (req, res, next) => {
const knexInstance = req.app.get("db");
const comment = await CommentsService.getById(knexInstance, req.params.id);
if (comment === undefined) {
return res.status(404).json({
error: {
message: `Comment doesn't exist.`
},
});
}
if (comment.users_id !== req.users.id) {
return res.status(401).json({
error: {
message: `You can only delete your own comments.`
},
});
}
CommentsService.deleteComment(knexInstance, req.params.id)
.then((numRowsAffected) => {
res.status(204).end();
})
.catch(next);
})

Resources