Using a config file for JWT secret in Node.js - javascript

I am learning Node.js, and while implementing JWT I want to put a separate config.js file to set the secret to generate and verify tokens, but I am having trouble with this.
First I create the config file as follows:
// JWT config
module.exports.jwt_secret = 'mysecret';
Then I require it at the API endpoint as:
const jwt_secret = require('../../../../../config');
And finally, I try to use it as follows:
jwt.verify(token, (jwt_secret), function(err, decoded) { ... }
But it does not work, so I tried a console.log with the jwt_secret, and I get this:
{ jwt_secret: 'mysecret' }
I checked code and searched here at Stack Overflow but I do not see how to solve this. I know probably it is pretty obvious but as I said I am quite new at programming and I am learning.
Thank you in advance.

Taking a quick look at the node-jsonwebtoken api, verify seems to expect a string as the second argument. The way that you've set up your export and require means that your variable jwt_secret is the entire exports object from your config module, not the string. Try changing it to
jwt.verify(token, jwt_secret.jwt_secret, function(err, decoded) { ... }
and if that works, you may want to modify your require statement to something like
const config = require('some/path/config');
and then use config.jwt_secret as the argument. That's just style though, do what works for your project.

Related

Error: Authentication code missing (Mongoose-encryption)

im getting this error while login a registred user
ofcourse i got this error after using dotenv package to secure my database encryption key
but proccess.env.SECRET is working currectly
i guess my problem is here :
userSchema.plugin(encrypt, {
secret: process.env.SECRET,
encryptedFields: ["password"],
});
app.js :
require("dotenv").config();
const express = require("express");
const bodyParser = require("body-parser");
const ejs = require("ejs");
const mongoose = require("mongoose");
const encrypt = require("mongoose-encryption");
const app = express();
app.use(express.static("public"));
app.set("view engine", "ejs");
app.use(bodyParser.urlencoded({ extended: true }));
mongoose.connect("mongodb://localhost:27017/userDB", {
useUnifiedTopology: true,
useNewUrlParser: true,
});
const userSchema = new mongoose.Schema({
email: String,
password: String,
});
//_
// encrypting password field // |
userSchema.plugin(encrypt, { // | i guess problem is here
secret: process.env.SECRET, // |
encryptedFields: ["password"], //_|
});
const User = mongoose.model("User", userSchema);
error :
Error: Authentication code missing
at Object.schema.methods.authenticateSync (C:\Users\Amir\Desktop\security\node_modules\mongoose-encryption\lib\plugins\mongoose-encryption.js:419:23)
at model.<anonymous> (C:\Users\Amir\Desktop\security\node_modules\mongoose-encryption\lib\plugins\mongoose-encryption.js:239:47)
at Kareem.execPreSync (C:\Users\Amir\Desktop\security\node_modules\kareem\index.js:115:16)
at model.syncWrapper [as $__init] (C:\Users\Amir\Desktop\security\node_modules\kareem\index.js:232:12)
at model.Document.init (C:\Users\Amir\Desktop\security\node_modules\mongoose\lib\document.js:513:8)
at completeOne (C:\Users\Amir\Desktop\security\node_modules\mongoose\lib\query.js:2853:12)
at model.Query.Query._completeOne (C:\Users\Amir\Desktop\security\node_modules\mongoose\lib\query.js:2094:7)
at Immediate.<anonymous> (C:\Users\Amir\Desktop\security\node_modules\mongoose\lib\query.js:2138:10)
at Immediate.<anonymous> (C:\Users\Amir\Desktop\security\node_modules\mquery\lib\utils.js:116:16)
at processImmediate (internal/timers.js:456:21)
I had the same problem and this worked for me:
Navigate to your database using your terminal using (as much I can see you use mongo) ex:
show dbs, use databaseName, show collections, db.databaseName.find() and then
Empty your database db.databaseName.drop() (If it is important stuff, then keep it somewhere safe so you can reuse it again, should be easy if you use Postman)
And recreate your database
You should delete the existing documents in your database and run the code again with an empty document.
Actually, the thing is that you might be using your new encryption on data which was stored before the addition of encryption , whereas if you check the same with the new data it will work fine , thus you should create a new database first so that you add new items in it , and it will hopefully work for you . :)
Well, I was facing with the same issue, but it occurs only to the data which you have stored in the database previously using mongoose-encryption without dotenv.
However, it works fine
when you create a new data by registering as new user.
Drop the database and create a new one. (Make sure you save the data before doing it).
:)
The reason is you might changed the "encryption key". If you can find out the one you made it at start, then you can still check and use this database in your (.js) file. However, "Error: Authentication code missing (Mongoose-encryption)" does not mean you destroy it. You still can use. Have a try!
Yes,
You should try to Drop your Database once and Start the server agein.
It may be possible that you have changed your encryption "secret" code a bit while transferring it to the .env file.
Don't forget to take backup before dropping it.
To fix this error, drop the collection you are trying to encrypt (with db.<collection-name>.drop() and create it again.
You are seeing this error because some of the data in your database is not encrypted while the rest of it is encrypted.
In my case, the error was triggered by the usage of findOneAndReplace.
I wanted to replace the record if it already existed in this way:
const newCredentials = { userId, securedCredentials};
await Credentials.findOneAndReplace({ userId }, newCredentials, {upsert:true});
I noticed that the code works if we try to add the object in the standard way:
await new Credentials(newCredentials).save();
Thus the problem is that we are trying to upsert a non-encrypted object. Ok, let's encrypt it then! I tried by calling the encrypt method, but that doesn't work
// The following line doesn't work. `encrypted` is undefined
const encrypted = await new Credentials(newCredentials).encrypt();
// This does work though...
const credentials = new Credentials(newCredentials);
credentials.encrypt((err) => {console.log(credentials)});
As I couldn't figure out how to do this in an atomic operation, I just went the long way:
await Credentials.deleteOne({userId});
await new Credentials(newCredentials).save();
If someone has an idea about how to atomize the operation, it would be great!
You don't have the MongoDB server port 27017 active on your system.
To do that, simply write "mongod" command in another tab of your hyper terminal.

Discord.js read client bot token from a file rather than hard-coded

I want to be able to read the client.login(BOT_TOKEN); dynamically from a file/database, but this is getting executed before my file read function finishes executing.
BOT_TOKEN = '';
if(BUILD_PROFILE == 'dev'){
filesystem.readFile('./../devToken.txt', 'utf8', (err, data) => {
if(err) throw err;
console.log(data);
BOT_TOKEN = data;
})
}
client.login(BOT_TOKEN);
This is the error I'm getting in logs - I have double checked the file and it's console.log(data) shows the right token, but it's not being applied
I suggest you place your token in an ENV file.
I also think you should copy your token directly from your bot's bot page on discord and pasting it directly.
You console.log'd the data was it the right token?
A very easy way to do this would be to have a config.js file in your main bot folder, and set out the
{
token: “token-here”
}
Then, in your main.js file, require the config file as a variable, then at your ‘bot.login’, just do ‘bot.login(config.token)’
You can also have your prefix set in this file too, allowing a user to possibly change your command prefix in the future
Additionally, you could use a SQLite database, that saves your token - you have to have the SQLite npm library, from https://www.npmjs.com/package/sqlite here, but it is very simple to set up, if anyone needs help here, add my discord Proto#4992
n.m. SQLite databases also will come in useful when/if you want to set up a currency system in the future.

Is it safe to use a single Mongoose database from two files/processes?

I've been working on a server and a push notification daemon that will both run simultaneously and interact with the same database. The idea behind this is that if one goes down, the other will still function.
I normally use Swift but for this project I'm writing it in Node, using Mongoose as my database. I've created a helper class that I import in both my server.js file and my notifier.js file.
const Mongoose = require('mongoose');
const Device = require('./device'); // This is a Schema
var uri = 'mongodb://localhost/devices';
function Database() {
Mongoose.connect(uri, { useMongoClient: true }, function(err) {
console.log('connected: ' + err);
});
}
Database.prototype.findDevice = function(params, callback) {
Device.findOne(params, function(err, device) {
// etc...
});
};
module.exports = Database;
Then separately from both server.js and notifier.js I create objects and query the database:
const Database = require('./db');
const db = new Database();
db.findDevice(params, function(err, device) {
// Simplified, but I edit and save things back to the database via db
device.token = 'blah';
device.save();
});
Is this safe to do? When working with Swift (and Objective-C) I'm always concerned about making things thread safe. Is this a concern? Should I be worried about race conditions and modifying the same files at the same time?
Also, bonus question: How does Mongoose share a connection between files (or processes?). For example Mongoose.connection.readyState returns the same thing from different files.
The short answer is "safe enough."
The long answer has to do with understanding what sort of consistency guarantees your system needs, how you've configured MongoDB, and whether there's any sharding or replication going on.
For the latter, you'll want to read about atomicity and consistency and perhaps also peek at write concern.
A good way to answer these questions, even when you think you've figured it out, is to test scenarios: Hammer a duplicate of your system with fake data and events and see if what happen is OK or not.

Node JS sending data via URL

Recently i started programming with Node JS and found it an amazing replacement for php . In php i used to send get requests with Data in the url .
Something like : http://sample.com/public.php?x=helloworld
How to perform something like this in Node JS or is there a better way to send data to node unlike using the url in the above case .
Also , I have noticed that in some cases like stackoverflow , queries are different and dont include the file name
like /public?= instead of /public.php?=
How is this achieved , i always thought this was something related to REST . Also , if you have the answer you might as well guide me if it could be done with Node and a few sources to learn could be of help too .
the most regular way to use REST api
req.query
// GET /search?q=foo+bar
req.query.q
// => "foo bar"
// GET /phone?order=desc&phone[color]=black&shoe[type]=apple
req.query.order
// => "desc"
req.query.phone.color
// => "black"
req.params
// GET /user/william
req.params.name
// => "william"
req.body(for form data)
// POST /login
req.body.username
// => "william"
req.body.password
// => "xxxxxx"
You'll probably be much better off using a pre-existing module as your web server. You can set one up manually, but you have to know about a lot of potential edge cases and really understand web servers. Most people in node use express. In node, as in any server-side language, you can pass data around in a few ways. The query string is one. You can also put some parameters directly in the url (like "/users/12" where 12 is a user id). Depending on the type of request, you can put data in the body of the request. You can also pass cookies. These are not node-specific. Explaining how express works in a post like this would be crazy, so I'll just give you a short example of a what a route handler matching your example route might look like:
var express = require('express');
var app = express();
app.get('/public', function(req, res, next) {
// Get the value from the query string. Express makes the query
// available as an object on the request parameter.
var x = req.query.x;
// Execute your main logic
doSomethingWithX(x);
// Send a response
res.status(200).json({ foo: 'bar' });
});

NodeJS Modulization

So, I was told that passing around the request and or response variable in nodeJS is "bad practice". But this means that most of your code has to be in the server.js file, making it cluttered and kind of ugly.
How can you modularize your nodejs server, passing around req/res appropriately and be able to organize your code into separate files?
For example, I would like to split my socket routing, .get and .post into different files, but still be able to use the callback parameters like so:
app.io.route("disconnect", function(req,res) { <--- these params
db.query("UPDATE player_data SET online=0 WHERE id="+mysql.escape(req.session.user));
req.io.broadcast("event", {msg:req.session.username+" has logged out!"});
app.io.broadcast("reloadXY");
});
As of right now they're all in one file and I don't like that.
I think what the person meant by 'passing around' was something like this (in plain express):
app.get('/kittens', function(req, res) {
db.doAthing(req);
updateSomethingElse(res);
upvoteThisAnswer(res);
});
That is, passing around the two variables beyond the first function. This is bad because it becomes increasingly difficult to figure out where the call actually ends. One little res.end(500) in updateSomethingElse can cause the whole house of cards to come tumbling down.
It's perfectly ok (in fact, standard to the point of being the default in express) to declare that callback elsewhere (usually the /routes directory of your project.)
// app.js
var user = require('./routes/user')
, kittens = require('./routes/kittens');
// express stuff...
app.get('/settings', user.getSettings);
app.get('/fur', kittens.shed);
Then, in routes/user.js:
exports.getSettings = function(req, res) {
// Note how we're passing around properties of req/res, not the objects themselves.
db.getUserSettings(req.user.id).then(function(settings) {
res.render('settings', settings);
});
};
This video from TJ Holowaychuk (the guy who wrote Express and a ton of other Node infrastructure that we all use) helped me take Express modularization to the next level. Basically you can make individual apps in their own folders and consume them as middleware very easily. I have managed to extend this technique to socket.io with some tricks.
http://vimeo.com/56166857
You should not pass req and res to another modules but pass callbacks from another modules to route.
It should look like.
var someModule = require("./someModule")
app.get("/someAction", someModule.handleSomeAction) ;
If You want to have post and get in another modules You should pass reference to app (from express()) once to that module and operate on that.
For example :
var express = require("express") ;
var app = express();
var get_handler = require("./get_handler ")
var post_handler = require("./post_handler ")
get_handler.init(app);
post_handler.init(app);
and in post/get_handler :
var app;
exports.init = function( eApp){
app = eApp;
// operate on app
}

Categories