I am new to nodejs. I need to create and authentication using nodejs. Here I found few answers but they also used old version. Here I am using these versions
I used this code to create the passport.js file in my node application.
const JwtStrategy = require('passport-jwt').Strategy,
ExtractJwt = require('passport-jwt').ExtractJwt;
const config = require('./db');
const User = require('./models/user');
const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = config.secret;
module.exports = (passport)=>{
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
User.findUserbyId({_id: jwt_payload._doc._id}, function(err, user) {
if (err) {
return done(err, false);
}
if (user) {
return done(null, user);
} else {
return done(null, false);
}
});
}));
};
And I used this routes method to create a route with the Authentication.
router.post('/profile',
passport.authenticate('jwt'),{ session: false },
(req, res)=> {
res.json({user:req.user});
});
I used postman to create a token and check the authentication.
I cannot understand the why it wrong. findUserById method is follow
module.exports.findUserbyId = (id, callback)=>{
User.findOne(id, callback);
}
What's the problem in my code? Why it every time gives
unauthorized
in my postman application.
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 writing a application that uses JWTs for user authentication. I am trying to allow the user to submit or edit resources associated ONLY to there ID which is generated when they create their account in MongoDB only after the user has logged in. My instructor suggested to store the user._id within a cookie but not familiar with that process. Any tips on how I could accomplish this?
Here is an example of how my users are registered within the server
app.get('/register', function (req, res) {
res.sendFile(__dirname + '/public/register.html');
});
app.post('/register', async function (req,res) {
try {
req.body.password = await bcrypt.hash(req.body.password, 10);
var newUser = new User(req.body);
newUser.save(function(error,user){
res.redirect('/login');
});
} catch{
res.redirect('/register');
}
// console.log(newUser);
});
Here is the auth process
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const bcrypt = require('bcrypt');
const opts = {}
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = process.env.secret;
module.exports = new JwtStrategy(opts, async (jwt_payload,done)=> {
const user = await (req.body.email);
if( jwt_payload.email === req.body.email){
return done(null, true)
}
try {
if (await bcrypt.compare(password, user.password)){
return done(null, user);
} else {
return done(null, false, { message: "Password is incorrect"});
}
} catch (e) {
return done(e);
}
})
Here is logging in
app.post('/login', async (req, res) => {
const { username, password } = req.body
const user = await User.findOne({ username }).lean()
if (!user) {
return res.sendFile(__dirname + '/public/401.html');
}
if (await bcrypt.compare(password, user.password)) {
// the username, password combination is successful
const token = jwt.sign(
{
id: user._id,
username: user.username
},
process.env.secret
)
console.log(user._id);
//I need to find a way to send over the user._id to the client side so it can be stored later to allow the user to only update their resources and to view their resources
return res.redirect('/welcome.html');
}
res.sendFile(__dirname + '/public/401.html');
})
EDIT: I am not not wanting to store the token unless that is the only way to pass the user._id to the client side due to security reasoning.
Technologies I am using are, Node.js, Express.js, Mongoose, MongoDB, JWT, passport, jwt-simple, bcrypt, methodOverride, and secrets for resetting the users password and creating the user are stored in an .env.
I have a stand alone oauth2 identity provider that is working.
Now I'm developing a consumer that will authenticate users with this stand alone provider.
I'm following this tutorial about passport and Google Auth:
I'm trying to use this information to use passport-oauth2 to work as a client. I have made some changes in the code provided in the tutorial above by following the official documentation on passoprt-oauth2.
I think that I have some problem in the callback function where expressjs receive the confirmation of authentication and info about the user. I don't understand how to use this information.
Here is the code of my app.js
const express = require('express');
const app = express();
const passport = require('passport');
const OAuth2Strategy = require('passport-oauth2');
const cookieSession = require('cookie-session');
// cookieSession config
app.use(cookieSession({
maxAge:24*60*60*1000,
keys: ['secret-personalize']
}));
app.use(passport.initialize());
app.use(passport.session());
//Strategy config
passport.use(new OAuth2Strategy({
authorizationURL: 'http://localhost:3000/dialog/authorize',
tokenURL: 'http://localhost:3000/oauth/token',
clientID: 'xyz123',
clientSecret: 'ssh-password',
callbackURL: "/auth/oauth2/callback"
},
(accessToken, refreshToken, profile, done) => {
console.log(profile);
done(null, profile);
}
));
// Used to decode the received cookie and persist session
passport.deserializeUser((user, done) => {
done(null, user);
});
// Middleware to check if the User is authenticated
app.get('/auth/oauth2',
passport.authenticate('oauth2'));
function isUserAuthenticated(req, res, next){
if (req.user){
next();
} else {
res.send('you must login!');
}
}
// Routes
app.get('/', (req, res) => {
res.render('index.ejs');
});
// The middleware receives the data from AuthPRovider and runs the function on Strategy config
app.get('/auth/oauth2/callback', passport.authenticate('oauth2'), (req,res) => {
res.redirect('/secret');
});
// secret route
app.get('/secret', isUserAuthenticated, (req, res) =>{
res.send('You have reached the secret route');
});
// Logout route
app.get('/logout',(req, res) => {
req.logout();
res.redirect('/');
});
app.listen(8000, () => {
console.log('Server Started 8000');
});
and this is for views/index.ejs
<ul>
<li>Login</li>
<li>Secret</li>
<li>Logout</li></ul>
I got this error:
Error: Failed to serialize user into session
at pass (/home/user/job/NodeJS/test-consumer/second/node_modules/passport/lib/authenticator.js:281:19)
at Authenticator.serializeUser (/home/user/job/NodeJS/test-consumer/second/node_modules/passport/lib/authenticator.js:299:5)
at SessionManager.logIn (/home/user/job/NodeJS/test-consumer/second/node_modules/passport/lib/sessionmanager.js:14:8)
at IncomingMessage.req.login.req.logIn (/home/user/job/NodeJS/test-consumer/second/node_modules/passport/lib/http/request.js:50:33)
at OAuth2Strategy.strategy.success (/home/user/job/NodeJS/test-consumer/second/node_modules/passport/lib/middleware/authenticate.js:248:13)
at verified (/home/user/job/NodeJS/test-consumer/second/node_modules/passport-oauth2/lib/strategy.js:177:20)
at OAuth2Strategy.passport.use.OAuth2Strategy [as _verify] (/home/user/job/NodeJS/test-consumer/second/app.js:31:5)
at /home/user/job/NodeJS/test-consumer/second/node_modules/passport-oauth2/lib/strategy.js:193:24
at OAuth2Strategy.userProfile (/home/user/job/NodeJS/test-consumer/second/node_modules/passport-oauth2/lib/strategy.js:275:10)
at loadIt (/home/user/job/NodeJS/test-consumer/second/node_modules/passport-oauth2/lib/strategy.js:345:17)
Every help is welcome.
Thanks you
You need to add serializer:
passport.serializeUser(function(user, done) {
done(null, user);
});
I'm using this module now, but the profile always returns empty.
First you need to override the userProfile
This is the source code
const passport = require('passport')
// const { Strategy: GoogleStrategy } = require('passport-google-oauth20')
const { Strategy: GithubStrategy } = require('passport-github')
const { Strategy: OAuth2Strategy } = require('passport-oauth2')
const { GITHUB_CONFIG, OAUTH2_CONFIG} = require('../config')
const Profile = require('./profile')
module.exports = () => {
// Allow passport to serialize and deserialize users into sessions
passport.serializeUser((user, cb) => cb(null, user))
passport.deserializeUser((obj, cb) => cb(null, obj))
// The callback that is invoked when an OAuth provider sends back user
// information. Normally, you would save the user to the database
// in this callback and it would be customized for each provider
const callback = (accessToken, refreshToken, params, profile, cb) => {
console.log('access-token',accessToken)
console.log('refresh-token',refreshToken)
console.log('profile',profile)
console.log('params',params)
return cb(null, profile)
}
// Adding each OAuth provider's startegy to passport
// passport.use(new GoogleStrategy(GOOGLE_CONFIG, callback))
passport.use(new GithubStrategy(GITHUB_CONFIG, callback))
const DjangoStrategy = new OAuth2Strategy(OAUTH2_CONFIG, callback)
DjangoStrategy.userProfile = function(accessToken, done) {
var self = this;
this._userProfileURL = 'http://localhost:8001/accounts/profile/';
this._oauth2.get(this._userProfileURL, accessToken, function (err, body, res) {
var json;
if (err) {
if (err.data) {
try {
json = JSON.parse(err.data);
} catch (_) {}
}
if (json && json.message) {
return done(new APIError(json.message));
}
return done(new InternalOAuthError('Failed to fetch user profile', err));
}
try {
json = JSON.parse(body);
} catch (ex) {
return done(new Error('Failed to parse user profile'));
}
console.log('json', json)
var profile = Profile.parse(json);
profile.provider = 'oauth2';
profile._raw = body;
profile._json = json;
done(null, profile);
});
}
passport.use(DjangoStrategy)
}
Create a profile
profile.js
exports.parse = function(json) {
if ('string' == typeof json) {
json = JSON.parse(json);
}
var profile = {};
profile.id = String(json.id);
profile.displayName = json.name;
profile.username = json.username;
profile.email = json.email;
return profile;
};
You can also check clone my source code
https://github.com/faisallarai/nodejs-oauth-server.git
Im using passport.js JWT strategy to authenticate my MEAN-Stack app. The unsecured routes work properly but i cant get the secured routes to work. they allways return Internal Server Error 500 even though im sticking to the docs. Here is the code:
im initializing in index.js before applying routes:
server.use(passport.initialize());
My passport.js setup file:
const JwtStrategy = require('passport-jwt').Strategy,
ExtractJwt = require('passport-jwt').ExtractJwt;
const User = require('../models/user');
const config = require('../config/db');
module.exports = function(passport) {
let opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = config.secret;
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
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);
}
});
}));
};
My Route that doesnt work:
const express = require('express');
const router = express.Router();
const config = require('../config/db');
const jwt = require('jsonwebtoken');
const User = require('../models/user');
require('../config/passport');
const passport = require('passport');
router.get('/profile', passport.authenticate('jwt', {session: false}), function(req,
res){
res.json(user);
});
module.exports = router;
my token is setup properly since i can decode it manually.
How im calling this route from angular (i know that i actually dont need the userId parameter for the call itself):
public getProfile(userId) : any{
let httpOptions = {
headers: new HttpHeaders({ 'Authorization': `Bearer ${this.token}` })
};
this.http.get('http://localhost:8080/api/v1/profile', httpOptions).subscribe(res => {
console.log('got the profile for user with id: ' + userId + '=> ' + res);
return res;
}, err => {
console.log(err);
});
}
Any help is appreciated. Thanks in advance for your time!
EDIT: Mongoose logs
Mongoose: users.findOne({ _id: ObjectId("5bcf1218cace7d1168a23672") }, {
projection: {} })
GET /api/v1/profile 500 4.579 ms - 5
OPTIONS /api/v1/profile 204 0.097 ms - 0
{ _id: '5bcf1218cace7d1168a23672',
email: '12#email.com',
password: '$2a$10$z8li41jQMESsmbIyQUsPfO6VkYjOyO/ybj4lW04VGUkJmlShydBN.',
name: '12',
age: 12,
gender: 'male',
description: '12',
question: '12',
__v: 0,
iat: 1540419498 }
Mongoose: users.findOne({ _id: ObjectId("5bcf1218cace7d1168a23672") }, {
projection: {} })
GET /api/v1/profile 500 3.995 ms - 5
I have added single-line comments to hit spots, verify the spots and comment accordingly to further debug. Confirm /api/v1/ is an express root route.
passport.js
const JwtStrategy = require('passport-jwt').Strategy,
const ExtractJwt = require('passport-jwt').ExtractJwt;
const User = require('../models/user');
const config = require('../config/db');
module.exports = function(passport) {
let opts = {
secretOrKey: config.secret,
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
issuer: 'TODO', // configure issuer
audience: 'TODO' // configure audience
};
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
console.log(jwt_payload); // confirm _id is defined
User.findOne({ _id: jwt_payload._id }, function(err, user) {
if (err) {
return done(err, false);
}
if (!user) {
return done(null, false);
}
return done(null, user);
});
}));
};
route.js
const express = require('express');
const passport = require('passport');
const jwt = require('jsonwebtoken');
const config = require('../config/db');
const User = require('../models/user');
const router = express.Router();
require('../config/passport');
router.get('/profile', passport.authenticate('jwt', { session: false }), function(req, res) {
res.json(req.user); // use req.user not user
});
module.exports = router;
Had the same issue. Seems like the way you are returning the done(null, user) callback needs to be modified. Try this.
User.findOne({ _id: jwt_payload._id }, function(err, user) {
if (err) {
return done(err, false);
}
if (!user) {
return done(null, false);
}
// Your code should process further if you get user. Returning
// here will terminate your program early. Hence, protected
// route is not accessed.
done(null, user);
});
I'm using passport-jwt package for simple authentication and the token is generated by jsonwebtoken.
But the problem is that verify callback is never called.
Here my passport.js code.
var JwtStrategy = require('passport-jwt').Strategy;
var User = require('../app/models/user');
var config = require('../config/database');
var opts = {};
opts.jwtFromRequest = function(req) {
var token = null;
if (req && req.headers) {
token = req.headers.authorization;
}
return token;
};
opts.secretOrKey = config.secret;
console.log(opts);
module.exports = function(passport) {
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
User.findOne({_id: jwt_payload._doc._id}, function(err, user) {
if (err) {
return done(err, false);
}
if (user) {
done(null, user);
} else {
done(null, false);
}
});
}));
};
Hope to hear from you.
Thanks
The problem is that you should add 'JWT '(JWT and a space ahead of the original jwt signed). Please check this tutorial http://blog.slatepeak.com/building-a-basic-restful-api-for-a-chat-system/
by Joshua for assistance.
By the way, make sure that if you need a 'where' inside your findOne or not.