How to Login with Google in Angular using ASP.NET Core

In this article, we will learn how to login with google in Angular using ASP.NET Core.

1. Create the Angular App

Create the app using below command:

ng new YourProjectName

Install the angularx social login module

npm install angularx-social-login

2. Get client id from google

Get client id using this Link.

Now Use your google client ID and activate the social login module in the providers section of the app.module.ts:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http'
import {FormsModule} from '@angular/forms'
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import {SocialAuthServiceConfig} from 'angularx-social-login'
import {SocialLoginModule, GoogleLoginProvider} from 'angularx-social-login';
import { HomeComponent } from './home/home.component'


@NgModule({
  declarations: [
    AppComponent,
    HomeComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    SocialLoginModule,
    HttpClientModule,
    FormsModule
  ],
  providers: [
    {
      provide: 'SocialAuthServiceConfig',
      useValue: {
        autoLogin: false,
        providers: [
          {
            id: GoogleLoginProvider.PROVIDER_ID,
            provider: new GoogleLoginProvider(
              // add your google client id here
            )
          }
        ]
      } as SocialAuthServiceConfig,
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

Now add new component using below command

ng g c ComponantName

Add routing like below

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';

const routes: Routes = [
  {path: 'login', component: HomeComponent},
  {path: '**', redirectTo: 'login'}
];



@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { SocialAuthService, SocialUser, GoogleLoginProvider } from 'angularx-social-login'

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {

  user?: SocialUser;
  hasApiAccess = false;

  constructor(private socialAuthService: SocialAuthService, private http: HttpClient) { }

  ngOnInit(): void {
    this.socialAuthService.authState.subscribe((user) => {
      if (user) {
        this.http.post<any>('https://localhost:44361/authenticate', { idToken: user.idToken, accessToken: user.response.access_token }).subscribe((authToken: any) => {
          console.log(authToken);
          let reqHeader = new HttpHeaders({
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + authToken.authToken
          });
          this.http.get<any>('https://localhost:44361/secured', { headers: reqHeader }).subscribe((data: any) => {            
            this.hasApiAccess = true;
          })
        })
      }
      this.user = user;
    })
  }

  loginWithgoogle(): any {
    this.socialAuthService.signIn(GoogleLoginProvider.PROVIDER_ID);
  }

  signout(): any {
    this.socialAuthService.signOut();
  }
}

Add HTML

<div class="container mt-5">
    <div *ngIf="!user" class="card text-center" style="width: 18rem; padding: 10px;">
        <h5>Google Login</h5>
        <div class="card-block">
            <h4 class="card-title">
                Not sign in
            </h4>
            <p class="card-text">sign in with</p>
        </div>
        <div class="card-block">
            <button class="btn btn-primary" (click)="loginWithgoogle()">Login with Google</button>
        </div>
    </div>
    <div *ngIf="user" class="card text-center" style="width: 18rem; padding: 10px;">
        <h5>Google Login</h5>
        <div class="card-block">
            <p class="card-title">{{user.name}}</p>
            <p class="card-text">{{user.email}}</p>
        </div>
        <div class="card-block">
            <button class="btn btn-danger" (click)="signout()">sign out</button>
        </div>
    </div>
</div>

3. Authentication API in the .NET Core Backend

install the google Auth Package below:

Install-Package Google.Apis.Auth

Add below code in controller

using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using Google.Apis.Auth;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Configuration;
using System.ComponentModel.DataAnnotations;

namespace LoginWithGoogle.Controllers
{
    [ApiController]
    public class LoginController : ControllerBase
    {
        public class AuthenticateRequest
        {
            [Required]
            public string IdToken { get; set; }

            public string AccessToken { get; set; }
        }

        private readonly JwtGenerator _jwtGenerator;

        public LoginController(IConfiguration configuration)
        {
            _jwtGenerator = new JwtGenerator(configuration.GetValue<string>("JwtPrivateSigningKey"));
        }

        [AllowAnonymous]
        [HttpPost("authenticate")]
        public IActionResult Authenticate([FromBody] AuthenticateRequest data)
        {
            GoogleJsonWebSignature.ValidationSettings settings = new GoogleJsonWebSignature.ValidationSettings();

            settings.Audience = new List<string>() { "your client id" };

            GoogleJsonWebSignature.Payload payload = GoogleJsonWebSignature.ValidateAsync(data.IdToken, settings).Result;
            return Ok(new { AuthToken = _jwtGenerator.CreateUserAuthToken(payload.Email) });
        }
    }

}

Add below key to appsettings.json

"JwtPrivateSigningKey": "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"

Edit Startup.cs

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System;
using System.Security.Cryptography;

namespace LoginWithGoogle
{
    public class Startup
    {
        public class ConfigureJwtBearerOptions : IConfigureNamedOptions<JwtBearerOptions>
        {
            public void Configure(string name, JwtBearerOptions options)
            {
                RSA rsa = RSA.Create();
                rsa.ImportRSAPublicKey(Convert.FromBase64String(PUBLIC_KEY), out _);

                options.IncludeErrorDetails = true;
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new RsaSecurityKey(rsa),
                    ValidateIssuer = true,
                    ValidIssuer = "AuthService",
                    ValidateAudience = true,
                    ValidAudience = "myApi",
                    CryptoProviderFactory = new CryptoProviderFactory()
                    {
                        CacheSignatureProviders = false
                    }
                };
            }

            public void Configure(JwtBearerOptions options)
            {
                throw new NotImplementedException();
            }
        }

        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {

            services.AddControllers();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "LoginWithGoogle", Version = "v1" });
            });


        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "LoginWithGoogle v1"));
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseCors(x => x
               .AllowAnyOrigin()
               .AllowAnyMethod()
               .AllowAnyHeader());

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

        private const string PUBLIC_KEY = @"MIICCgKCAgEAtCR2Pii+q9C76P2E9ydHYxnBPjJFGT7MvHuQPKpcS9RImfrkobt0
        LPS/406eWm/tRBvnYD9nDpHJNKN3TjEenFQuDGR4RHcGK/e43SAhTAi7+s0tfAQd
        6BK4gznIwvs5cWyilh1B7c9sCnxhJ/EYLIe1N2yiD8mhvfojIF4vMYxONIMTGYXy
        87lnO9zRAdXAZ39YbtmFmQwK8gfXX5d/XVlKy0tc2y5bRY5iXn9kwqwvFlzL6O4v
        pjhqA5kwsJV7efhL9nU0ACR4dG3zwFR3SAOOSETXjnfmjH2ocga+oa65ToypUz2L
        1DwnNHt+M5CtDJ9um4dbYaqfBWkjWe3FuGB0GNPS8pbX2nVt76OfHA/QKmxTWvFd
        POZnjpg2QhDujyXgoIY731zx5bAklKVoKFma/qfWfCyCSTUzhgu1KQm9swipMsQy
        NYr9CjbnIlPn4EvrBIbGcIiaRNCLCIlcAuxE/GiH1zBUfeJxfJQmurejp6mBAtAS
        FY08DmUebBz8mlUbB+LXMYKHZ4GK6TecPy0WJU2qRMQ//PKfOa+wkesp4M53SQdp
        ItDp5akTzYUo4rXwk3HPCtemKaSNhyG+EYtZ1CAmPN5sEjU0/x0Dq7SU5o8KhogB
        m/5HRJ3M9dMRcwD3OcsMl0kW1PPUt04itboS3SlFav90V9uc2YNGpPsCAwEAAQ==";
    }
}

Add a controller:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace LoginWithGoogle.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class SecuredController : ControllerBase
    {
        [Authorize]
        [HttpGet]
        public void Test()
        {
            return;
        }
    }
}

Output

Google login

Submit a Comment

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

Subscribe

Select Categories