I'm trying to log users with Client Credentials Flow with Simple-OAuth2 in a NodeJS website.
My routes/index.js is this:
var express = require('express');
var router = express.Router();
var authHelper = require('../helpers/auth');
router.get('/', async function(req, res, next) {
let parms = { title: 'Home', active: { home: true } };
const accessToken = await authHelper.accessToken;
res.render('index', parms);
});
module.exports = router;
And my auth.js is this:
const credentials = {
client: {
id: process.env.APP_ID,
secret: process.env.APP_PASSWORD,
},
auth: {
tokenHost: 'https://login.microsoftonline.com',
authorizePath: "common/oauth2/v2.0/authorize",
tokenPath: "common/oauth2/v2.0/token",
}
};
const oauth2 = require('simple-oauth2').create(credentials);
const tokenConfig = {
username: 'uuuuuu#dddddd.com',
password: 'ppppppp',
scope: process.env.APP_SCOPES,
};
try {
const result = await oauth2.ownerPassword.getToken(tokenConfig);
const accessToken = oauth2.accessToken.create(result);
} catch (error) {
console.log('Access Token Error', error.message);
}
exports.accessToken = accessToken;
When I try to start website, nodejs shows me a sintax error:
const result = await oauth2.ownerPassword.getToken(tokenConfig);
^^^^^
SyntaxError: await is only valid in async function
This error does not make much sense to me since the code is provided by simple-oauth2.
Could someone shed light on my actual error?
Well you have to wrap your code into async function so you could use await key word in that function. You cna find more info here.
In your case I would wrap code into function and export that function like this:
const credentials = {
client: {
id: process.env.APP_ID,
secret: process.env.APP_PASSWORD,
},
auth: {
tokenHost: 'https://login.microsoftonline.com',
authorizePath: "common/oauth2/v2.0/authorize",
tokenPath: "common/oauth2/v2.0/token",
}
};
const oauth2 = require('simple-oauth2').create(credentials);
const tokenConfig = {
username: 'uuuuuu#dddddd.com',
password: 'ppppppp',
scope: process.env.APP_SCOPES,
};
const getAccessToken = async () => {
try {
const result = await oauth2.ownerPassword.getToken(tokenConfig);
const accessToken = oauth2.accessToken.create(result);
return accessToken;
} catch (error) {
console.log('Access Token Error', error.message);
return null;
}
};
exports.getAccessToken = getAccessToken;
And then you can use that function like this:
var express = require('express');
var router = express.Router();
var authHelper = require('../helpers/auth');
router.get('/', async function(req, res, next) {
let parms = { title: 'Home', active: { home: true } };
const accessToken = await authHelper.getAccessToken();
res.render('index', parms);
});
module.exports = router;
Related
I'm trying to develop a verifyTokenAdmin middleware, however when testing in my postman, it is returned to me error
TypeError: Cannot read properties of undefined (reading 'isAdmin') JWT token
I would like to have a token for a check if isAdmin is true, and consequently authenticate my route. In theory in the user I don't have null, pos isAdmin starts as false by default.
middleware
const jwt = require('jsonwebtoken');
const verifyToken = (req, res, next) => {
const { authorization } = req.headers;
if (!authorization) {
return res.status(401).json('Invalid Authorization')
};
const token = authorization.replace('Bearer', ' ').trim();
try {
const secret = process.env.JWT_SECRET;
const data = jwt.verify(token, secret);
const { id } = data;
req.userId = id;
return next();
} catch (err) {
return res.status(400).json(err);
}
};
verifyAdmin = (req, res, next) => {
if (req.Users.isAdmin) {
next();
} else {
return res.status(403).json("You are not alowed to do that!");
}
}
module.exports = {
verifyToken,
verifyAdmin,
};
route
const router = require('express').Router();
const CreateUserController = require('../controllers/UserController/CreateUser');
const FindAllUsersController = require('../controllers/UserController/FindAllUsers');
const { verifyToken, verifyAdmin } = require('../middlewares/verifyToken');
router.post('/', CreateUserController.store);
router.get('/', verifyToken, verifyAdmin, FindAllUsersController.index);
module.exports = router;
model user
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class User extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
}
}
User.init({
firstName: DataTypes.STRING,
lastName: DataTypes.STRING,
email: DataTypes.STRING,
password: DataTypes.STRING,
phoneNumber: DataTypes.STRING,
isAdmin: DataTypes.BOOLEAN
}, {
sequelize,
modelName: 'User',
});
return User;
};
The table is saved as "Users" in the database.
You need to add one line in your middleware file:
const verifyToken = (req, res, next) => {
const { authorization } = req.headers;
if (!authorization) {
return res.status(401).json('Invalid Authorization')
};
const token = authorization.replace('Bearer', ' ').trim();
try {
const secret = process.env.JWT_SECRET;
const data = jwt.verify(token, secret);
req.users = data; //add this new line in your code
const { id } = data;
req.userId = id;
return next();
} catch (err) {
return res.status(400).json(err);
}
};
Hi I'm making a login server there is an error There's an error when I make a declaration. const createToken what can I do How can I change that code? What's the problem and how to solve and why? can you explain me thank you very much
isRefresh.js
const jwt = require("jsonwebtoken");
const { createToken } = require("../utils/jwt");
const db = require("../database/db");
const createToken = (payload) => {
console.log("createToken");
const token = jwt.sign({ username: payload.toString() }, secretKey, {
algorithm: "sha256",
expiresIn: "30m",
});
return token;
};
module.exports = async (req, res, next) => {
try {
const refreshtoken = req.get("r_x_auth");
if (!refreshtoken) {
return false;
}
const decodedToken = jwt.verify(refreshtoken, R_secretKey);
const data = [decodedToken.username];
const sql = "select * from member where user_id = ?";
const conn = await db.getConnection();
const [rows] = await conn.query(sql, data);
if (rows) {
const newtoken = createToken(rows[0].username);
res.send(newtoken);
} else {
return false;
}
} catch (err) {
next(err);
}
};
jwt.js
const jwt = require("jsonwebtoken");
const { ACCESS_KEY, REFRESH_KEY } = process.env;
const createToken = (payload) => {
const token = jwt.sign({ username: payload.toString() }, ACCESS_KEY, {
algorithm: "sha256",
expiresIn: "30m",
});
return token;
};
const creatRefreshToken = (payload) => {
const retoken = jwt.sign({ username: payload.toString() }, REFRESH_KEY, {
algorithm: "sha256",
expiresIn: "1d",
});
return retoken;
};
module.exports = { createToken, creatRefreshToken };
isAuth.js
const jwt = require("jsonwebtoken");
require("dotenv").config();
const secretKey = process.env.ACCESS_KEY;
const db = require("../database/db");
module.exports = async (req, res, next) => {
try {
const token = req.get("x_auth");
const decodedToken = jwt.verify(token, secretKey);
const { username } = decodedToken;
const data = [username];
const sql = "select * from member where username = ?";
const conn = await db.getConnection();
const [rows] = await conn.query(sql, data);
if (!rows) {
return false;
}
next();
} catch (err) {
next(err);
}
};
controller.js
const jwt = require("jsonwebtoken");
require("dotenv").config();
const secretKey = process.env.ACCESS_KEY;
const db = require("../database/db");
module.exports = async (req, res, next) => {
try {
const token = req.get("x_auth");
const decodedToken = jwt.verify(token, secretKey);
const { username } = decodedToken;
const data = [username];
const sql = "select * from member where username = ?";
const conn = await db.getConnection();
const [rows] = await conn.query(sql, data);
if (!rows) {
return false;
}
next();
} catch (err) {
next(err);
}
};
Anyone please help thanks !
please please help me
I'm clueless save me
Error message is clean as it should be: you defined createToken twice on same module level.
Rename one of them, for example:
const createTokenJWT = require("../utils/jwt").createToken;
You are declaring createToken twice:
const { createToken } = require("../utils/jwt");
and here:
const createToken = (payload) => {
console.log("createToken");
const token = jwt.sign({ username: payload.toString() }, secretKey, {
algorithm: "sha256",
expiresIn: "30m",
});
return token;
};
the below code returns not found (404) all the time. But the console logs the data as expected.
I am using Node, Koa, and Mongoose.
the server.js
const Koa = require('koa');
const bodyparser = require('koa-bodyparser');
const UserRoutes = require('./router/user.routes');
const TrustRoutes = require('./router/trust.routes');
const auth = require('./middleware/auth');
const app = new Koa();
require('dotenv').config();
require('./db');
app.use(bodyparser());
app.use(auth);
app.use(
TrustRoutes.routes()
).use(TrustRoutes.allowedMethods());
app.use(
UserRoutes.routes()
).use(UserRoutes.allowedMethods());
app.listen(process.env.PORT || 3000);
trust.routes.js
const router = new Router({
prefix: '/trust'
});
router.get('/:trustId', async (ctx,next) => {
let id = ctx.params.trustId;
let trust = await Trust.findById(id);
console.log(trust);
ctx.response.body = {
status: true,
message: 'Trust info',
data: trust
};
console.log('trust info');
next();
});
module.exports = router
the console logs the below details
{
_id: new ObjectId("61ed34100ebd7c8fbdbef596"),
name: 'new trust',
description: 'match',
contact: { email: 'gmail#gmail.com', phone: '90334' },
isActive: true,
createdAt: 2022-01-23T10:55:12.866Z,
updatedAt: 2022-01-23T10:55:12.866Z,
__v: 0
}
trust info
and the middleware (I suspect in here)
require('dotenv').config();
const jwt = require("jsonwebtoken");
const User = require("../models/user")
const except = [
'/user/login'
];
const verifyToken = async (ctx, next) => {
if (except.indexOf(ctx.request.path) >= 0) return next();
let token = (
ctx.request.body.token || ctx.request.query.token ||
ctx.request.headers["authorization"]
);
if (!token) {
ctx.response.status = 403;
ctx.body = {
status: false,
message: 'Unauthorized'
}
return;
}
token = token.replace(/^Bearer\s+/,'');
try {
const decoded = jwt.verify(token, process.env.TOKEN_KEY);
const user = await User.findOne({
email: decoded.username
},{password: 0});
ctx.request.user = user;
} catch (err) {
ctx.response.status = 403;
ctx.body = {
status: false,
message: 'Unauthorized'
}
return;
}
next();
};
module.exports = verifyToken;
I know that something in here is not correct but hard to understand since it's my first time on these async and koa with middleware please help me out on this.
the postman
You don't export anything from your router-file. In order to use
app
.use(TrustRoutes.routes())
.use(TrustRoutes.allowedMethods());
you need to export the koa-router from the TrustRoutes-file:
const router = new Router({
prefix: '/trust'
});
router.get('/:trustId', async (ctx,next) => {
// ...
});
module.exports = router;
Apart from this when using async handlers, you need to either return next or await (see https://github.com/ZijianHe/koa-router/issues/476):
router.get('/:trustId', async (ctx,next) => {
// ...
return next(); // or await next();
});
I missed to have return next() in auth js the middleware.
After updating it next(); to return next() it works.
const verifyToken = async (ctx, next) => {
.....
return next();
};
When calling my PUT method, I got this error:
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<h1>Forbidden</h1>
<p>You don't have permission to access this resource.</p>
</body>
</html>
I have some jwt authentification, so I put my complete code here:
It works with GET and POST methods
const express = require('express');
const logger = require('morgan');
var fs = require('fs');
var https = require('https');
var privateKey = fs.readFileSync('/etc/letsencrypt/live/hidden/privkey.pem', 'utf8');
var certificate = fs.readFileSync('/etc/letsencrypt/live/hidden/fullchain.pem', 'utf8');
const util = require('util')
var credentials = {key: privateKey, cert: certificate};
var queryString = require('querystring');
const bodyParser = require('body-parser');
const app = express();
const jwt = require('jsonwebtoken');
// import passport and passport-jwt modules
const passport = require('passport');
const passportJWT = require('passport-jwt');
const bcrypt = require('bcryptjs');
const Sequelize = require('sequelize');
var httpProxy = require('http-proxy');
var apiProxy = httpProxy.createProxyServer();
var backend = 'http://localhost:8484';
// initialize an instance of Sequelize
const sequelize = new Sequelize({
//hiden///
});
// ExtractJwt to help extract the token
let ExtractJwt = passportJWT.ExtractJwt;
// JwtStrategy which is the strategy for the authentication
let JwtStrategy = passportJWT.Strategy;
let jwtOptions = {};
jwtOptions.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
jwtOptions.secretOrKey = 'hidden';
// lets create our strategy for web token
let strategy = new JwtStrategy(jwtOptions, function(jwt_payload, next) {
console.log('payload received', jwt_payload);
let user = getUser({ id: jwt_payload.id });
if (user) {
next(null, user);
} else {
next(null, false);
}
});
// use the strategy
passport.use(strategy);
app.use(passport.initialize());
app.use(logger(':date[iso] :method :url :status :response-time ms - :res[content-length]'));
// parse application/json
app.use(bodyParser.json());
//parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));
// check the databse connection
sequelize
.authenticate()
.then(() => console.log('Connection has been established successfully.'))
.catch(err => console.error('Unable to connect to the database:', err));
// create user model
const User = sequelize.define('user', {
name: {
type: Sequelize.STRING,
allowNull: false
},
code_event: {
type: Sequelize.INTEGER,
allowNull: false
},
password: {
type: Sequelize.STRING,
allowNull: false
},
});
// create table with user model
User.sync()
.then(() => console.log('User table created successfully'))
.catch(err => console.log('did you enter wrong database credentials?'));
// create some helper functions to work on the database
const createUser = async ({ name, password, code_event }) => {
try{
return await User.create({ name, password, code_event });
}
catch (error) {
// your catch block code goes here
}
};
const getAllUsers = async () => {
try{
return await User.findAll();
}
catch (error) {
// your catch block code goes here
}
};
const getUser = async obj => {
try{
return await User.findOne({where: obj,});
}
catch (error) {
// your catch block code goes here
}
};
// get all users
app.get('/users', function(req, res) {
getAllUsers().then(user => res.json(user));
});
// register route
app.post('/register', function(req, res, next) {
console.log(req.body);
let { name, password, code_event } = req.body;
bcrypt.genSalt(10, (err, salt) => {
if(err) throw err;
bcrypt.hash(password, salt,
(err, hash) => {
if(err) throw err;
password = hash;
createUser({ name, password, code_event }).then(user =>
res.json({ user, msg: 'account created successfully' })
)
.catch(err => res.status(400).json(err));
});
});
});
// login route
app.post('/login', async function(req, res, next) {
console.log(req.body);
const { name, password , code_event} = req.body;
if (name && password) {
// we get the user with the name and save the resolved promise returned
let user = await getUser({ name, code_event});
if (!user) {
res.status(401).json({ msg: 'No such user found', user });
}
bcrypt.compare(password, user.password)
.then(isMatch => {
if (isMatch) {
const payload = {id: user._id};
// let token = jwt.sign(payload, jwtOptions.secretOrKey, { expiresIn: 36000 }, (err, token) => {
// if (err) res.status(500).json({ error: "Error signing token", raw: err });
// res.json({ msg: 'ok', token: token });
// });
let token = jwt.sign(payload, jwtOptions.secretOrKey);
res.json({ msg: 'ok', token: token });
} else {
res.status(401).json("Password is incorrect");
}
});
}
});
apiProxy.on( 'proxyReq', ( proxyReq, req, res, options ) => {
console.log("body " +util.inspect(req.body, false, null, true /* enable colors */));
if ( !req.body || !Object.keys( req.body ).length ) {
return;
}
let contentType = proxyReq.getHeader( 'Content-Type' );
let bodyData;
if ( contentType.includes( 'application/json' ) ) {
bodyData = JSON.stringify( req.body );
}
if ( contentType.includes( 'application/x-www-form-urlencoded' ) ) {
bodyData = queryString.stringify( req.body );
}
if ( bodyData ) {
proxyReq.setHeader( 'Content-Length', Buffer.byteLength( bodyData ) );
proxyReq.write( bodyData );
}
});
app.all("/*", passport.authenticate('jwt', { session: false }), function(req, res) {
console.log("req all" + req);
apiProxy.web(req, res, {target: backend});
});
app.on('upgrade', function (req, socket, head) {
console.log("req on" + req);
apiProxy.ws(req, socket, head, {target: backend});
});
var httpsServer = https.createServer(credentials, app);
// start the app
httpsServer.listen(8383, function() {
console.log("Express is running on port 3000");
});
It works with my POST methods.
I don't know where it goes because, when calling a method, I should have a trace in my log files. I can see POST ot GET calls but not PUT ones.
Any ideas?
the question is pretty self explanatory. I am registering/signing up users in a mongoDB database. They are being registered fine and an accesstoken [jwt based] is also being generated.
Now, when I go to query the database to fetch the list of users I am getting that error -
jwt is not defined.
It is worthwhile to mention that users also in my backend can have two type of roles - basic and admin. And only an admin user can fetch list of all users by sending accessToken in the header as Bearer authorization parameter.
I have 2 main files in my backend project structure that uses jwt.access methods like jwt.verify or jwt.signIn; these are the server.js and userController.js [a separate file where I have written all individual db related methods].
As far as I am concerned, all necessary packages are there in my project - express, node, jwa, jws, jsonwebtoken, mongo, mongoose, bcrypt, cors etc. So what is the trouble?
My route.js -->
const User = require('../models/user.model');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const { roles } = require('../models/roles');
const JWT_SECRET = "$#GR24T4344$#$##%ETWWTEME%$6";
async function hashPassword(password) {
return await bcrypt.hash(password, 10);
}
async function validatePassword(plainPassword, hashedPassword) {
return await bcrypt.compare(plainPassword, hashedPassword);
}
exports.grantAccess = function (action, resource) {
return async (req, res, next) => {
try {
const permission = roles.can(req.user.role)[action](resource);
if (!permission.granted) {
return res.status(401).json({
error: "You don't have enough permission to perform this action"
});
}
next();
} catch (error) {
next(error);
}
}
}
exports.allowIfLoggedin = async (req, res, next) => {
try {
const user = res.locals.loggedInUser;
if (!user)
return res.status(401).json({
error: "You need to be logged in to access this route"
});
req.user = user;
next();
} catch (error) {
next(error);
}
}
exports.signup = async (req, res, next) => {
try {
const { role, email, password } = req.body;
const hashedPassword = await hashPassword(password);
const newUser = new User({ email, password: hashedPassword, role: role || "basic" });
const accessToken = jwt.sign({ userId: newUser._id }, JWT_SECRET, {
expiresIn: "1d"
});
newUser.accessToken = accessToken;
await newUser.save();
res.json({
data: newUser,
message: "You have signed up successfully"
});
} catch (error) {
next(error);
}
}
exports.login = async (req, res, next) => {
try {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user)
return next(new Error('Email does not exist'));
const validPassword = await validatePassword(password, user.password);
if (!validPassword)
return next(new Error('Password is not correct'));
const accessToken = jwt.sign({ userId: user._id }, JWT_SECRET, {
expiresIn: "1d"
});
await User.findByIdAndUpdate(user._id, { accessToken });
res.status(200).json({
data: { email: user.email, role: user.role },
accessToken
});
} catch (error) {
next(error);
}
}
exports.getUsers = async (req, res, next) => {
const users = await User.find({});
res.status(200).json({
data: users
});
}
exports.getUser = async (req, res, next) => {
try {
const userId = req.params.userId;
const user = await User.findById(userId);
if (!user)
return next(new Error('User does not exist'));
res.status(200).json({
data: user
});
} catch (error) {
next(error);
}
}
exports.updateUser = async (req, res, next) => {
try {
const { role } = req.body;
const userId = req.params.userId;
await User.findByIdAndUpdate(userId, { role });
const user = await User.findById(userId);
res.status(200).json({
data: user
});
} catch (error) {
next(error);
}
}
exports.deleteUser = async (req, res, next) => {
try {
const userId = req.params.userId;
await User.findByIdAndDelete(userId);
res.status(200).json({
data: null,
message: 'User has been deleted'
});
} catch (error) {
next(error);
}
}
My server.js -->
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const PORT = 4000;
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const playerRoutes = express.Router();
const userRoutes = express.Router();
const userController = require('./controllers/userController');
const user_routes = require('./apiroutes/route');
const app = express();
const JWT_SECRET = "$#GR24T4344$#$##%ETWWTEME%$6";
const users = "users";
require("dotenv").config({path: __dirname+ '../.env'});
let Player = require('./models/player.model');
let User = require('./models/user.model');
app.use(cors());
app.use(bodyParser.json());
app.use(
bodyParser.urlencoded({
extended: false
})
);
mongoose.connect('mongodb://127.0.0.1:27017/playerDB', function (err, db) {
if (err)
throw err;
db.createCollection(users, function (err, resp) {
if (err)
throw err;
console.log("Collection created!");
});
}, { useNewUrlParser: true });
const connection = mongoose.connection;
connection.once('open', function () {
console.log("MongoDB database connection established successfully");
});
..... blablablaaaa
app.use('/playerDB', playerRoutes);
app.use(async (req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
if (req.headers["x-access-token"]) {
try {
const accessToken = req.headers["x-access-token"];
const { userId, exp } = await jwt.verify(accessToken, JWT_SECRET);
// If token has expired
if (exp < Date.now().valueOf() / 1000) {
return res.status(401).json({
error: "JWT token has expired, please login to obtain a new one"
});
}
res.locals.loggedInUser = await User.findById(userId);
next();
} catch (error) {
next(error);
}
} else {
next();
}
});
app.use('/users', user_routes);
app.listen(PORT, function () {
console.log("Server is running on Port: " + PORT);
});
I hope you understand my approach and scenario? Can you guess, where it could have gone wrong? Any idea?
Missing npm packages or something more critical?
Look forward to some hints on this problem! Can't seem to figure out a way!
it seems you forgot to add this line to server.js
const jwt = require('jsonwebtoken');
While register and login, this didn't caused a problem, because for these requests, req.headers["x-access-token"] was null, and the code didn't reach the if block where you used jwt, but one a request with this header came (like getUsers) the code tried to use jwt.verify, but since jwt wasn't imported it gave error.