How to implement Facebook Login with NestJS
Published: 2020-08-20 16:55:56

[NestJS](https://docs.nestjs.com) is a relatively new framework that has been growing in popularity for many good reasons. It has full support for TypeScript and it combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming) to enable developers build scalable and coherent server-side applications.

## Requirements

Below is a list of software required to follow along as we setup facebook login with NestJS:

- Facebook account
- NodeJS
- [Yarn](https://classic.yarnpkg.com/en/docs/install)

## Project Setup

NestJS comes with a convenient CLI that can be used to scaffold a new NestJS project.

Install the CLI globally using the following command:

```sh
npm i -g @nestjs/cli
```

Scaffold a new project using the command:

```sh
nest new <project-name>
```

For this project,you use a descriptive name as shown below:

```sh
nest new nest-facebook-auth
```

The CLI will prompt you to choose a package manager between `yarn` or `npm`.you be using [yarn](https://classic.yarnpkg.com/en/docs/install) for this project.

After the setup is complete, you can open the project in your favorite editor and you should have a folder structure like this:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0cyjrgr5vdkswho7px4v.png)

### Dependencies

To implement facebook login, we need to add a few dependencies to the project:

- dotenv
- passport
- passport-facebook
- @nestjs/passport

The dotenv package will be used to load environment variables and passport will be used to manage authentication. Add the packages using the following command:

```sh
yarn add dotenv @nestjs/passport passport passport-facebook
```

To add static typing for `passport-facebook`, we need to install one more dependency:

```sh
yarn add @types/passport-facebook
```

## Create Facebook App

Visit https://developers.facebook.com to create a Facebook app. If you don't have a developer account, click on **Get Started** at the top right of the screen. After setting up your account, you should see the dialog below:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/4kcaa29uho7uejpka24c.png)

Click on **Create First App** and fill in the details for your desired app name and contact info. You can give yours a different name than the one below:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7j5vxvetwheagczr6wg0.png)

Once your app is created, you should see a dashboard that looks similar to the one below. Click on **Set Up** Facebook Login.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ek1lmdywcx74oml6r4tf.png)

Select **Web** and fill in your website's URL (without any paths). Since this is just for testing, our request will be coming from localhost, so enter http://localhost:3000 and click **Save**.

Just like this:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/nrwvnvtljjpjcqobz37w.png)

### Get and Save Credentials

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/2uuvf5rupkksqdjhq3il.png)

To get your app credentials, click on **Settings** on the left side menu and click on **Basic**. Copy your **App ID** and **App Secret**.

Create a new `.env` file in the NestJs project's root directory. Store your app credentials as environment variables for security reasons:

```conf
APP_ID=<your_app_id>
APP_SECRET=<your_app_secret>
```

**NOTE:** make sure you add `.env` to your `.gitignore` to prevent it from being added to git. At the bottom of your `.gitignore`, add the following:

```sh
# Environment
.env
```

## Implement Facebook Login

To import the saved environment variables, add the following code to the top (and below other imports) of your `main.ts` file in the `src` folder

```ts
import * as dotenv from "dotenv";

dotenv.config();
```

Since we're using passport to implement Facebook Login, we need to create a passport strategy. To do that, create a `facebook.strategy.ts` file in the `src` folder and add the code below:

```ts
import { Injectable } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { Profile, Strategy } from "passport-facebook";

@Injectable()
export class FacebookStrategy extends PassportStrategy(Strategy, "facebook") {
  constructor() {
    super({
      clientID: process.env.APP_ID,
      clientSecret: process.env.APP_SECRET,
      callbackURL: "http://localhost:3000/facebook/redirect",
      scope: "email",
      profileFields: ["emails", "name"],
    });
  }

  async validate(
    accessToken: string,
    refreshToken: string,
    profile: Profile,
    done: (err: any, user: any, info?: any) => void
  ): Promise<any> {
    const { name, emails } = profile;
    const user = {
      email: emails[0].value,
      firstName: name.givenName,
      lastName: name.familyName,
    };
    const payload = {
      user,
      accessToken,
    };

    done(null, payload);
  }
}
```

The first argument to `PassportStrategy` is `Strategy` which comes from `passport-facebook`. The second argument tells passport the **name** of the strategy which in our case is `facebook`.

To be able to use the newly created strategy, we need to include it as a provider in our app module. Open `app.module.ts` in the `src` folder and replace it with:

```ts
import { Module } from "@nestjs/common";

import { AppController } from "./app.controller";
import { AppService } from "./app.service";
import { FacebookStrategy } from "./facebook.strategy";

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService, FacebookStrategy],
})
export class AppModule {}
```

## Add login route

Finally, we need to add the API endpoint/route for facebook login. In NestJS, routes are handled by controllers.you implement facebook login in `app.controller.ts` as follows:

```ts
import { Controller, Get, UseGuards, HttpStatus, Req } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";
import { Request } from "express";

import { AppService } from "./app.service";

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }

  @Get("/facebook")
  @UseGuards(AuthGuard("facebook"))
  async facebookLogin(): Promise<any> {
    return HttpStatus.OK;
  }

  @Get("/facebook/redirect")
  @UseGuards(AuthGuard("facebook"))
  async facebookLoginRedirect(@Req() req: Request): Promise<any> {
    return {
      statusCode: HttpStatus.OK,
      data: req.user,
    };
  }
}
```

The last two routes are responsible for the entire login flow. The first one initiates facebook login. The second route is where facebook will redirect the user to after a successful login.

## Test App

Run in development mode using the following command:

```sh
yarn start:dev
```

Navigate to the facebook endpoint in your browser: http://localhost:3000/facebook. You'll be prompted to log in with facebook as shown below:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/sne7gs6df5n8rz4w259z.png)

After a successful login, you'll be redirected to http://localhost:3000/facebook/redirect and you'll get the response as defined in the `facebookLoginRedirect` controller. See an example response below:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/o346st3e5pym8l1gvlyg.png)

🎉🎉🎉, you have successfully implemented facebook login. The code for this project can be found on GitHub: https://github.com/elishaking/nestjs-facebook-login

If you encountered any issues, feel free to leave a comment below or reach me @ElishaChibueze.

I love making these articles, so please I'd love to know your suggestion on topics you'll like me to explore.

❤️ the article _**?\*\*\*\***?**\*\***?\*\*_ I loved making it.