Implementing Facebook Login with Angular and REST API

Today, I am going to show you how to create an Angular App with a REST API that uses Facebook Login to sign in/up users. For this application, we are going to be using PHP in our backend, but this can work with any Framework or Language for the backend.

First Thing First

The login flow of the app will work something like this: when a user clicks on Login with Facebook, the user is redirected to Facebook to give your app permission. In return, your app will receive an Access Token and some other personal information from Facebook.  But the Golden rule here is never trust anything that comes from the user.

So, your app will only send the token received from Facebook to the REST API. Which in turn will verify with Facebook whether it is genuine and request personal information from Facebook.

Once the REST API has verified the details as genuine, go ahead and check whether the user exists in the database. if the user exists, go ahead and log the user in. If the user is not signed up, go ahead and sign the user up and log the user in. You can also send a welcome/confirmation email at this point.

Create a Facebook Application

For this to work, you need a Facebook application. Head over to Facebook Developers portal and create an app as demonstrated by the YouTube video below:

Adding Login with Facebook Button to your App

Assuming you have successfully setup your Facebook App successfully, you should have an App Id and App Secret. For the angular application, we are going to only need the App Id, the app secret will be used by the REST API.

For social login, we are going to be using angularx-social-login npm module. You can install it using the command below

 npm install --save angular5-social-login 
Or
 yarn add angular5-social-login

After you have successfully installed the module, Import it in the app.modules.ts in your project.

import { SocialLoginModule, AuthServiceConfig } from "angular5-social-login";import { FacebookLoginProvider } from "angular5-social-login";

Then create a new file socialloginConfig.ts in the root of your project and add a config file for social login:

import { AuthServiceConfig, FacebookLoginProvider } from "angular5-social-login"; 

export function getAuthServiceConfigs() 
{
  let config = new AuthServiceConfig([
    {
      id: FacebookLoginProvider.PROVIDER_ID,
      provider: new FacebookLoginProvider("{FACEBOOK_APP_ID_HERE}")
    }
  ]);
   return config;
}

Then import the config file into your app modules:

import { getAuthServiceConfigs } from "./socialloginConfig ";

And finally import SocialLoginModule and declare providers for SocialLoginModule as show below

@NgModule({  imports: [ 
   ...
    SocialLoginModule
  ],  
providers: [
    ...
    {
      provide: AuthServiceConfig,
      useFactory: getAuthServiceConfigs
    }
  ],
  bootstrap: [...]
})

On your Sign in Component

Then, on your sign in component (or wherever you wish to add this button), import the AuthService, FacebookLoginProvider as shown below:

import {    AuthService,    FacebookLoginProvider,    GoogleLoginProvider} from 'angular5-social-login';

And Inject AuthService into your component as shown below:

constructor( private socialAuthService: AuthService ) {}

Note: If you are like me, you may already have another AuthService Service, you can import the new AuthService as an ALIAS as shown below:

import {    AuthService as SocialAuthService,    FacebookLoginProvider,    GoogleLoginProvider} from 'angular5-social-login';

And then Inject SocialAuthService into your component as shown below:

constructor( private socialAuthService: SocialAuthService ) {}

Now, it’s a simple matter off adding a Facebook login method and a button. The method should look like this:

public facebookLogin() {
    let socialPlatformProvider = FacebookLoginProvider.PROVIDER_ID;
    this.socialAuthService.signIn(socialPlatformProvider).then(
      (userData) => {
              //this will return user data from facebook. What you need is a user token which you will send it to the server
              this.sendToRestApiMethod(userData.token);
       }
    );
}

On success – the user has granted your app permission – then send the token from user data received to the REST API. There is no need to send other personal information such as email and name as the REST API will get that information for itself. Your sendToRestApiMethod() should look like this.

sendToRestApiMethod(token: string) : void {
    this.http.post(“url to facebook login here”, { token: token } }
        .subscribe(onSuccess => {
                       //login was successful
                       //save the token that you got from your REST API in your preferred location i.e. as a Cookie or LocalStorage as you do with normal login
               }, onFail => {
                       //login was unsuccessful
                       //show an error message
               }
        );
}

(You should put it inside an Authentication Service together with other related authentication services)

And finally add the Login with Facebook button:

<button (click)=”facebookLogin()” >Login with Facebook</button> 

Integrating with a REST API

