Without passport, I have added simple middleware to authorize user as below.
const jwt = require('jsonwebtoken');
module.exports = (req, res, next) => {
const authHeader = req.get('Authorization');
const token = authHeader.split(' ')[1];
let jwttoken;
try {
jwttoken = jwt.verify(token, 'secret');
} catch (err) {
err.statusCode = 500;
throw err;
}
if (!jwttoken) {
const error = new Error('Not authenticated.');
error.statusCode = 401;
throw error;
}
req.userId = jwttoken.userId;
next();
};
with passport, I have added middleware as below
const options = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'SECRET'
}
module.exports = (passport) => {
passport.use(new Strategy(options, async (payload, done) => {
await user.findByPk(payload.userId).then(user => {
if (user) {
return done(null, user);
}
return done(null, false);
}).catch(error => {
return done(null, error);
});
}));
}
Question: like I was adding user to request without passport as req.userId = jwttoken.userId, how can we do it with passport middleware?
At passport this is accomplished with that line of code on your module.exports:
return done(null, user);
This tells passport that the information should be sent to the next function callback at req.user.
So for example, if you "user.findByPk(payload.userId)" response is something like:
{
"name": <NAME>
"profile": <profile>
}
At your protected endpoint's callback, you should see it on req.user.
For example:
app.post('/profile', passport.authenticate('jwt', { session: false }),
function(req, res) {
res.send(req.user.profile);
}
);
With req.user.profile being equal to of the "user.findByPk(payload.userId)" response.
Related
I am using passport-jwt with express js & node js. for the database I am using MongoDB.
My passport.js file code is :
const { Users } = require("./model/userModel");
const passport = require("passport");
const JwtStrategy = require("passport-jwt").Strategy;
const ExtractJwt = require("passport-jwt").ExtractJwt;
const jwt = require("jsonwebtoken");
const jwtOptions = {
jwtFromRequest: ExtractJwt.fromHeader("authorization"),
secretOrKey: "secret",
};
exports.initializingPassport = (passport) => {
passport.use(
new JwtStrategy(jwtOptions, async (email, passport, done) => {
try {
const user = await Users.findOne({ email });
if (!user) {
return done(null, false);
} else if (user.password !== password) {
return done(null, false);
}
return done(null, user);
} catch (error) {
return done(error, false);
}
})
);
};
in app.js file I am using this code for registration. can you please help me with updated code.
app.post('/register',async(req,res)=>{
const user = await Users.findOne({email: req.body.email});
if(user){
return res.status(409).send("user already exist");
}
const newUser = await Users.create(req.body);
const token = passport.authenticate('jwt', { session: false },(req, res, () => {
res.status(200).send({
email: newUser.email,
token: 'Bearer ' + token
});
}));
});
I am having the file with OIDC implementation like below.
const passport = require('passport');
const passportOidc = require('passport-openidconnect').Strategy;
module.exports.oktaOidcVerify = (req, res, next) => {
try {
const oidcStrategy = new passportOidc(
oidcOptions,
async (
issuer,
profile,
context,
idToken,
accessToken,
refreshToken,
done
) => {
try {
if (!profile.id) {
return done(
new Error('Profile not found'),
null
);
} else {
return done(null, profile, {
accessToken,
refreshToken
});
}
} catch (err) {
}
}
);
passport.use('oidc', oidcStrategy);
passport.serializeUser((user, next) => {
next(null, user);
});
passport.deserializeUser((obj, next) => {
next(null, obj);
});
next();
} catch (error) {
}
};
In my express server.js file, I am adding as the middleware like below
app.use(passport.initialize());
app.use(oktaOidcVerify);
Is there a way to write JEST Unit Test case for only the "oktaOidcVerify" function by passing the sample request?
passport.authenticate from koa-passport doesn't work with local strategy. I use no sessions, no serializing. It's just simple passport example, but the server response is always 404.
const Koa = require('koa');
const bodyParser = require('koa-bodyparser');
const passport = require('koa-passport');
const Router = require('koa-router');
const LocalStrategy = require('passport-local').Strategy;
const app = new Koa();
app.use(bodyParser());
app.use(passport.initialize());
passport.use(new LocalStrategy({
session: false,
}, (email, password, done) => {
if(email && password){
return done(null, [email, password]);
}
else {
return done(null, false);
}
}
));
const router = new Router();
router.post('/auth', async (ctx) => {
passport.authenticate('local', { session: false }, (err, user) => {
if(!user)
return ctx.body = 'Failed!';
return ctx.body = { msg: 'Success' };
});
});
app.use(router.routes());
app.listen(3000, console.log('The server is started'));
The answer is in a depth of an issues on github repo of koa-router:
We should return passport.authenticate with passed context object:
router.post('/auth', async (ctx) => {
return passport.authenticate('local', { session: false }, (err, user) => {
if(!user)
return ctx.body = 'Failed!';
return ctx.body = { msg: 'Success' };
})(ctx, next);
});
I had the same issue and understood that the context object must be returned back for it to parse the response.
router.post('/auth', async (ctx) => {
return passport.authenticate('local', { session: false }, (err, user) => {
if(!user)
return ctx.body = 'Failed!';
return ctx.body = { msg: 'Success' };
})(ctx);
});
I use nodejs with passport Auth JWT. I can create the JWT Token but If I secure my route with passport.authenticate('jwt') it's not work and i have an errors.
My Error :
TypeError: Cannot read property '_id' of undefined
at JwtStrategy._verify (D:\Programes\nodejs\node\CRUD_NodeAngular5\NodeServer\config\passport.js:15:39)
at D:\Programes\nodejs\node\CRUD_NodeAngular5\NodeServer\node_modules\passport-jwt\lib\strategy.js:110:26
at D:\Programes\nodejs\node\CRUD_NodeAngular5\NodeServer\node_modules\passport-jwt\node_modules\jsonwebtoken\verify.js:27:18
at _combinedTickCallback (internal/process/next_tick.js:131:7)
at process._tickCallback (internal/process/next_tick.js:180:9)
Passport.js
var JwtStrategy = require('passport-jwt').Strategy;
var ExtractJwt = require('passport-jwt').ExtractJwt;
var User = require('../models/User');
var config = require('./database');
module.exports = function(passport) {
var opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeader();
opts.secretOrKey = config.secret;
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
User.findById(jwt_payload.$__._id, function(err, user) {
if (err) {
return done(err, false);
}
if (user) {
done(null, user);
} else {
done(null, false);
}
});
}));
};
Login
router.post('/login', function(req, res) {
User.findOne({ email: req.body.email }, function(err, user) {
if (err) throw err;
if (!user) {
res.send({ success: false, message: 'Authentication failed. User not found.' });
console.log('User not found');
} else {
user.comparePassword(req.body.password, function(err, isMatch) {
if (isMatch && !err) {
var token = jwt.sign(user.toJSON(), config.secret, {expiresIn: 1000 });
var decoded = jwt.decode(token);
console.log(decoded);
res.json({ success: true, token:'JWT ' + token, decoded: decoded });
console.log('Connected : ' + token);
} else {
res.send({ success: false, message: 'Authentication failed. Passwords did not match.' });
console.log('Password is wrong');
}
});
}
});
});
Route Dashboard Not work
router.get('/dashboard', passport.authenticate('jwt', { session: false }), function(req, res) {
res.send('It worked! User id is: ' );
});
lets clean your code it's simple :-
Step1: create config file and load where you keep your routes
var checkAuth = require('../config/check-auth');
Step2: copy paste it in check-auth
const jwt = require('jsonwebtoken');
module.exports = (req,res,next)=>{
try{
const token = req.headers.authorization.split(" ")[1];
const decoded = jwt.verify(token,"secret");
req.userData = decoded;
next();
}catch(error){
return res.status(401).json({message:'Auth failed'});
}
}
step 3 :protect your route
router.get('/dashboard',checkAuth , { session: false }),
function(req, res) {
res.send('It worked! User id is: ' );
});
protect all your routes by passing checkAuth as parameter
I'm trying to use koa-passport for koa2, and followed the examples of the author, but i always get "Unauthorized". I used the console.log and found that it even not hit the serializeUser.
var UserLogin = async (ctx, next) =>{
return passport.authenticate('local', function(err, user, info, status) {
if (user === false) {
ctx.body = { success: false }
} else {
ctx.body = { success: true }
return ctx.login(user)
}
})(ctx, next);
};
And then I searched on the web and found another writing of router, it goes to the serializeUser but the done(null, user.id) threw error that "cannot get id from undefined".
let middleware = passport.authenticate('local', async(user, info) => {
if (user === false) {
ctx.status = 401;
} else {
await ctx.login(ctx.user, function(err){
console.log("Error:\n- " + err);
})
ctx.body = { user: user }
}
});
await middleware.call(this, ctx, next)
The auth.js are showed below. Also I followed koa-passport example from the author here and tried to use session, but every request i sent will get a TypeError said "Cannot read property 'message' of undefined". But I think this is not the core problem of authentication, but for reference if that really is.
const passport = require('koa-passport')
const fetchUser = (() => {
const user = { id: 1, username: 'name', password: 'pass', isAdmin: 'false' };
return async function() {
return user
}
})()
const LocalStrategy = require('passport-local').Strategy
passport.use(new LocalStrategy(function(username, password, done) {
fetchUser()
.then(user => {
if (username === user.username && password === user.password) {
done(null, user)
} else {
done(null, false)
}
})
.catch(err => done(err))
}))
passport.serializeUser(function(user, done) {
done(null, user.id)
})
passport.deserializeUser(async function(id, done) {
try {
const user = await fetchUser();
done(null, user)
} catch(err) {
done(err)
}
})
module.exports = passport;
By the way when I use the simple default one, it will just give me a "Not found". But through console.log I can see it actually got into the loginPass.
var loginPass = async (ctx, next) =>{
passport.authenticate('local', {
successRedirect: '/myApp',
failureRedirect: '/'
});
};
In server.js:
// Sessions
const convert = require('koa-convert');
const session = require('koa-generic-session');
app.keys = ['mySecret'];
app.use(convert(session()));
// authentication
passport = require('./auth');
app.use(passport.initialize());
app.use(passport.session());
Thanks a lot for any help!!! :D