Search code examples
node.jstypescriptpassport.jspassport-local

'Unknown authentication strategy' error using TS in server


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


Solution

  • 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.