Codementor Events

Third-party authentication with Angular and Asp.net Core Web API.

Published Nov 14, 2019
Third-party authentication with Angular and Asp.net Core Web API.

Manually creating accounts is a pain: we just want to access an app’s services, not spend five minutes setting up emails, passwords, and basic information. That’s why the “Log in with Facebook” and “Login with Google” buttons have become so common across the Internet.

Introduction

In this article, we’ll be implementing 3rd party logins (with Google and Facebook only) on our Angular +Asp.net core web API app. You will be able to get user details such as names, email and profile images and save them into your MSSQL database.

We will be using Visual Studio 2019, Visual studio code, and SQL Server 2017.

Note that this article will not be discussing cookies and tokens, all this article would be discussing is how to get your users to login with a 3rd party on angular and then, how to send those details to your controller API on ASP.net Core.

We’re not building our authentication system 😅.

Prerequisite

Basic Knowledge of Web development. (You can learn here)

Basic Knowledge of ASP.net core and MVC (You can learn here).

Basic knowledge of Angular. (You can learn here).

Basic knowledge of working with Angular and Asp.net core together. (You can learn here).

Google and Facebook accounts. (If you’re reading this, you probably have one already).

Getting Started

We are going to achieve this by enabling our Angular client app to get user data from these 3rd parties. Then send this data to our controller API to handle saving it into our database and any other operation.

Before anything, we’ll need to register our web app on google and facebook’s developer’s platforms to get our client-IDs which we’ll be using to access authorization on their servers. It’s pretty straightforward so we won’t go into details about it.

These pieces of information (Your application IDs) are quite important, so don’t just leave them hanging around. Once registered you can always check for them later.

To register your web app and get a Google client ID, please click here. All you need to do is Configure a project and get the Project’s client ID.

To register your web app and get a Facebook app ID, please click here. All you need to do here is register your app and get the APP ID.

We’ll also need to set up our database. I assume anyone reading this already has some knowledge on ASP.net core so I wouldn’t be going into details like creating a database with EFcore or any of that stuff. That being said, you should create a table in your database (for example UserData) that has the following columns: Id, Firstname, LastName, EmailAddress, PictureURL, Provider.

And with that you’re all set to begin.

Configure our App

To get started and make our Angular login users and get data, we’ll need to get a module that plays a very huge role in all of this. The name of that module is the angularx-social-login module.

The angularx-social-login module is a social login and authentication module for Angular 8 (supports Angular 4+). It supports authentication with google, facebook, twitter, and other providers too and is super easy to use. To find out more about this module, please click here.

To install the angularx-social-login Module, we’ll need to navigate to our ClientApp directory in our Web App and go to our terminal or any form of console and type:

npm i angularx-social-login

So it looks somewhat like this.

\repos\WebApplication5\WebApplication5\ClientApp>npm i angularx-social-login

Once the module has been installed, we can go ahead to start using it in our Angular ClientApp.

First, we’ll have to import the module into our application. So in our app.module.ts file, we’ll have something like this.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { SocialLoginModule, AuthServiceConfig } from 'angularx-social-login';
import { GoogleLoginProvider, FacebookLoginProvider } from 'angularx-social-login';

What we just did was to tell angular that we would like to use the SocialLoginModule, AuthServiceConfig, GoogleLoginProvider, and FacebookLoginProvider from the angularx-social-login module that we just installed.

Next is to configure our 3rd parties with the AuthServiceConfig class. Add this to your app.module.ts file, just after the imports we just added.

let config = new AuthServiceConfig([
     {
        id: GoogleLoginProvider.PROVIDER_ID,
        provider: new GoogleLoginProvider(Google ClientID)
     },
{
        id: FacebookLoginProvider.PROVIDER_ID,
        provider: new FacebookLoginProvider(Facebook AppId)
     },
]);
export function provideConfig()
    {
       return config;
    }

We just configured our app with our 3rd parties with the AuthServiceConfig from the angularx-social-login module using the ID’s we got earlier. If you haven’t gotten your Google/Facebook App IDs please go back to the top to check out the links.

