logo
    • Home
    • Categories
    • About
  • en-languageEnglish
NodejsBy Pierre Colart

NestJs - Authentication

Introduction

Authentication is a crucial aspect of many modern web applications. Authentication involves verifying a user's identity before allowing them access to the application's protected resources. In Nest.js, authentication can be implemented using a variety of authentication strategies such as JWT (JSON Web Token), OAuth, OAuth2, and many others.

In Nest.js, you can implement authentication using the authentication middleware provided by the framework or by writing your own custom authentication middleware. Authentication middleware are functions that run before the request is processed by your application and verify the user's identity based on the configured authentication strategies.

Passport

Passport.js is a very popular authentication library for Node.js. It makes it easy to add authentication strategies to an application, such as password authentication, social media authentication, or third-party service authentication. NestJS is a Node.js framework for building highly scalable and performant backend applications.

Integrating Passport.js with NestJS is relatively simple and offers many possibilities for managing authentication effectively and securely. By using Passport.js with NestJS, it is possible to set up authentication strategies based on tokens, cookies, sessions, or even protocols such as OAuth2.

One of the main features of Passport.js is its modularity. It is possible to add custom authentication strategies based on the application's needs. In addition, Passport.js offers great flexibility when it comes to error handling, customizing error messages, as well as managing user sessions.

Thanks to the integration of Passport.js with NestJS, it is possible to set up secure and customized authentication for your backend application. Whether for web applications, APIs, or mobile applications, using Passport.js with NestJS is a preferred solution for managing user authentication.

Passport.js allows for the implementation of different authentication strategies to allow a user to identify themselves on an application. Among the most commonly used strategies is the "local strategy", which allows a user to authenticate using their email and password. This strategy is used in most cases, to allow users to sign in with their own account on the application.

Another commonly used strategy is the "jwt strategy", which allows a user to authenticate using a token. This strategy is often used for applications that use a token-based authentication protocol such as OAuth2. The "jwt strategy" uses the jsonwebtoken library to verify the validity of the token provided by the user.

In addition to the "local" and "jwt" authentication strategies, Passport.js also allows for the implementation of authentication strategies based on social media or third-party services. For example, the "GoogleOAuth" strategy allows a user to authenticate using their Google account, while the "Facebook" and "Twitter" strategies allow a user to authenticate using their Facebook or Twitter account, respectively.

Implementation

To set up Passport, three elements need to be taken into account:

  • Authentication strategy: This is used by Passport to verify the identity of the user when they log in to the application. Passport offers different authentication strategies such as "local", "JWT", "OAuth", etc. In this case, we will use the "passport-jwt" strategy.

  • Application middleware: This allows us to define how Passport will be used in the application. For example, it is possible to configure the routes that require authentication or to define custom error messages.

  • Session (optional): This allows us to store the user's authentication information in a session. If the session is not used, authentication information will need to be provided with each request.

Once these elements are configured, Passport can be used to secure the application's routes. When a user attempts to access a protected route, Passport verifies their identity using the configured authentication strategy.

To install the "passport-jwt" strategy, you can use the following npm commands:

 npm i passport-jwt @types/passport-jwt
npm i jsonwebtoken @types/jsonwebtoken

Authentication module

This module allows us to configure the JWT (JSON Web Token) authentication strategy using the "passport-jwt" package. To do this, it extends the "Strategy" class provided by this package. Here is an example of this class:

 @Injectable()
export default class JwtStrategy extends Strategy {
   constructor(private readonly authenticationService: AuthenticationService) {
       super({
            jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
            passReqToCallback: true,
            secretOrKey: 'secret'
        }, async (req, payload, next) => {
            return await this.verify(req, payload, next);
        });
        passport.use(this);
    }

   public async verify(req, payload, done) {
       const isValid = await this.authenticationService.validateUser(payload);
        if (!isValid) {
           return done('Unauthorized', null);
        } else {
           return done(null, payload);
        }
   }
}

The constructor of this class allows for passing different configuration parameters:

  • The "jwtFromRequest" option accepts a function for extracting the JWT token from the request. In this example, the "ExtractJwt.fromAuthHeaderAsBearerToken()" function is used to select the token from the request header using the "Authorization" header and selecting the token following the word "Bearer".

  • The "passReqToCallback" parameter takes a boolean to indicate whether you want to get the request (req) in the verification method (verify) that will be called later.

  • The "secretOrKey" parameter takes a string or buffer to verify the token signature.

Other parameters are available to configure the strategy, but they are not necessary for this authentication.

Next, we pass a callback function "verify" which is intended to verify if the token is valid and if the payload obtained from the token is valid or not. This function is asynchronous and executes the "verify" method which calls the authenticationService to validate the user with the payload passed as a parameter.

If the user is valid, we return the payload, otherwise we return an error to indicate that the payload is not valid.

Authentication service

As mentioned earlier, to verify the payload obtained from the token, it is necessary to call the "validateUser" method provided by the "AuthenticationService" service. This service will also implement a method to generate the token for the logged-in user.

Here is an example implementation of this service:

 @Injectable()
export class AuthenticationService {
   constructor(private readonly userService: UserService) { }

   createToken(email: string, ttl?: number) {
        const expiresIn = ttl || 60 * 60;
        const secretOrKey = 'secret';
        const user = { email };
        const token = jwt.sign(user, secretOrKey, { expiresIn });
        return {
            expires_in: expiresIn,
            access_token: token,
        };
   }

   async validateUser(payload: { email: string; password: string }): Promise<boolean> {
        const user = await this.userService.findOne({
            where: { email: payload.email }
        });
        return !!user;
   }
}

This service injects the "UserService" service to find the user corresponding to the payload passed to the "validateUser" method. If the email present in the payload can find the user and if that user has a valid token, they can proceed with the authentication process.

To provide a token to the user attempting to log in, the service implements the "createToken" method, which takes an email and an optional TTL as parameters. The TTL (Time-To-Live) is used to define the lifespan of the token, in seconds. In the given example, the default TTL is one hour (60 * 60 seconds).

The "createToken" method uses the "jsonwebtoken" package to sign the token using a secret key. The token contains the user's email and a validity period defined by the TTL. The method returns an object containing the token's validity period and the token itself.

Conclusion

In conclusion, we have seen how to configure the JWT authentication strategy with the "passport-jwt" package and how to implement the "AuthenticationService" service to verify the token payload and generate a valid token for the logged-in user. We have also seen how to use the "createToken" method of this service to generate a token, which will then be used to secure the routes of the application.

Configuring the JWT strategy and validating the token are crucial steps in securing a web application. By using Passport and associated packages, we can easily set up a secure authentication system based on JWT tokens.

It is important to note that the security of the application is not limited to authentication. Other security measures, such as protection against SQL injections and authorization checks, must also be put in place to ensure that the application is secure and protected against malicious attacks.

Pierre Colart

Passionate developer and architect who wants to share their world and discoveries in order to make things simpler for everyone.

See profil

Latest posts

Sequences, Time Series and Prediction

© 2023 Switch case. Made with by Pierre Colart