Reputation: 157
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
Reputation: 778
You need to install types for Passport.js:
npm install -D typescript @types/passport
Upvotes: 0
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
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