Nick Gr
Nick Gr

Reputation: 157

How to initialize passport config file in typescript?

I have this passport config file with local-strategy:

const LocalStrategy = passportLocal.Strategy;
const User = UserModel;

passport.serializeUser((user: any, cb) => {
  cb(undefined, user.id);
});

passport.deserializeUser((id: string, cb) => {
  User.findOne({_id: id}, (err: Error, user: IUser) => { //might need to change it to findById instead of findOne
    const userInfo = {
      username: user.username,
      role: user.role
    };
    cb(err, userInfo);
  });
});

passport.use(new LocalStrategy((username, password, done) => {
  User.findOne({username: username}, (err: Error, user: IUser) => { //note here that the IUser might be bad, instead place any (to all IUser too)
    if (err) throw err;
    if (!user) return done(null, false);
    bcrypt.compare(password, user.password, (err, result) => {
      if (err) throw err;
      if (result === true) {
        return done(null, user);
      }else{
        return done(null, false);
      }
    })
  })
}));

And here is my App.ts file where I guess is where my passport along with my configuration should be initialized:

import passport from "passport";


class App {
  public express: Application;
  public port: number;

  constructor(controllers: Controller[], port: number) {
    this.express = express();
    this.port = port;

    this.initialiseDatabaseConnection();
    this.initialiseMiddleware();
    this.initialiaseControllers(controllers);
    this.initializeErrorHandling();
  }

  private initialiseMiddleware(): void {
    this.express.use(helmet());
    this.express.use(cors());
    this.express.use(morgan("dev"));
    this.express.use(express.json());
    this.express.use(express.urlencoded({ extended: false }));
    this.express.use(compression());
    this.express.use(bodyParser.json());
    this.express.use(bodyParser.urlencoded({extended: true}));
    this.express.use(expressSession({
      secret: String(process.env.SECRET_KEY),
      resave: true,
      saveUninitialized:true
    }));
    this.express.use(cookieParser(process.env.SECRET_KEY));
    this.express.use(passport.initialize());
    this.express.use(passport.session());
  }

  private initialiaseControllers(controllers: Controller[]): void {
    controllers.forEach((controller: Controller) => {
      this.express.use("/api", controller.router);
    });
  }

  private initializeErrorHandling(): void {
    this.express.use(ErrorMiddleware);
  }

  private initialiseDatabaseConnection(): void {
    const { MONGO_USER, MONGO_PASSWORD, MONGO_PATH } = process.env;

    mongoose.connect(
      `mongodb+srv://${MONGO_USER}:${MONGO_PASSWORD}${MONGO_PATH}`
    );
  }

  public listen(): void {
    this.express.listen(this.port, () => {
      console.log(`App listening on port ${this.port}`)
    });
  }
}

export default App;

How do I initialize my passport as middleware along with my passport configuration to start using my local strategy in my routes? I mostly find examples where the configuration lies in the same file along with the routes which doesn't work in my case. Also I can't seem to find official documentation with typescript, I would appreciate it if you could link it along with your answer.

Edit: To give a few more details, what I basically want to do is to initialize my strategy so I can use passport as a middleware in my routes like that:

this.router.post(
      `${this.path}/login`,
      passport.authenticate("local", (req, res) => {
        res.send("Successfuly authenticated");
      })
    )

Note those 3 code blocks come from 3 different files, passportConfig.ts, App.ts, userController.ts, accordingly.

Lastly here is how I initialize my controller on a different file:

const app = new App([new PetController(), new UserController()], Number(process.env.PORT));

app.listen();

TL;DR:

I guess I need to require the config like this but in TS: require('./path/to/passport/config/file')(passport);. Please point out if there is any other mistake to why my local strategy isn't being recognized.

Upvotes: 3

Views: 858

Answers (3)

vbg
vbg

Reputation: 778

You need to install types for Passport.js:

npm install -D typescript @types/passport

Upvotes: 0

Kypps
Kypps

Reputation: 346

If you're trying to get the LocalStrategy which is located in the config file in another file, you can simply export the variable. For example,

In the passportConfig.ts file,

export const LocalStrategy = passportLocal.Strategy;

And in another file such as App.ts, you can import { LocalStrategy } from './passportConfig'; and call the LocalStrategy variable.

Upvotes: 0

Gary Archer
Gary Archer

Reputation: 29301

Some preferences of mine below, for an object based approach that works the same in any API technology and (I think) leads to clean testable code. Feels like some of this may be relevant to your use case.

CONFIGURATION LOADING

An option I commonly use is a JSON file deployed with built code, that can be different for different stages of your pipeline. This follows continuous delivery best practice of build binaries once, then deploy multiple times.

In your case, create a Typescript class that wraps passport, similar to how my authenticator class wraps use of a JWT library. Secrets should be handled with more care than in my example though, eg by encrypting them.

DEPENDENCY INJECTION

Out of interest, more advanced DI in Node is possible also, where config is registered as a singleton dependency at app startup and then injected into classes that need it. For an example that uses Inversify, see my advanced Node API. This is probably overkill at the moment but can be useful as the code base becomes larger.

Upvotes: 1

Related Questions