I am using mongoose and passport-local for my strategy. With Redux I dispatch an action to register a user and it works fine. After I register I want to use those same credentials to log the user in.
I have login working with JWT but it's not hitting any backend, only a users object. I'm wondering how I can use passport to authenticate with my mongo backend, give a success response, and then I can keep using my current setup to issue the JWT. I know I can probably rework this to be cleaner and use passport only but I have this working so far and I'd like to only connect it to a real database now that registerUser successfully uses.
./server/models/account.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var passportLocalMongoose = require('passport-local-mongoose');
var Account = new Schema({
username: String,
password: String
});
Account.plugin(passportLocalMongoose);
module.exports = mongoose.model('Account', Account);
./index.js (server entry point)
var bodyParser = require('body-parser')
// db
var db = require('./server/db'); // just db url
var mongoose = require('mongoose');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var Account = require('./server/models/account');
var app = new (require('express'))()
var port = 3000
// webpack stuff went here
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(passport.initialize());
app.get("/", function(req, res) {
res.sendFile(__dirname + '/client/index.html')
})
passport.use(new LocalStrategy(Account.authenticate()));
mongoose.connect(db.url);
app.use(require('./server/routes')); <------------------------------ file below
app.listen etc
./server/routes.js
var express = require('express'),
_ = require('lodash'),
config = require('./config'),
jwt = require('jsonwebtoken');
var app = module.exports = express.Router();
// XXX: This should be a database of users :).
var users = [{ <----------------------------dummy account
id: 1,
username: 'test',
password: 'test'
}];
function createToken(user) {
return jwt.sign(_.omit(user, 'password'), config.secret, { expiresIn: 60*60*5 });
}
function getUserScheme(req) {
var username;
var type;
var userSearch = {};
-- error stuff --
return {
username: username,
type: type,
userSearch: userSearch
}
}
app.post('/sessions/create', function(req, res) {
var userScheme = getUserScheme(req);
-- error stuff --
res.status(201).send({
id_token: createToken(user)
});
});
./client/actions/index.js - actions that get called to register/login (register works with mongo, login only works with a dummy object)
export function registerUser(creds) {
let config = {
method: 'POST',
headers: { 'Content-Type':'application/x-www-form-urlencoded' },
body: `username=${creds.username}&password=${creds.password}`
}
return dispatch => {
// dispatch(requestLogin(creds))
return fetch('http://localhost:3000/register', config)
.then((response) => {
if (!response.ok) { console.log("err"); }
else { dispatch(loginUser(creds)) }
}).catch(err => console.log("Error: ", err))
}
}
// Calls the API to get a token and
// dispatches actions along the way
export function loginUser(creds) {
let config = {
method: 'POST',
headers: { 'Content-Type':'application/x-www-form-urlencoded' },
body: `username=${creds.username}&password=${creds.password}`
}
return dispatch => {
// We dispatch requestLogin to kickoff the call to the API
// console.log(creds)
dispatch(requestLogin(creds))
return fetch('http://localhost:3000/sessions/create', config)
.then(response =>
response.json()
.then(user => ({ user, response }))
)
.then(({ user, response }) => {
if (!response.ok) {
// If there was a problem, we want to
// dispatch the error condition
dispatch(loginError(user.message))
return Promise.reject(user)
}
else {
// If login was successful, set the token in local storage
localStorage.setItem('id_token', user.id_token)
// Dispatch the success action
dispatch(receiveLogin(user))
}
}).catch(err => console.log("Error: ", err))
}
}
I guess you need something like:
export const passportJWT = function (passport) {
passport.use(new JwtStrategy({
jwtFromRequest: ExtractJwt.fromAuthHeader(),
secretOrKey: config.JwtSecret,
}, (jwtPayload, done) => {
Account.findOne({ username: jwtPayload.username}, (err, account) => {
if (err) return done(err, false);
if (user) {
return done(null, account);
}
return done(null, false);
});
}));
};
and
export const JWTAuthentication = (req, res, next) => {
passport.authenticate('jwt', { session: false })(req, res, next);
};
then use this middleware for the routes that needs JWT authentication.
like:
yourRouter.get('/login', JWTAuthentication, (req, res) => {
//if jwt authentication passed
//you can access user object as req.user
});
Related
I have been in the process of building a server using node.js, express.js, Mongoose, and MongoDB. After trying to implement passport and JWT authentication, I have encountered an error (seen in the link) every time I try to make a request to my '/login' endpoint. This error occurs when I make a request through Postman using a username and password from my database to test if the user is assigned a JWT token.
https://i.stack.imgur.com/g6e4Z.png
All of my endpoints, except for the one in my auth.js file, work fine in my index.js file, which is the main file where everything gets imported. I do not have any problems getting/staying connected to my database, so this leads me to believe that the issue stems from some mistake in the error handling.
This is how the middleware is set up in the index.js file, right above my endpoints.
'use strict';
const express = require('express');
const morgan = require('morgan');
const mongoose = require('mongoose');
const Models = require('./models');
const Movies = Models.Movie;
const Genres = Models.Genre;
const Directors = Models.Director;
const Users = Models.User;
function displayErrorMsg(err) {
console.error(err);
res.status(500).send(`Error: ${err}`);
}
function resJSON(model, res) {
return model.find().then(data => res.json(data));
}
const app = express();
mongoose
.connect('mongodb://localhost:27017/filmfeverDB', {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(res => console.log('DB Connected!'))
.catch(err => console.log(err, err.message));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static(`public`));
app.use(morgan('common'));
let auth = require('./auth')(app);
const passport = require('passport');
require('./passport');
passport.js
const passport = require("passport"),
LocalStrategy = require("passport-local").Strategy,
Models = require("./models.js"),
passportJWT = require("passport-jwt"),
config = require('./configs').config
let Users = Models.User,
JWTStrategy = passportJWT.Strategy,
ExtractJWT = passportJWT.ExtractJwt;
passport.use(
new LocalStrategy(
{
usernameField: "Username",
passwordField: "Password"
},
(username, password, callback) => {
console.log(username + " " + password);
Users.findOne({ Username: username }, (error, user) => {
if (error) {
console.log(error);
return callback(error);
}
if (!user) {
console.log("incorrect username");
return callback(null, false, {
message: "Incorrect username."
});
}
console.log("finished");
return callback(null, user);
});
}
)
);
passport.use(
new JWTStrategy(
{
jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken(),
secretOrKey: config.passport.secret
},
(jwtPayload, callback) => {
return Users.findById(jwtPayload._id)
.then(user => {
return callback(null, user);
})
.catch(error => {
return callback(error);
});
}
)
);
auth.js
const jwt = require("jsonwebtoken"),
passport = require("passport");
require("./passport");
let generateJWTToken = user => {
return jwt.sign(user, config.passport.secret, {
subject: user.Username,
expiresIn: config.passport.expiresIn,
algorithm: "HS256"
});
};
/* POST login. */
module.exports = router => {
router.post("/login", (req, res) => {
passport.authenticate("local", { session: false }, (error, user, info) => {
if (error || !user) {
return res.status(400).json({
message: "something is not right",
user: user
});
}
req.login(user, { session: false }, error => {
if (error) {
res.send(error);
}
let token = generateJWTToken(user.toJSON());
return res.json({ user, token });
});
})(req, res);
});
};
Here is my Mongoose connection and my imports of the auth.js, passport.js, and passport module files located in my index.js file.
mongoose
.connect('mongodb://localhost:27017/filmfeverDB', {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(res => console.log('DB Connected!'))
.catch(err => console.log(err, err.message));
let auth = require('./auth')(app);
const passport = require('passport');
require('./passport');
If anyone has any ideas, please let me know.
I have created a login form that should redirect the user to a dashboard page in case he enters the right password and username. If the user tries to navigate to the dashboard url without being logged in the page should not display as it is a protected route. I am trying to send a jwt token when the user logs in, but that doesn't work I just get the Forbidden message when I log in so it seems that the token is not sent correctly, how can I send the jwt token and access the protected route once the user logs in successfully?
Here is my server.js:
const express = require('express');
const jwt = require('jsonwebtoken');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
let Post = require('./models/post.model.js');
const app = express();
const cors = require('cors');
require('dotenv').config();
app.use(cors());
app.use("/assets", express.static(__dirname + "/assets"));
app.use(bodyParser.urlencoded({ extended: true }));
const BASE_URL = process.env.BASE_URL;
const PORT = process.env.PORT || 1337;
mongoose.connect(BASE_URL, { useNewUrlParser: true, useUnifiedTopology: true })
const connection = mongoose.connection;
connection.once('open', function () {
console.log('Connection to MongoDB established succesfully!');
});
app.set('view-engine', 'ejs');
app.get('/', (req, res) => {
res.render('index.ejs');
});
app.post('/', (req, res) => {
let username = req.body.username;
let password = req.body.password;
const user = {
username: username,
password: password
}
jwt.sign({ user }, process.env.SECRET_KEY, (err, token) => {
res.json({
token
})
});
if (username !== process.env.USER_NAME && password !== process.env.USER_PASSWORD) {
res.json('Invalid credentials');
} else {
res.setHeader('Authorization', 'Bearer '+ token);
res.redirect('/dashboard')
}
});
app.get('/dashboard', verifyToken, (req, res) => {
jwt.verify(req.token, process.env.SECRET_KEY, (err, authData) => {
if (err) {
res.sendStatus(403);
} else {
res.sendStatus(200);
}
});
res.render('dashboard.ejs');
});
app.get('/dashboard/createPost', verifyToken, (req, res) => {
res.render('post.ejs');
});
app.post('/dashboard/createPost', async (req, res) => {
let collection = connection.collection(process.env.POSTS_WITH_TAGS);
res.setHeader('Content-Type', 'application/json');
let post = new Post(req.body);
collection.insertOne(post)
.then(post => {
res.redirect('/dashboard')
})
.catch(err => {
res.status(400).send(err);
});
});
// TOKEN FORMAT
// Authorization: Bearer <access_token>
//Verifing the Token
function verifyToken(req, res, next) {
// Get auth header value
const bearerHeader = req.headers['authorization'];
// Check if bearer is undefined
if (typeof bearerHeader !== 'undefined') {
// Spliting the bearer
const bearer = bearerHeader.split(' ');
// Get token from array
const bearerToken = bearer[1];
// Set the token
req.token = bearerToken;
// Next middleware
next();
} else {
// Forbid the route
res.sendStatus(403);
}
}
app.listen(PORT);
see this example, i use middleware(checkAuthLogin), this code contains all thing for your question:
index.js:
const express = require('express');
const app = express();
require('./db/mongoose');
const userRouter = require('./routers/user');
app.use(express.json());
app.use(userRouter);
app.listen(3000, ()=> {
console.log('Server is up on port ', 3000)
});
db/mongoose.js:
const mongoose = require('mongoose');
mongoose.connect("mongodb://127.0.0.1:27017/db-test" {
useNewUrlParser : true,
useCreateIndex : true,
useFindAndModify : false,
useUnifiedTopology: true
});
routers/user.js:
const express = require('express');
const router = new express.Router();
const RootUser = require('../models/root-user');
const {checkRootLogin} = require('../middleware/checkAuthLogin');
router.post('/createrootuser', async (req, res) => {
const updates = Object.keys(req.body);
const allowedUpdatesArray = ['name', 'password'];
const isValidOperation = updates.every((update) => allowedUpdatesArray.includes(update));
if (!isValidOperation) {
return res.status(400).send({error: 'Invalid Request Body'})
}
const rootUser = new RootUser(req.body);
try {
await rootUser.save();
// sendWelcomeEmail(user.email, user.name)
const token = await rootUser.generateAuthToken();
//console.log(user)
res.status(201).send({rootUser, token});
} catch (e) {
res.status(400).send(e)
}
});
//use this middleware(checkRootLogin) for check root user can access this function
router.post('/rootconfig', checkRootLogin, async (req, res) => {
res.status(200).send({success: 'success add root config'})
});
module.exports = router;
model/root-user.js:
const mongoose = require('mongoose');
const validator = require('validator');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const userRootSchema = new mongoose.Schema({
name: {
type : String,
required: true,
unique : true,
trim : true,
lowercase : true,
},
password: {
type : String,
required: true,
unique : true,
trim : true,
lowercase : true,
minlength : 6,
validate (value) {
//if (validator.contains(value.toLowerCase(), 'password')){
if (value.toLowerCase().includes('password')){
throw new Error('Password can not contained "password"')
}
}
},
tokens : [{
token : {
type : String ,
required : true
}
}],
}, {
timestamps: true
});
userRootSchema.methods.generateAuthToken = async function(){
const root = this;
// generate token
try {
// const token = jwt.sign({ _id : user._id.toString()}, process.env.JWT_SECRET);
const token = jwt.sign({ _id : root._id.toString()}, "test");
// add token to user model
root.tokens = root.tokens.concat({ token });
await root.save();
return token
} catch (e){
throw new Error(e)
}
};
userRootSchema.pre('save', async function(next){
// this give ccess to individual user
const user = this;
if (user.isModified('password')){
user.password = await bcrypt.hash(user.password, 8)
}
next()
});
const UserRoot = mongoose.model('UserRoot', userRootSchema);
module.exports = UserRoot;
middleware/checkAuthLogin.js:
const jwt = require('jsonwebtoken');
const RootUser = require('../models/root-user');
const checkRootLogin = async (req, res, next) => {
try {
const token = req.header('Authorization').replace('Bearer ', '');
// const decoded = jwt.verify(token, process.env.JWT_SECRET);
const decoded = jwt.verify(token, "test");
const rootUser = await RootUser.findOne({_id: decoded._id, 'tokens.token': token});
if (!rootUser) {
throw new Error("User cannot find!!");
}
req.token = token;
req.rootUser = rootUser;
req.userID = rootUser._id;
next()
} catch (e) {
res.status(401).send({error: 'Authentication problem!!'})
}
};
module.exports = {checkRootLogin};
Your issue is that your token variable is only accessible inside of the callback to the jwt.sign call, so when you try to do this here res.setHeader('Authorization', 'Bearer '+ token);, it won't know what variable you're referring to, hence the undefined error. By the way, if you're going to use jwt.sign asynchronously, then the code that uses it needs to also be inside of the callback, otherwise synchronous code outside of the callback will likely execute first (and thus not be able to access any results of the asynchronous code) as the asynchronous callback executes in the background. The solution here is to either switch your usage to a synchronous usage or place your response code inside of the callback. Also, calling res.json will end the response so I'm not sure what exactly you're trying to accomplish with the multiple response calls
Synchronous version:
app.post('/', (req, res) => {
let username = req.body.username;
let password = req.body.password;
const user = {
username: username,
password: password
};
let token = undefined;
try {
token = jwt.sign({ user }, process.env.SECRET_KEY);
} catch (e) {
// handle error
}
if (username !== process.env.USER_NAME && password !== process.env.USER_PASSWORD) {
res.json('Invalid credentials');
} else {
res.setHeader('Authorization', 'Bearer '+ token);
res.redirect('/dashboard');
}
});
Asynchronous version:
app.post('/', (req, res) => {
let username = req.body.username;
let password = req.body.password;
const user = {
username: username,
password: password
}
jwt.sign({ user }, process.env.SECRET_KEY, (err, token) => {
if (username !== process.env.USER_NAME && password !== process.env.USER_PASSWORD) {
res.json('Invalid credentials');
} else {
res.setHeader('Authorization', 'Bearer '+ token);
res.redirect('/dashboard')
}
});
});
In these examples, I took out res.json({ token }) because you can't use res.json and then perform a redirect, but modify those parts however best fits your code. On another note, you probably don't want to include the password in your token because while JWTs (when using the default/standard algorithms which do not include encryption) are cryptographically guaranteed to be unmodifiable, they are still readable
I have one solution to send jwt token, but you will need to install one more package. If you think it worth maybe you can follow.
I use express only for backend api. But you can use the same logic applied here to your application.
The lib you will need to install is the express-jwt
It handles routes to block access to endpoint that need authentication.
server.js
require('dotenv').config()
const express = require('express');
const logger = require('morgan');
const cors = require('cors');
const jwt = require('jsonwebtoken');
const expressJwt = require('express-jwt');
const app = express();
cors({ credentials: true, origin: true });
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use('/secure', expressJwt({ secret: process.env.SECRET }));
app.use(require('./server/index'));
app.get('/secure/dashboard') => {
//now you can only access this route with authorization header
//prependending the '/secure/ to new routes should make them return 401 when accessed without authorization token
//accessing this route without returns 401.
//there is no need to validate because express-jwt is handling.
console.log(res.user)//should print current user and pass signed with token
res.render('dashboard.ejs');
});
app.post('/', (req, res) => {
let username = req.body.username;
let password = req.body.password;
//jwt.sign({ user }, process.env.SECRET_KEY, (err, token) => {
// res.json({
// token
// })
//});
//shouldn't sign json here, because there is no guarantee this is a valid
//username and password it can be an impostor
if (username !== process.env.USER_NAME && password !== process.env.USER_PASSWORD) {
res.json('Invalid credentials');
} else {
const user = {
username: username,
password: password
};
const tk = {};
tk.token = 'Bearer ' + jwt.sign(user, process.env.SECRET_KEY, { expiresIn: 1800 });//expires in 1800 seconds
res.status(200).json(tk);
}
});
Now in your frontend put the authorization token sent by this route in cookies or store in client-side.
Do the next request with the header authorization for the secure dashboard route.
I think the problem in the sign in controller function
you must check first if the user have the correct password before attempting to send him a token
you should save the result of jwt sign function in a variable to send back to the user in case he has the right credintials.
It make no sense to send the password again to the user , only the username is needed
you can try this :
app.post('/', (req, res) => {
const {username , password} = req.body;
if (username !== process.env.USER_NAME && password !== process.env.USER_PASSWORD) {
return res.json('Invalid credentials');
}
const token = jwt.sign({username:username }, SECRET)
res.setHeader('Authorization', token);
res.redirect('/dashboard')
});
I have a nodejs backend with sessions made using express-session npm module. I want to test the sessions using postman.
What I want is a user should be allowed to access the users list via the /getUsers route only if he is currently in a session. But what is happening is when I test the backend using postman even after logging in the user is unable to access the users using the /getUsers route. Is this something to do with postman?
Here is my app.js
const express = require("express");
const app = express();
const authRoutes=require('./routes/auth');
const mongoose=require('mongoose');
const bodyParser = require("body-parser");
require("dotenv").config();
const nodemailer = require("nodemailer");
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
const cors = require('cors');
app.use(cors({
origin:['http://localhost:8080'],
methods:['GET','POST'],
credentials: true // enable set cookie
}));
app.use(
// Creates a session middleware with given options.
session({
name: 'sid',
saveUninitialized: false,
resave: false,
secret: 'sssh, quiet! it\'s a secret!',
cookie: {
httpOnly: true,
maxAge: 1000 * 60 * 60 * 2,
sameSite: true,
secure: true
}
})
);
mongoose.connect(process.env.LOCAL_MONGO_URI,{useNewUrlParser:true},function (err) {
if (err) throw err
console.log("Connected to local mongo db database");
});
app.get("/",(req,res)=> {console.log("A request was made to /")
console.log("/GET called");
});
app.use(bodyParser.json());
app.use("/",authRoutes);
const port = process.env.PORT||8080
app.listen(port,()=> {
console.log("Hello world");
})
Here is my routes/auth.js:
const express = require("express");
const {
signup,login,verifyemail,requiresLogin,getUsers,logout
} = require("../handler/auth")
const router = express.Router();
router.post("/signup",signup);
router.post("/login",login);
router.get("/verifyemail/:token",verifyemail);
router.get("/getUsers",requiresLogin,getUsers);
router.get("/getUsers",requiresLogin,getUsers);
router.get("/logout",requiresLogin,logout);
module.exports=router;
Here is my handler/auth.js
const User = require("../models/user");
const bcrypt = require('bcrypt');
const crypto = require('crypto');
exports.signup = async (req, res) => {
const email = req.body.email;
User.findOne({email},function(err,user){
if(err) return res.status(500).json({message:err.message});
else if(user) return res.status(403).json({"message":"User exists"});
const password = req.body.password;
const name = req.body.name;
bcrypt.hash(password, 10)
.then(async function(hashed_password) {
const user = await new User({email,name,hashed_password});
user.emailVerificationToken = crypto.randomBytes(20).toString('hex');
user.emailVerificationTokenExpires = Date.now() + 3600000*24;
await user.save(function(err) {
if(!err) {
const resetURL = `http://${req.headers.host}/verifyemail/${user.emailVerificationToken}`;
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const msg = {
from: 'admin#pinclone.com',
to: email,
subject: 'Email verification link',
html: `Verify your email here to login to your account`,
};
sgMail.send(msg);
return res.json({message:"verify email address to login"});
}
return res.status(500).send({ message: err.message });
});
})
.catch(function(error){
res.status(500).send({message:error.message});
});
});
};
exports.login = (req,res) => {
const email = req.body.email;
const password = req.body.password;
User.findOne({email},function(err,user) {
if(err) return res.status(500).json({message:err.message});
if(!user) return res.status(403).json({"message":"User does not exists"});
bcrypt.compare(password,user.hashed_password,(err,result) => {
if(result) {
if(user.isVerified)
return res.status(200).json({"message":"successfully logged in"});
else
return res.status(403).json({"message":"user is not verified"});
}
else return res.status(403).json({message: "email address password do not match"});
});
});
};
exports.verifyemail = async (req,res) => {
User.findOneAndUpdate({emailVerificationToken: req.params.token,emailVerificationTokenExpires: { $gt: Date.now() }}, {$set:{isVerified:true}}, {new: true}, (err, user) => {
if (err) {
res.status(403).send({message:"Link invalid or expired"});
// res.status(500).send({message:"Something wrong when updating data!"});
}
if(user) {
res.status(200).send({"message":"email verification successful you can login now!"});
}
});
};
exports.requiresLogin = (req, res, next) => {
if (req.cookies.sid) {
return next();
} else {
var err = new Error('You must be logged in to view this page.');
err.status = 401;
return next(err);
}
};
exports.logout = (req, res) => {
res.clearCookie('sid');
res.send("logout success");
};
exports.getUsers = (req,res) => {
User.find({},function(err,users){
res.send(users);
});
};
You can set session in tab Header with your key.
You can read https://www.toolsqa.com/postman/sessions-in-postman/ for more detail.
You should read at How to use Sessions in Postman? part.
*Please don't ignore the question looking at its length. It might seem long because I've attached the code. The actual problem statement is really small.
I've tried integrating Passport, Koa & MongoDB from the last two days. I've been failing and am unable to get any references regarding the problem I've been facing. My primary concern is to just get the login module working.
My problem is that the function to handle post request for login in my index routes, associated with koa-passport is being called and ctx.body is also being sent as a response but successRedirect and failureRedirect aren't working. Down below are the files that I'm using.
In the auth.js, I have console logged user inside the new LocalStrategy, right after var user = line. Nothing is logged to the console.
auth.js
const passport = require('koa-passport')
const LocalStretegy = require('passport-local').Strategy
const mongoose = require('mongoose')
const User = mongoose.model('User', mongoose.Schema({}, { strict: false }))
function *getUser(name) {
let user = yield User.find({username: name})
return user
}
passport.serializeUser( (user, done) => {
done(null, user.id)
})
passport.deserializeUser( async (id, done) => {
done(null, user)
})
passport.use(new LocalStretegy( (username, password, done) => {
co(function*() {
try {
var user = yield getUser(username)
if (user.username === username && user.password === password) {
return user
} else {
return null
}
} catch(e) {
return null
}
}).then((user) => {
done(null, user)
})
}))
module.exports = passport
/routes/index.js
const router = require('koa-router')()
const sendfile = require('koa-sendfile')
const passport = require('koa-passport')
const mongoose = require('mongoose')
const Counter = mongoose.model('Counter', mongoose.Schema({}, { strict: false }))
router.post('/custom', (ctx, next) => {
return passport.authenticate('local', function(user, info, status) {
if (user === false) {
ctx.status = 401
ctx.body = { success: false }
ctx.body = { success: true }
} else {
return ctx.login(user)
}
})(ctx, next)
})
router.post('/login', (ctx) => {
passport.authenticate('local', {
successRedirect: '/dash-board',
failureRedirect: '/login'
})
ctx.body={status: 'okay'}
})
router.get('/logout', (ctx) => {
ctx.logout()
ctx.redirect('/')
})
module.exports = router
app.js
const Koa = require('koa')
const router = require('koa-router')()
const app = new Koa()
app.proxy = true
//Routes
const users = require('./routes/users')
const index = require('./routes/index')
//Error handler
const onerror = require('koa-onerror')
onerror(app)
//MongoDB connection
const mongoose = require('mongoose')
mongoose.Promise = global.Promise
try{
mongoose.connect('mongodb://<user>:<pass>#<something>.mlab.com:<number>/<someDB>?poolSize=10&retries=5')
} catch(err) {
console.log(err)
}
// Sessions
const convert = require('koa-convert')
const session = require('koa-generic-session')
const MongoStore = require('koa-generic-session-mongo')
app.keys = ['key1']
app.use(convert(session({
store: new MongoStore()
})))
//body parser
const bodyparser = require('koa-bodyparser')
app.use(bodyparser({
enableTypes:['json', 'form', 'text']
}))
//passport
require('./auth')
const passport = require('koa-passport')
app.use(passport.initialize())
app.use(passport.session())
app.use(index.routes(), index.allowedMethods(), users.prefix('/index'))
app.use((ctx, next) => {
if(ctx.isAuthenticated()) {
return next()
} else {
ctx.redirect('/')
}
})
app.use((ctx, next) => {
return next().catch(function (err) {
ctx.status = err.status || 500;
if (err.expose) {
ctx.body = err.message;
}
})
})
module.exports = app
I am unable to deduce anything from here on. I've searched extensively and changed the code to work until here.
Maybe it has something to do with this code in which user does not seem to be declared.
passport.deserializeUser( async (id, done) => {
done(null, user)
})
When I use 'passport.authenticate('jwt', { session: false })' in a route, it returns 'Unauthorized'. The passport middleware seems not working. I don't know what is wrong! In the header I'm using the 'Authorization: JWT MY_TOKEN'.
app.js file
// ...code
const app = express();
app.use(bodyParser.json());
app.use(passport.initialize());
require('./config/passport')(passport); // passport middleware file
app.use('/api/auth', auth); // routes
app.use('/api/lists', lists); // routes
.
Passport middleware file:
const { Strategy, ExtractJwt } = require('passport-jwt');
const User = require('../models/User');
const keys = require('./keys');
module.exports = (passport) => {
const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = 'MYSECRETKEY';
// HERE IS EXECUTED! <<<<<<<<
passport.use(new Strategy(opts, function(jwt_payload, done) {
// HERE IS NOT BEING EXECUTED! <<<<<<<<
User.findOne({_id: jwt_payload.id}, function(err, user) {
if (err) {
return done(err, false);
}
if (user) {
return done(null, user);
} else {
return done(null, false);
}
});
}));
}
.
Login route (creating the token):
router.post('/login', (req, res, next) => {
const { email, } = req.body;
User.findOne({ email: email }, { password: 0 }, (errQuery, resUser) => {
const token = jwt.sign({_id: resUser.id}, 'MYSECRETKEY');
const responseData = {
status: true,
token: `JWT ${token}`
};
res.send(responseData);
});
});
The issue is this line:
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
Because you're calling that configuration option, your header needs to look like:
Authorization: Bearer MY_TOKEN