DEV Community

Cover image for How to implement Facebook Login with NestJS
King Elisha
King Elisha

Posted on

How to implement Facebook Login with NestJS

NestJS 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

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:



npm i -g @nestjs/cli


Enter fullscreen mode Exit fullscreen mode

Scaffold a new project using the command:



nest new <project-name>


Enter fullscreen mode Exit fullscreen mode

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



nest new nest-facebook-auth


Enter fullscreen mode Exit fullscreen mode

The CLI will prompt you to choose a package manager between yarn or npm.you be using yarn 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

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:



yarn add dotenv @nestjs/passport passport passport-facebook


Enter fullscreen mode Exit fullscreen mode

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



yarn add @types/passport-facebook


Enter fullscreen mode Exit fullscreen mode

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

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

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

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

Get and Save Credentials

Alt Text

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:



APP_ID=<your_app_id>
APP_SECRET=<your_app_secret>


Enter fullscreen mode Exit fullscreen mode

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:



# Environment
.env


Enter fullscreen mode Exit fullscreen mode

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



import * as dotenv from "dotenv";

dotenv.config();


Enter fullscreen mode Exit fullscreen mode

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:



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);
  }
}


Enter fullscreen mode Exit fullscreen mode

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:



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 {}


Enter fullscreen mode Exit fullscreen mode

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:



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,
    };
  }
}


Enter fullscreen mode Exit fullscreen mode

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:



yarn start:dev


Enter fullscreen mode Exit fullscreen mode

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

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

๐ŸŽ‰๐ŸŽ‰๐ŸŽ‰, 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.

Top comments (17)

Collapse
 
noorul_amin_d76066b12282 profile image
Noor Ul Amin

when i git the localhost:3000/auth/facebook in the browser i do get a login screen by facebook. After login i do get an error from facebook:
Image description

Collapse
 
hoangdaochuz profile image
hoangdaochuz

I have a similar issue, but I solve it by adding an email scope on facebook app

Image description
I hope this one can help you guys

Collapse
 
tahirmahmudzade profile image
Tahir Mahmudzade

hey did you find the solution for this? I've been getting the exact same error, even though I have tried everything, I'm still stuck with this

Collapse
 
eduwr profile image
Eduardo Wronscki • Edited

you are my hero! Thank you for this article, it was very very useful...

Collapse
 
slavik_semen_be52899bfbcc profile image
Slavik Semen

Thank you.
How protect other routes ?
@Get("/products")
@UseGuards(AuthGuard("facebook")) ?

if i have also Google guard it will be like:
@Get("/products")
@UseGuards(AuthGuard("facebook"))
@UseGuards(AuthGuard("google"))

Collapse
 
yueyuuta profile image
YueYuuta • Edited

I got an error, apparently it does not return the name and email, some help

dev-to-uploads.s3.amazonaws.com/i/...

Collapse
 
usmanashraf678 profile image
Usman Ashraf

I think this shows up if the email of user is not verified.

Collapse
 
embpdaniel profile image
Daniel Montano

Amazing article! One thing to note is if your local front-end runs on a separate port you will have CORS errors with Facebook. To resolve, the front-end MUST use the same port as your server (localhost:3000 in this case) so you'll need to proxy your request made on front-end to get rid of the errors.

Collapse
 
andyogaga1 profile image
Andy Ogaga

Wonderful article Sir....

Collapse
 
quangkhaidev profile image
ฤแป— Quang Khแบฃi

Thank King Elisha, hope you can create a lot of post like this <3

Collapse
 
budazimbud profile image
BudAzimbud

then how to implement logout ??

Collapse
 
linhtran28 profile image
linhtran28

Thank for your sharing, may i ask how can i implement facebook login with graphql project? is it possible without @Req annotation?

Collapse
 
devlugo profile image
Rodolfo Lugo

Hello @linhtran28 , did you found a way to implemenent this?

Collapse
 
bogdy234 profile image
Filimon Bogdan

Any news on this?

Collapse
 
podrimczech profile image
Faton

To anyone getting the "Sorry, something went wrong". Go to facebook app and allow "email" as a scope.