Learning to build an API in NestJS (Node + Typescript) - Part 03
Tags: node, nestjs, typescript, beginners
Published: 2022-11-17 01:02:36

Back again for the third round of NestJS goodness. :sunglasses:

If you didn't read the past two articles... you should! This is a _process-oriented series_, so every article builds on the last one.

Last time we managed to implement a super basic service, inject it into a controller, route endpoints properly, capture params (query parameters, URI embedded parameters, and request body), and import a module to the main module.

Now we are going to apply this new knowledge by building useful stuff. We start by coding a semi-public authentication scheme. No users, for now, just an unguarded endpoint that always returns a valid token. The rest of the endpoints should be guarded.

The first question that comes to my mind is ¿How do we generate a token?...

## Generating a Token
NestJS has a `JwtModule` we can install ([docs](https://github.com/nestjs/jwt/blob/master/README.md)). :heart:
```bash
npm i @nestjs/jwt
```
It has a service that can _sign_ a user token. This should be used by our AuthenticationService to execute the _sign in_ action.

```ts
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';

@Injectable({})
export class AuthenticationService {
  constructor(private readonly jwtService: JwtService) {
    this.jwtService = jwtService;
  }
  async signIn(user: any): Promise<any> {
    // Here we should map the user entity to a stripped-down object
    const userInfo = { username: 'username', sub: 'sub' };
    return this.jwtService.sign(userInfo);
  }
}
```
Remember that if we use a service, we need to import the module where it came from. This specific import has a few configuration parameters that need to be provided. These involve the expiration time of the token, the hashing algorithm, the secret key, etc... These parameters come from the underlying library [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken#usage).
So at `AuthenticationModule`, we will import `JtwModule` with just a fantasy secret:
```ts
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { AuthenticationService } from './authentication.service';
import { JwtModule } from '@nestjs/jwt';

@Module({
  imports: [PassportModule, JwtModule.register({ secret: 'secret-key' })],
  providers: [AuthenticationService],
})
export class AuthenticationModule {}
```
## Get the token for future requests
So now we should create a _sign in_ endpoint which will return our token.
```ts
// All other imports
// ...
import { AuthenticationService } from 'src/authentication/authentication.service';

@Controller('example')
export default class ExampleController {
  constructor(
    private readonly exampleService: ExampleService,
    private readonly authenticationService: AuthenticationService,
  ) {}

  @Get('sign-in')
  async signIn() {
    return await this.authenticationService.signIn({});
  }

  // All the other endpoints
  //...
}
```

That is looking good. The next step is to guard the rest of the endpoints by checking if there is a valid bearer token in the authorization header of the request. For that, we need to implement an authentication step in the server pipeline.

## Implementing Passport
Looking at the official documentation, there is an [authentication section](https://docs.nestjs.com/security/authentication). It introduces the `passport` library.

Passport gives us the middleware responsible for parsing the request and validating that the jwt token is valid.

We need to install the core Node library (`passport`), the underlying code to support a jwt _strategy_ (`passport-jwt`), the NestJS wrapper (`@nestjs/passport`), and some types for development easiness (`@types/passport-jwt`).

```bash
npm install passport passport-jwt @nestjs/passport
npm install -D @types/passport-jwt
```
So how does Passport know if the jwt token is valid?

### Configuring Passport JWT Strategy
In the same way, we configured NestJS's JwtModule for building our jwt tokens, Passport will need to be configured with the same parameters to be able to parse correctly the token.

To go alongside the convention, this configuration goes in a `jwt.strategy.ts` file inside the authentication folder. It defines a class that is responsible for extending the base passport strategy class with the configuration needed. This includes implementing a `validate` function which will consume a user validation callback (we need to code this callback). This class will be available through `AuthenticationModule` as a [provider for the rest of the application to use](https://docs.nestjs.com/providers). This implies that the strategy class should be decorated with `@Injectable()`. The file should look something like this:

```ts
// import the specific strategy from Passport
import { Strategy } from 'passport-jwt';
// import NestJS passport wrapper
import { PassportStrategy } from '@nestjs/passport';
// import the Injectable decorator to allow this class to be imported into the AuthenticationModule
import { Injectable } from '@nestjs/common';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super();
  }
}
```

For this to work properly we need to add some parameters to the base constructor. We will provide the two most basic ones:
* `jwtFromRequest`: Defines where to find the jwt token
 (it could be another place than the authorization header...). We will stick with the classic _Bearer_ schema. For that, the value should be `ExtractJwt.fromAuthHeaderAsBearerToken()`. This seems to map to [this](https://www.passportjs.org/packages/passport-jwt/#extracting-the-jwt-from-the-request) and [this](https://www.passportjs.org/packages/passport-jwt/#included-extractors) parts of the passport documentation about extracting the jwt token from the request.
* `secretOrKey`: The key that will sign the tokens provided by our app. For demo purposes, the value will be `"secret-key"`. This seems to map to [this part of the passport documentation](https://www.passportjs.org/packages/passport-jwt/#usage)

The file ends up looking like this:

```ts
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthenticationService } from './authentication.service';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(private authenticationService: AuthenticationService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      secretOrKey: 'secret-key',
    });
  }

  async validate(userInfo: any): Promise<any> {
    // This method needs to be implemented right now
    const user = await this.authenticationService.validateUser(userInfo);
    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}
```

Now we are missing the user validation callback.

### User validation
Passport requires a callback from us which will be used to validate a user. That validation callback receives the supposed user information as interpreted by the passport middleware. So with that information, we have to execute the validation process.

For this jwt strategy scenario, as we defined how our tokens are built, Passport already knows if the token is valid before the user validation. So what gets passed to our callback is the decoded jwt token. This is implied in this passage of the [passport documentation](https://www.passportjs.org/packages/passport-jwt/#usage).

Here we can add some logic if we wanted to. The only constraint is that if the validation es correct, we should return an object with useful user information (this info will be available at a `user` property of the request object). If not, the return value should be null. In our case, the validation will always succeed because we won't have users. Nonetheless, that validation callback needs to be implemented and should be placed in the AuthenticationService.

```ts
import { Injectable } from '@nestjs/common';

@Injectable({})
export class AuthenticationService {
  validateUser(userInfo: any): boolean | null {
    // Passport expects this return value to be a user object when validation is successful.
    // That info will be available at a `user` property in the `request` object
    return true;
  }

  // SignIn method
  // ...
}
```
For the module to work, we need to import the recently installed `PassportModule`. Also, the Authentication Service should be exposed as an export. So the file will look like this:
```ts
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { AuthenticationService } from './authentication.service';
import { JwtModule } from '@nestjs/jwt';

@Module({
  imports: [PassportModule, JwtModule.register({ secret: 'secret-key' })],
  providers: [AuthenticationService],
  exports: [AuthenticationService],
})
export class AuthenticationModule {}

```

## Guard endpoints
What remains is to guard our endpoints. Last step to finish this one up. :muscle:

NestJS Passport wrapper provides us with an AuthGuard decorator. You can provide the strategy name for the guard, but it is better to extend the class to a specific one per strategy basis. That way the code is cleaner and easier to maintain. This is evident when you use more than one strategy. For now, we just have de jwt one, but when adding users and logging in, that endpoint should be guarded by the _local_ strategy which is based on username and password.

```ts
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class JwtGuard extends AuthGuard('jwt') {}
```
Then import the guard in the controller and use it!
```ts
@Controller('example')
export default class ExampleController {
  constructor(
    private readonly exampleService: ExampleService,
    private readonly authenticationService: AuthenticationService,
  ) {}

  @Get()
  @UseGuards(JwtGuard)
  index() {
    return this.exampleService.getAll();
  }

  // All other endpoints
  // ...
}
```

Try your endpoints with curl:
```bash
curl http://localhost:3000/example -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwic3ViIjoic3ViIiwiaWF0IjoxNjY3MDc3NzYxfQ.LX2jeE1bavLOk9x-YvBZdEsfOo2ow4fMJ9DT4CYhXiE

curl http://localhost:3000/example
```

![curl result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/76043xla5xjmze833c8f.png)

## Wrap up
This concludes the third article of this series. Today we covered how to create a JWT token and validate it using the Passport library and guarding our endpoints with custom guards extending from the NestJS Passport wrapper.

Next, we should start including users to make this authentication more realistic. For that, we need to use a database. So that will be the next step. Set up a database, choose a library to interact with it, successfully self-sign up to the app, and then be able to log in (log out will be left for another time...).

That's all for now! thanks for reading. I hope these articles are useful to you. Have fun and keep learning!