config/passport.ts
/// <reference path='../typings/index.d.ts' />
import * as passport from 'passport';
import { User } from '../models/user';
import * as config from './main';
import { Strategy as JwtStrategy, ExtractJwt } from 'passport-jwt';
import { Strategy as LocalStrategy } from 'passport-local';
const localOptions = { usernameField: 'email' };
// Setting up local login strategy
const localLogin = new LocalStrategy(localOptions, function(email, password, done) {
User.findOne({ email: email }, function(err, user) {
if(err) { return done(err); }
if(!user) { return done(null, false, { message: 'Your login details could not be verified. Please try again.' }); }
//test instead of user.comparePassword
user.schema.methods.comparePassword(password, function(err, isMatch) {
if (err) { return done(err); }
if (!isMatch) { return done(null, false, { message: "Your login details could not be verified. Please try again." }); }
return done(null, user);
});
});
});
const jwtOptions = {
// Telling Passport to check authorization headers for JWT
jwtFromRequest: ExtractJwt.fromAuthHeader(),
// Telling Passport where to find the secret
secretOrKey: config.secret
};
// Setting up JWT login strategy
const jwtLogin = new JwtStrategy(jwtOptions, function(payload, done) {
User.findById(payload._id, function(err, user) {
if (err) { return done(err, false); }
if (user) {
done(null, user);
} else {
done(null, false);
}
});
});
passport.use(jwtLogin);
passport.use(localLogin);
router.ts
import * as AuthenticationController from './controllers/authentication';
import * as express from 'express';
import * as passport from 'passport';
import * as passportService from './config/passport';
// Middleware to require login/auth
const requireAuth = passport.authenticate('jwt', { session: false });
const requireLogin = passport.authenticate('local', { session: false });
// Constants for role types
const REQUIRE_ADMIN = "Admin";
const REQUIRE_OWNER = "Owner";
const REQUIRE_CLIENT = "Client";
const REQUIRE_MEMBER = "Member";
export function router(app) {
// Initializing route groups
const apiRoutes = express.Router();
const authRoutes = express.Router();
// Registration route
authRoutes.post('/register', AuthenticationController.register);
// Login route
authRoutes.post('/login', requireLogin, AuthenticationController.login);
// Set auth routes as subgroup/middleware to apiRoutes
apiRoutes.use('/auth', authRoutes);
// Set url for API group routes
app.use('/api', apiRoutes);
};
index.ts
/// <reference path="./typings/index.d.ts" />
// Importing Node modules and initializing Express
import * as express from 'express';
import * as logger from 'morgan';
import * as config from './config/main';
import * as bodyParser from 'body-parser';
import * as mongoose from 'mongoose';
import { router } from './router';
export const app = express();
const server = app.listen(config.port);
console.log(`Your server is running on port ${config.port}.`);
app.use(logger('dev'));
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization, Access-Control-Allow-Credentials");
res.header("Access-Control-Allow-Credentials", "true");
next();
});
//DB connection
mongoose.connect(config.database);
//Body parsing
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
router(app);
And the error:
POST /api/auth/login 500 4.796 ms - 1947
Error: Unknown authentication strategy "local"
at attempt (/Users/pumz/closeloop/app/server/node_modules/passport/lib/middleware/authenticate.js:173:37)
at authenticate (/Users/pumz/closeloop/app/server/node_modules/passport/lib/middleware/authenticate.js:349:7)
at Layer.handle [as handle_request] (/Users/pumz/closeloop/app/server/node_modules/express/lib/router/layer.js:95:5)
at next (/Users/pumz/closeloop/app/server/node_modules/express/lib/router/route.js:131:13)
at Route.dispatch (/Users/pumz/closeloop/app/server/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/Users/pumz/closeloop/app/server/node_modules/express/lib/router/layer.js:95:5)
at /Users/pumz/closeloop/app/server/node_modules/express/lib/router/index.js:277:22
at Function.process_params (/Users/pumz/closeloop/app/server/node_modules/express/lib/router/index.js:330:12)
at next (/Users/pumz/closeloop/app/server/node_modules/express/lib/router/index.js:271:10)
at Function.handle (/Users/pumz/closeloop/app/server/node_modules/express/lib/router/index.js:176:3)
at router (/Users/pumz/closeloop/app/server/node_modules/express/lib/router/index.js:46:12)
at Layer.handle [as handle_request] (/Users/pumz/closeloop/app/server/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/Users/pumz/closeloop/app/server/node_modules/express/lib/router/index.js:312:13)
at /Users/pumz/closeloop/app/server/node_modules/express/lib/router/index.js:280:7
at Function.process_params (/Users/pumz/closeloop/app/server/node_modules/express/lib/router/index.js:330:12)
at next (/Users/pumz/closeloop/app/server/node_modules/express/lib/router/index.js:271:10)
I believe everything is well configured, I got no compilation errors, and the register works as expected.
I've seen some require('passport-local')(passport)
that solves it, but it's not working. Nor changing the authentication method to local-login
import * as passportService from './config/passport';
TypeScript will elide that import as you are not using anything config/passport is exporting (you're not exporting anything at all from that module actually) in the value position. See https://github.com/Microsoft/TypeScript/issues/2812 and similar.
If you look at the transpiled output for router.ts you will see that it is indeed missing require('./config/passport'). The fix is to export something from that module and then reference it -- maybe initialize the passport authentication strategies in an exported init() function.