We’ll then go ahead to inject our configurations we’ve just set during the application startup. So we just need to go to our @NgModule decorator and add a few things to its properties. First, we’ll add the initialize class from SocialLoginModule to our imports property and put our config class as parameter. Next, we would specify the services we’ll be needing in the providers’ property. So our @NgModule decorator would be something like this.

@NgModule({
declarations: [
     ///some declerations
  ],
imports: [
   ///some other imports
    SocialLoginModule.initialize(config)
  ],
providers: [
    {
      provide: AuthServiceConfig,
      useFactory: provideConfig
    }
  ],
bootstrap: [AppComponent]
})

Logging in And getting User Data

Now that we’ve configured the angularx-social-login to work with angular, we can now implement it and get user information from our 3rd parties.

Generate a new component in your ClientApp (for example LoginComponent). You’ll need to add some buttons in the template of your Login component and give them the (click) event binder so that our class knows how to respond when we click. Also, add a tag to display error messages. Going ahead to do that, we could come up with something like this

<h5>{{resultMessage}}</h5>
<button (click)="logInWithGoogle('Google')"> Google Login </button>
<button (click)="logInWithFacebook('Facebook')"> Facebook Login </button>
<button  (click)="signOut()" class="btn btn-success Facebook">Sign Out</button>

Then in the component’s class, we’ll need to first import the AuthService, GoogleLoginProvider and, FacebookLoginProvider from the angularx-social-login module. Which should look like this

///some other imports
import { AuthService } from 'angularx-social-login';
import { FacebookLoginProvider, GoogleLoginProvider } from 'angularx-social-login';

Then we inject the AuthService through our constructor. Which should look like this

