I've been trying to test the protected routes by using passport and passport-jwt.
I've got it to the point where the token is being generated when a user tries to log in and tested it in Postman.
I've created a route and passed in as an argument passport.authenticate with the jwt strategy and am getting errors all over the place.
In my main server.js, I require passport:
passport = require('passport');
app.use(passport.initialize());
// passport config
require('./config/passport')(passport);
My folder structure is this:
in my passport config file, i have this:
const jwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const mongoose = require('mongoose');
const User = mongoose.model('users')
const keys = require('../config/keys');
const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = keys.secretOrKey;
module.export = passport => {
passport.use(
new jwtStrategy(opts, (jwt_payload, done) => {
console.log(jwt_payload);
}));
};
And my route is this:
// #route get to /users/current
// #desc: return the current user (who the jwt token belongs to)
// #access: should be public
router.get('/current',
passport.authenticate('jwt', { session: false }),
(req, res) => {
res.json({msg: "Success"})
}
);
The first error I can't seem to get passed is this in the console:
require('./config/passport')(passport);
^
TypeError: require(...) is not a function
In postman, when I try to go to /users/current and pass in a confirmed bearer token, I get this:
Error: Unknown authentication strategy "jwt" at attempt
in passport config file
you have typo module.export actualy its module.exports
thats why after require it does not recongnizing it as function
change the module.export to
module.exports = passport => {
passport.use(
new jwtStrategy(opts, (jwt_payload, done) => {
console.log(jwt_payload);
}));
};
its module.exports and not module.export.
The module.exports property can be assigned a new value (such as a function or object).
module.exports = class Square {
constructor(width) {
this.width = width;
}
area() {
return this.width ** 2;
}
};
nodejs modules documentation reference
Related
I am using JWT to do authentication with a user in my express app. One of the routes needs to be authenticated before continuing so I am doing so like this per following the documentation and a tutorial:
router.post('/current/update', passport.authenticate('jwt', { session: false }),(res, req) => {
console.log(req.body) //undefined
}
passport.js
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const mongoose = require('mongoose');
const Account = mongoose.model('accounts')
const keys = require('./keys');
const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = keys.secretOrKey;
module.exports = passport => {
passport.use(
new JwtStrategy(opts, (jwt_payload, done) => {
Account.findById(jwt_payload.id)
.then(account => {
if(account){
return done(null, account)
}
return done(null, false)
}).catch(err => {
console.log(err)
return done(err)
})
})
);
};
Not knowing how to get access to the body of the request is troubling because that means I don't know how to get access to the req.params and req.query. I have tried numerous methods, including passing the req along with the strategy:
new JwtStrategy(opts, (req, jwt_payload, done) => ...
So question is, if not gotten from above, is how do I get access to the req object, other than just req.userso that I am able to handle parameterized URLs and queries?
You need to tell the JwtStrategy to pass the req object to your callback. You can do this via the options object you supply to the strategy. Your code will look something like this:
const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = keys.secretOrKey;
opts.passReqToCallback = true; // New option!
Then in your callback function you'll need to also accept the req field which comes in as the first argument to the function. So your callback initialisation goes from
new JwtStrategy(opts, (jwt_payload, done)
and becomes
new JwtStrategy(opts, (req, jwt_payload, done)
You can then access the full express request object via req. As noted in the comments, you'll also need something like body-parser to ensure it's decoded properly.
When I am trying to secure the users API; I am getting always 401 unauthorized. I have tried different variations to define strategy; but no luck. I have been using JWTStrategy and using jwtwebtoken while signing the token with the Secret and RS256 Algorithm
Passport.js
// import * as module from 'module';
const
User = require('../models/user'),
JwtStrategy = require('passport-jwt').Strategy,
ExtractJwt = require('passport-jwt').ExtractJwt,
config = require('./appconfig');
// Setting JWT strategy options
const jwtOptions = {
// Telling Passport to check authorization headers for JWT
jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme('Bearer'),
// Telling Passport where to find the secret
secretOrKey: config.jwtSecret,
algorithms:['RS256']
// TO-DO: Add issuer and audience checks
};
console.log(config.jwtSecret);
module.exports = function(passport) {
passport.use(new JwtStrategy(jwtOptions, function(jwt_payload, done) {
console.log(jwt_payload);
User.findOne({id: jwt_payload.sub}, function(err, user) {
if (err) {
return done(err, false);
}
if (user) {
return done(null, user);
} else {
return done(null, false);
// or you could create a new account
}
});
}));
};
Index.Route.js
const express = require('express');
const userRoutes = require('./user.route');
const authRoutes = require('./auth.route');
// const postRoutes = require('./post.route');
const passport = require('passport');
passport.initialize();
var jwt = require('../config/passport')(passport);
const router = express.Router(); // eslint-disable-line new-cap
/** GET /health-check - Check service health */
router.get('/health-check', (req, res) =>
res.send('OK')
);
// mount user routes at /users
router.use('/users', passport.authenticate('jwt', { session: false }), userRoutes);
// mount auth routes at /auth
router.use('/auth', authRoutes);
// router.use('/posts', postRoutes);
module.exports = router;
Using Postman:
Header:
Authentication: JWT Token
localhost:4040/api/users
Did you configure postman in header section? Can you show JwtStrategy code.
I'm having trouble authenticating with passportjs and jwt. I'm sending an authorization header in a get request and reciveve an Unauthorized response. My first thought was that I'm probably messing up something with the token, so I'm trying to log the jwt_payload.
It seems to me like passport.authenticate() does not even run any of the code in my passport.js file, as console.log(jwt_payload) below never logs anything
/config/passport.js
module.exports = function(passport) {
let opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = config.secret;
passport.use(new JwtStrategy(opts, (jwt_payload, done) => {
console.log(jwt_payload);
User.getUserById(jwt_payload._id, (err, user) => {
if(err){
return done(err,false);
}
if(user){
return done(null,user);
} else {
return done(null, false);
}
});
}));
}
The passport.use(...) clause above must however be doing something, if i remove it i get an error of Unknown authentication strategy "jwt"
Below is the code for my passport setup and passport.authenticate() call.
/routes/users.js
const passport = require('passport');
const jwt = require('jsonwebtoken');
const config = require('../config/database');
router.get('/profile', passport.authenticate('jwt', {session:false}), (req, res, next) => {
res.json({user: req.user});
});
app.js
const passport = require('passport');
app.use(passport.initialize());
app.use(passport.session());
require('./config/passport')(passport);
I am new to Javascript and even newer to Node. I am trying to read an express server code and can't figure out following line in my app.js file:
module.require('./auth')(passport);
I know I have a variable that holds passport module in app.js:
var passport = require('passport');
and I also have auth.js in the same directory which exports the following function:
module.exports = function(passport) {
passport.use('local-login', new LocalStrategy({
usernameField: 'email'
}, function(idpEmail, password, done) {
// do email mapping
findEmailFromDummyDb(idpEmail, password,function(err,user){
if(err) {
done(null, false, {
messages: err.toString()
});
} else {
done(null, {
sysEmail: user.sysEmail
});
}
});
}));
However, what does following function actually do?
module.require('./auth')(passport);
module.require('./auth') imports a function, then it get's called with passport as a parameter. It's the same as
const auth = require('./auth');
const passport = require('passport');
auth = auth(passport);
The below returns a javascript function.
module.require('./auth');
You are then immediately calling the function with the passport object as a function argument.
(passport)
I'm trying to set up Express routes bound with multiple controllers, of course they're supposed to receive functions, this is what I'm trying:
authRouter.get('/login/redirect/:provider', controllers.handleOAuth2Redirect, controllers.jwt);
This has sometimes worked, sometimes not, the only changes when works or not are minimal code changes, could be a require line, an expression, etc.
This is the error being thrown:
Error: Route.get() requires callback functions but got a [object Object]
So following code is the complete working controllers file:
'use strict';
var passport = require('passport');
var FacebookStrategy = require('passport-facebook').Strategy;
var TwitterStrategy = require('passport-twitter').Strategy;
var InstagramStrategy = require('passport-instagram').Strategy;
var OAuth2Strategy = require('passport-oauth2').Strategy;
var facebook_scope = ['email', 'user_about_me','user_friends','publish_actions'];
var passportFacebookOptions = {scope: facebook_scope};
passport.use(new FacebookStrategy({
clientID: process.env.FACEBOOK_FINALCUT_APP_ID,
clientSecret: process.env.FACEBOOK_FINALCUT_APP_SECRET,
callbackURL: 'http://localhost:9248/auth/login/redirect/fb'
},
function (accessToken, refreshToken, params, profile, done) {
return done(null, profile, params);
}));
passport.use(new InstagramStrategy({
clientID: process.env.INSTAGRAM_FINALCUT_CLIENT_ID,
clientSecret: process.env.INSTAGRAM_FINALCUT_CLIENT_SECRET,
callbackURL: 'http://localhost:9248/auth/login/redirect/ig'
},
function (accessToken,refreshToken,profile,done) {
return done(null, profile, {tokens: {accessToken: accessToken, refreshToken: refreshToken}});
}));
function oauth2ProviderLogin (request,response,next) {
var provider = request.query.provider;
switch (provider) {
case 'fb':
passport.authenticate('facebook')(request,response,next);
break;
case 'ig':
passport.authenticate('instagram')(request,response,next);
break;
}
}
function handleOAuth2Redirect (request,response,next) {
var provider = request.params.provider;
switch (provider) {
case 'fb':
passport.authenticate('facebook', {session:false})(request,response,next);
break;
case 'ig':
passport.authenticate('instagram', {session:false})(request,response,next);
break;
}
}
function jwt (request,response,next) {
var jwt = require('jsonwebtoken');
var token = jwt.sign({auth: request.authInfo}, '623145ca-7749-11e5-8bcf-feff819cdc9f');
return response.send({user: request.user, auth: token});
}
module.exports = (function() {
var authController = {
oauth2ProviderLogin: oauth2ProviderLogin,
handleOAuth2Redirect: handleOAuth2Redirect,
jwt: jwt
};
return authController;
})();
I've literally made it work by changing some lines of the controller functions. But the exports block has always remained the same. Naturally I nede to keep coding but then it stops working.
An example of something making it to stop working:
'use strict';
var passport = require('passport');
var jwt = require('jsonwebtoken'); // This makes it fail
var FacebookStrategy = require('passport-facebook').Strategy;
var TwitterStrategy = require('passport-twitter').Strategy;
var InstagramStrategy = require('passport-instagram').Strategy;
var OAuth2Strategy = require('passport-oauth2').Strategy;
That's it: adding a var jwt = require('jsonwebtoken') will make it fail.
Is there something I'm missing?
My error is actually silly:
Adding var jwt = require('jsonwebtoken') because I have a function with same name below:
function jwt (request,response,next) {
var token = jwt.sign({auth: request.authInfo}, '623145ca-7749-11e5-8bcf-feff819cdc9f');
return response.send({user: request.user, auth: token});
}
Just changing the name of any of those will fix the issue.