And Finally, to the REST API. I will demonstrate this using PHP, but you can use any language you wish, you can get detailed support for your specific language here. (Scroll to the section for Facebook Login and User Profiles). Since you already have a App Secret and App ID and Access Token (Sent from the Angular App), this one is rather straight forward. In your PHP Method/Script for handling Facebook login, add the following code:

1. Initialize connection to Facebook API using the PHP SDK

$fb = new \Facebook\Facebook([
    'app_id' => "APP ID HERE",
    'app_secret' => "APP SECRET HERE"
    'default_graph_version' => 'v2.12', 
]);

Replace the APP ID HERE and APP SECRET HERE with your specific details from your Facebook app.

2. Send the access token received from the client app and request user id, name and email address of the user from Facebook. This will return those details if the access token is genuine and will fail if it isn’t.

try {       
      $fbresponse = $fb->get('/me?fields=id,name,email', "Access Token Here");
} catch (\Facebook\Exceptions\FacebookResponseException $e) {        
      //Handle this error, return a failed request to the app with either 401 or 500
} catch (\Facebook\Exceptions\FacebookSDKException $e) {       
      //Handle this error, return a 500 error – something is wrong with your code
}

3. Finally, do something with the data you received from Facebook. You can check if the user exists in your user database by both email and Facebook user Id, if they exist, sign them in and if they don’t exist sign them up. You can also check if the email address is associated with another user and if so, just associate the Facebook account to the account with the email address. This is all up to you, you can handle it any way you want. You can get the Facebook User Id, Names and Email as shown below:

$me = $fbresponse->getGraphUser();
$userId = $me->getId();
$email = $me->getEmail();  
$name = $user->name()

8 Replies to “Implementing Facebook Login with Angular and REST API”

    1. Can you share the component you are running this on so I can have a look at it (you can skip all the other methods functions). I am thinking that most probably it’s something that you are not importing.

      1. I think the problem is one of imported class, cause my component can be empty and when I add import line then error occures when component is loading.

        import { Component, OnInit } from ‘@angular/core’;
        import { AuthService, FacebookLoginProvider, SocialUser } from ‘angular5-social-login’;

        @Component({
        selector: ‘app-test’,
        templateUrl: ‘./test.component.html’,
        styleUrls: [‘./test.component.scss’]
        })
        export class TestComponent implements OnInit {

        constructor(private socialAuthService: AuthService ) { }

        ngOnInit(): void {
        this.socialAuthService.authState.subscribe(state => {
        console.log(state);
        });
        }

        signInWithFacebook() {
        this.socialAuthService.signIn(FacebookLoginProvider.PROVIDER_ID).then(userData => {
        console.log(userData);
        });
        }
        }

        1. Using the above component, I have successfully build in AOT without any issues. It may be an issue in your Module File or if you are using Lazy Loading in your project, it may be causing some issues. Can I see the error you get when you add the import line, it could be a collision of imported items names or something. Please share the error so i can help you more.

          1. Injection of AuthService in my component causes
            ERROR TypeError: FB.init is not a function
            at HTMLScriptElement.eval [as __zone_symbol__ON_PROPERTYload] (angular5-social-login.umd.js:307)
            at HTMLScriptElement.wrapFn (zone.js:1166)
            at ZoneDelegate.invokeTask (zone.js:421)
            at Object.onInvokeTask (core.js:4740)
            at ZoneDelegate.invokeTask (zone.js:420)
            at Zone.runTask (zone.js:188)
            at ZoneTask.invokeTask [as invoke] (zone.js:496)
            at invokeTask (zone.js:1517)
            at HTMLScriptElement.globalZoneAwareCallback (zone.js:1543)

          2. I am assuming the AuthService you are referencing in this comment is your custom service that you have build your self. If that is the case, the error occurs because you are importing two AuthService, one from angular5-social-login and the other from the component. This is why i recommended importing the AuthService from Anguler5-social-login component as an ALIAS as follows:

            import { AuthService as SocialAuthService, FacebookLoginProvider, GoogleLoginProvider} from 'angular5-social-login';

            And then inject it as follows:

            constructor( private socialAuthService: SocialAuthService ) {}

            And then inject your other AuthService as you normally would. Hope this helps you, if it doesn’t please provide all the imports when its producing an error so i can try and replicate your problem.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.