export class LoginComponent implements OnInit {
//create array to store user data we need
   userData: any [] = [];
// create a field to hold error messages so we can bind it to our        template
   resultMessage: string;
constructor( private authService: AuthService ) { }
ngOnInit() {
    //some code
  }
  

Notice that I created an array field just right before the constructor. Because we want to put the user’s data we need into the array field and send it to an angular service which then sends that data to our Controller API.

This helps us structure our data model on our ASP.net web API. I hope we haven’t forgotten about that guy yet 😅.

Notice that I also created a field called resultMessage so we can bind error messages to our template in case we get any errors or the user cancels the login.

Next, we’ll write the sign In methods for both Facebook and Google.

//logIn with google method. Takes the platform (Google) parameter.
logInWithGoogle(platform: string): void {
platform = GoogleLoginProvider.PROVIDER_ID;
//Sign In and get user Info using authService that we just injected
   this.authService.logIn(platform).then(
(response) => {
//Get all user details
     console.log(platform + ' logged in user data is= ' , response);
//Take the details we need and store in an array
     this.userData.push({
       UserId: response.id,
       Provider: response.provider,
       FirstName: response.firstName,
       LastName: response.lastName,
       EmailAddress: response.email,
       PictureUrl: response.photoUrl
     });
 },
 (error) => {
   console.log(error);
   this.resultMessage = error;
}
//logIn with facebook method. Takes the platform (Facebook) parameter.
logInWithFacebook(platform: string): void {
platform = FacebookLoginProvider.PROVIDER_ID;
//Sign In and get user Info using authService that we just injected
   this.authService.logIn(platform).then(
(response) => {
//Get all user details
     console.log(platform + ' logged in user data is= ' , response);
//Take the details we need and store in an array
     this.userData.push({
       UserId: response.id,
       Provider: response.provider,
       FirstName: response.firstName,
       LastName: response.lastName,
       EmailAddress: response.email,
       PictureUrl: response.photoUrl
     });
 },
 (error) => {
   console.log(error);
   this.resultMessage = error;
}

The major difference between both methods is the platform being used. They both implement the authService class and since we don’t expect users to use both methods to login, we can reuse the array.

Lastly, we’ll add a method that log users out of our application regardless of what platform you used to log in. Our log out method should be something like this.

logOut(): void {
    this.authService.signOut();
    console.log('User has signed our');
  }

Note:

If you’re getting any errors when trying to access the google 3rd party Login, It may be because Google has ‘blacklisted your site’ from accessing its servers. Google restricts URLs that have a javascript origin. To clear this error you’ll have to go to console.developer.google.com and navigate to the credentials of the project you created earlier (the one you used to get the ClientID). You should see a list of credentials. Click on the OAuth client

medium post 2.jpg

In the OAuth client credential, you can whitelist some URLs. For example, for one of my projects, I’ve whitelisted 2 URLs as shown below; one runs my angular app separately, the other runs it with ASP.net.core

medium post.jpg

You can see both URLs in the Authorised Javascript origins subheading.

ASP.net Core (Our backend guy)

We’ve been able to get our User’s data, now all that remains is to send this data to our API and tell ASP.net core to save this into our database. We’ll start this section with getting ASP.net core ready to accept and store this data.

Since we’ve created and already defined the table we’ll be using in our database, we’ll go ahead to define our model, create the Login method in our API controller and get it ready for communication with Angular. In that order.

To define our Model, we’ll need to leave the ClientApp directory and navigate to the Models directory. Create a new Model class if you don’t have one and add this:

public class LoginModel{
public string UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public string PictureUrl { get; set; }
public string Provider { get; set; }
}

You’ll notice that the fields are the same with the columns we specified for the table we created at the beginning of this article.

Let’s save that and leave our Models directory and navigate to our Controllers directory. If you don’t already have a controller, create a new one.In your controller, you’ll need to create a method that accepts user data as a parameter of type LoginModel that we created earlier.

With the data we’ll be getting, we can create a new record of UserData (the table we created at the beginning) named user. Then we can go-ahead to add the user to our database and then save it.

Lastly, we’ll return a message saying user login was successful. All these happens if our model state is valid (which is very important!). If our model state isn’t valid it returns errors explaining why it’s not valid.

At the end of the day, our AccountController looks like this:

[Route("api/[controller]")]
public class AccountController : Controller {
private readonly ApplicationDbContext _db;
public AccountController( ApplicationDbContext db) {
_db = db;
}
[HttpPost("[action]")]
public IActionResult Login([FromBody] LoginModel userdata) {
if(userdata != null) {
var alreadySaved = _db.UserData.Where(Uid => Uid.UserId == userdata.UserId).FirstOrDefault();
if (ModelState.IsValid) {
if(alreadySaved != null) {
      return Ok(new  {message="User data has been saved already!"});
      }
var user = new UserData {
UserId = userdata.UserId,
        FirstName = userdata.FirstName,
        LastName = userdata.LastName,
        PictureUrl = userdata.PictureUrl,
        EmailAddress = userdata.EmailAddress,
        Provider = userdata.Provider
};
_db.Add(user);
_db.SaveChanges();
return Ok(new  {  message="User Login successful" });
   }
}

      var errors = ModelState.Values.First().Errors;
      return BadRequest(new JsonResult(errors));
    
  }
}

Notice that I kept a condition to check if our user’s data has already been saved and I made it skip the save process and just return a message.

[Route(“api/[controller]”)] tells us the route we need to take to get to this controller. [HttpPost(“[action]”)] tells us the route we need to take to get to this method. So if we wanted to navigate to the Login method in the AccountController the route would be

api/Account/Login

That’s a wrap for working with ASP.net core. We’ve defined our Model, created our Login method in the Controller API and it’s ready to receive data from angular. Now we’ll need to configure angular to send the user data with a service and receive a response from our API.

Communicating with our Controller API

We’ll start this section by generating a new service in angular (for example LoginService). In our LoginService, we’ll import HttpClient module to help us communicate with our API, we’ll then inject it through our constructor and that way we’ll be able to create a method that calls our login method with the same route we already defined.

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
  providedIn: 'root'
})
export class AccountService {
  constructor(private http: HttpClient) { }
//properties needed
  private baseUrlLogin = 'api/Account/Login';
//communicate with web api
  Login(userData) {
    return this.http.post<any>(this.baseUrlLogin, userData).pipe(
      map(result => {
if (result.message != null) {
          console.log('We sent a message to our Controller API. It       works');
        }
        return result;
        })
      );
  }
}

So we can see that I defined my route in a private field named baseUrlLogin then my Login function which takes user data sends a post action to the route and also sends the user data. We use the pipe method to combine multiple functions into a single function even though we have just one here, the map() method to check for the result.message that we sent out in the API Login method. Also if it doesn’t find that, it would just return all the error messages to the console that we also sent from the API Login method.

Now that we’ve successfully created a service to send user data to our API, all we need to do now is get that user data to our service and we’ll be done. So we’ll go back to the component that has our login method and call this service so it can get the data and get a result.

First, we’ll need to import the AccountService class into our Login component so at the top of our login component we’ll have something like this:

import { AccountService } from '../services/account.service';

After that we need to inject it through our constructor. So we’ll have something like this in our constructor

constructor(private accountService: AccountService, private authService: AuthService ) { }

And then right under where we stored the user data in an array in both of our login methods (logInWithFacebook & logInWithGoogle), we’ll add this

// Take the array and send to our accountservice.login method
this.accountService.Login(this.userData[0]).subscribe(
    result => {
      console.log('success', result);
      this.route.navigate(['/home']);
    },
error => {
      this.resultMessage = 'it didn\'t work and that sucks';
      console.log(error);
     }
  );
  

So now that we have our accountService listening to our Login method, we can send data to accountService which will then send data to our controller API which then saves the data to our database.

Conclusions

At the end of the day we’ve been able to :

Configure our client-side (Angular) to log in to 3rd parties,

Enable our client-side (Angular) get user data from 3rd parties,

Enable communication with our client-side (Angular) and server (ASP.net core web API)

Send data across both Angular and ASP.net core web API

We’re done! 👌 If you stuck with this article till the end, thank you and I hope some part of it helped you out.

If you also have any questions at all or need to reach out, you can leave a comment or reach me on my email address onigbinde.i@gmail.com.

References

For further reading or study please check the articles below.

ASP.NET Web API 2 external logins with Facebook and Google in AngularJS app - Bit of Technology

How to Implement Sign-in with Google in Angular and a REST API

Discover and read more posts from Onigbinde Ifeoluwa
get started
post commentsBe the first to share your opinion
Test Quantsapp
3 years ago

I am working for a Angular project in which I want to add google login feature. I have researched about google login in Angular and found one npm packge angularx-social-login. I have implemented the package and its working properly for all browsers normal mode and incognito mode. But, I am facing an issue using chrome browser incognito mode.

Error: {“error”:“idpiframe_initialization_failed”,“details”:“Cookies are not enabled in current environment.”}

But when I enable “Allow all cookies” in browser then it’s working fine.

As well I play with some other site like linkedIn, Quora, Glassdoor, etc… It’s working fine with when “Block third-party cookies” in browser. In other words it’s working fine if " third-party cookies" is enable or not.

My question is How google login is working in private window when Block third-party cookies in browser in such a site linkedIn, Quora, Glassdoor.

I don’t want to implement google login using Firebase. Is there any other package or solution for using google login in normal browser mode as well as incognito mode in chrome and other browsers.

Abolfazl Vayani
4 years ago

Great post… thanks… but don’t we need our CLIENT SECRET? if no, what’s that used for though???

Rainer Kikkas
4 years ago

Have to agree with Roman. Up to the point where you start communicating with backend, it is fine. But then you just send all data in plain text to the backed.
Check out this article - https://dev.to/jorgecf/integrating-google-authentication-with-your-angular-app-4j2a, it has a different approach. The token from Google is sent back to your backend and then verified.

Onigbinde Ifeoluwa
4 years ago

Hey! Thanks so much for this. I’ll check it out now.

Show more replies