Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js authentication using passport and typescript: cannot find req.user

I am currently working on a authentication service for a node.js microservices application using typescript, WebStorm, passport and jwt. While trying to add the route to "/api/login", I am noticing that the intellisense does not seem to pick up the user object of req.user or the authorization object of req.header.authorization. For example, the following method is not working because it can not find the user object:

private generateToken(req: Request, res: Response, next: NextFunction){
req.token = jwt.sign({
  id: req.user.id,
  firstname: req.user.firstname,
  lastname: req.user.lastname,
  roles: req.user.roles
}, process.env.AUTH_KEY, {
  expiresIn: "7d"
});
return next();
}

I am using the Request object from express:

import { NextFunction, Request, Response, Router } from "express";

Would I need to use a different Request object?

Also, if I need to force authentication to certain api routes but lock other routes down, how should this be done using passport-jwt? I know there is an express-unless package that I can use for express-jwt.

like image 571
user1790300 Avatar asked May 15 '17 18:05

user1790300


People also ask

What is passport authentication in Node JS?

Authentication entails matching users credential to file or database which could be in a local file system or an authentication server and if they exist, they are given access to protected resources. Passport is the most popular user authentication external library for Node.js applications.

What is the best external authentication library for nodejs?

Passport is the most popular user authentication external library for Node.js applications. It currently has 17.4k stars on GitHub and provides middleware for over 480 strategies such as simple username and password, social media login such as facebook, twitter, google and many more.

What are the security modules in a NodeJS framework?

Most frameworks have security module in-built. Authentication entails matching users credential to file or database which could be in a local file system or an authentication server and if they exist, they are given access to protected resources. Passport is the most popular user authentication external library for Node.js applications.

How to send password from user model to database using JavaScript?

Note you also call the matchPassword () method on the user model so go to userModel.js file and add it. This method compares the password from the user and the one in the database and returns true if they match. You now need to create the endpoints to which users will send data.


1 Answers

Not sure why this question downvoted, maybe because it should be two separate questions.

You can extend type declarations for Express.

Extending the express type definitions

Add a file library-ext.d.ts into your source directory with this.

declare module 'express' {
  export interface Request {
        user?: any;
    }
}

For req.header.authorization try: req.headers['authorization']. Notice the 's'.

Relating to general authentication

It depends whether your registered users can also use the guest routes. If you never need identity on the guest routes then just register the passport authentication middleware only on the authenticated routes, or split the routes into separate routers. That's fairly simple to do, just search stack overflow or look in the docs for it.

The more complicated case is when you need both authenticated and non-authenticated users to access a route - think either a guest or authenticated customer adding something to a cart. Unfortunately passport-jwt rejects with a 401 when a token is not in the authorzation header, so the easiest way I found, rather than forking the project or rolling my own strategy, was to use middleware to add a known value to represent an otherwise anonymous request. Then just make sure that middleware is before the passport authentication in the affected routes. Here's a snippet to get you going:

CoreCtrl

class CoreCtrl {

  simulateAnonymous(req, res, next) {
    if (!req.headers.authorization) {
      req.headers.authorization = 'Bearer guest-token';
    }
    return next();
  }

}

Then somewhere in your Express Setup

setupRouters() {
    // the public and admin routers are bound to the application
    const coreCtrl = new CoreCtrl(this.serverOpts);
    const anonymousCtrl = coreCtrl.simulateAnonymous.bind(coreCtrl);
    this.routers.admin.use(anonymousCtrl);
    this.routers.admin.use(passport.authenticate('UserBearer', { session: false }));
    this.routers.public.use(anonymousCtrl);
    this.routers.public.use(passport.authenticate('CustomerBearer', { session: false }));
  }

Note that I had separate routers for public and admin set up here, that's not necessary but just to illustrate how to do it.

Then in the bearer strategy, you would have some code similar to this.

/**
* Run the strategy
*
* @param token {String} The JWT Token
* @param done {Callback} Callback function
*/
exec(token:string, done):Promise<any> {
  // this is the workaround to support not passing a token for guest users.
  if (token === 'guest-token') {
    return done(null, {
      userId: 'guest',
      roles: ['guest']
    });
  }
  // otherwise decode the token and find the user.
}

Finally, in some later Middleware you can check if the 'guest' role has access to the protected resource. I'd recommend acl module to manage role-based ACL list.

like image 90
Richard G Avatar answered Sep 28 '22 00:09

Richard G