Skip to content
Article

Shared Google Authorization with an Angular site and .Net Core API.

Man has an idea

There are many Angular tutorials for setting up websites using the Angular framework and .NET Core APIs. Likewise, there are many walkthroughs for integrating Google authentication with each. However, implementing these solutions separately yield the need to authenticate through Google twice, once for the angular site, once for the API.

This article provides a solution that allows shared Google authorization through authentication on the angular site. To surpass the need to authenticate a second time, pass the token through a standard header to the API and use Google libraries to validate and authorize.

Technology used in this Angular tutorial.

This post assumes you’ve got the basic angular website and Web API projects running. This post will also likely be effective for any angular site 2+ or front end site where google authentication occurs. It should also work if your Web API project is Core 2+.

The site I’m working with is designed to be exclusively authenticated through Google, however this method could be extended to handle multiple authentication formats (assuming there are .Net validation libraries for them or you write your own). Therefore, one other aspect to mention is that I am not storing any user data in a database.

Using the Angular site, Google login, and local storage as a start.

The primary goal is to make sure you have access to Google’s idToken after authentication. Using the angular-social-login default setup is pretty simple to get working. This is a pretty good article which also walks through setting up the Google App as part of this if you need. I can’t find the original post I followed, but this stackoverflow post shows storing the Google user/token in state for future calls.

This code block (customauth.service.ts in the Angular site) just shows that on user subscription the user is stored in local storage:

  constructor(
    public authService: AuthService,
    public router: Router,
    public ngZone: NgZone // NgZone service to remove outside scope warning
  ) {
    // Setting logged in user in localstorage else null
    this.authService.authState.subscribe(user => {
      if (user) {
        this.userData = user;
        localStorage.setItem('user', JSON.stringify(this.userData));
        JSON.parse(localStorage.getItem('user'));
      } else {
        localStorage.setItem('user', null);
        JSON.parse(localStorage.getItem('user'));
      }
    });
  }

  // Sign in with Google
  GoogleAuth() {
    return this.authService.signIn(GoogleLoginProvider.PROVIDER_ID);
  }

  // Sign out
  SignOut() {
    return this.authService.signOut().then(() => {
      localStorage.removeItem('user');
      this.router.navigate(['/']);
    });
  }

Options researched before finding the current solution.

  • The Microsoft standard way to handle google authentication. This is slick if you’re building an MVC site and need to allow Google auth, but I couldn’t find a way to allow sending over the token, as this generates and uses a cookie value with a Identity.External key.
  • JWT authorization is an option, but the tutorials got heavy quickly. Since I don’t need to store users or use Microsoft Identity, I blew past this.
  • A custom policy provider is another Microsft standard practice. There might be a better way to accomplish the solution using this approach, but I didn’t walk this path too far since I wasn’t using authentication through the .Net solution.

The solution: a .Net Core custom authorize attribute.

I used this stackoverflow post about custom auth attributes to hook up the solution. This is what allows the shared Google authorization using a standard authorization request header.

Approach

  1. In Angular
    1. Build the Authorization header using the Google idToken.
    2. Pass the header for any authorize only API endpoints.
  2. In the web API
    1. Enable authorization
    2. Create a custom IAuthorizationFilter and TypeFilterAttribute
    3. Tag any controllers or endpoints with the custom attribute

I provide code samples for these steps below.

Angular API calls with an authorization header.

The code in the api service (api.service.ts in Angular Site) grabs the id token from the user in local storage and passes it through the API call. If the user is logged out, this header isn’t passed.

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { SocialUser } from 'angularx-social-login';
import { environment } from './../../environments/environment';

export class ApiService {
  apiURL = environment.apiUrl;
  user: SocialUser;
  defaultHeaders: HttpHeaders;

  constructor(private httpClient: HttpClient) {
    this.user = JSON.parse(localStorage.getItem('user'));
    this.defaultHeaders = new HttpHeaders();
    this.defaultHeaders = this.defaultHeaders.append('Content-Type', 'application/json');
    if (this.user != null) {
      this.defaultHeaders = this.defaultHeaders.append('Authorization', 'Bearer ' + this.user.idToken);
    }
  }

  public getAccounts() {
    const accounts = this.httpClient.get<Account[]>(`${this.apiURL}/accounts`, { headers: this.defaultHeaders });
    return accounts;
  }
}

Enabling authorization in the .Net Core project.

In the StartUp file (StartUp.cs in the API project), authorization has to be enabled.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  ...
  app.UseRouting();
  app.UseAuthorization();
  app.UseEndpoints(endpoints =>
  {
      endpoints.MapControllers();
  });
}

The custom filter attribute to validate without another authorization.

This creates the attribute used for authorization and performs a Google validation on the token.

This application is used only for our Google G Suite users, and thus the “HostedDomain” option of the ValidationSettings is set. This isn’t necessary, and I believe can just be removed if you allow any Google user to authenticate.

I’ve named this file GoogleAuthorizationFilter.cs in the API project.

using Google.Apis.Auth;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;

namespace YourNamespace.API.Attributes
{
    /// <summary>
    /// Custom Google Authentication authorize attribute which validates the bearer token.
    /// </summary>
    public class GoogleAuthorizeAttribute : TypeFilterAttribute
    {
        public GoogleAuthorizeAttribute() : base(typeof(GoogleAuthorizeFilter)) { }
    }


    public class GoogleAuthorizeFilter : IAuthorizationFilter
    {

        public GoogleAuthorizeFilter()
        {
        }

        public void OnAuthorization(AuthorizationFilterContext context)
        {
            try
            {
                // Verify Authorization header exists
                var headers = context.HttpContext.Request.Headers;
                if (!headers.ContainsKey("Authorization"))
                {
                    context.Result = new ForbidResult();
                }
                var authHeader = headers["Authorization"].ToString();

                // Verify authorization header starts with bearer and has a token
                if (!authHeader.StartsWith("Bearer ") && authHeader.Length > 7)
                {
                    context.Result = new ForbidResult();
                }

                // Grab the token and verify through google. If verification fails, and exception will be thrown.
                var token = authHeader.Remove(0, 7);
                var validated = GoogleJsonWebSignature.ValidateAsync(token, new GoogleJsonWebSignature.ValidationSettings()
                {
                    HostedDomain = "yourdomain.com",
                }).Result;
            }
            catch (Exception)
            {
                context.Result = new ForbidResult();
            }
        }
    }
}

Putting the custom attribute in place.

This is just a snippet of code, as on your controllers you just have to add the one line of code (well, two including the using statement). If the GoogleAuthorize doesn’t validate, the call returns as access denied.

using YourNamespace.API.Attributes;

[GoogleAuthorize]
[ApiController]
public class AccountsController : BaseController {

Voila! No need for a second authentication.

The .Net API is now locked down only to requests originating from a site with Google authentication. The custom attribute can be extended for additional authentication sources or any other desired restrictions using the request. I like the simplicity of a site which allows Google auth only, but it wouldn’t be a stretch to add others – and I really like not managing any users or passwords. I hope this Angular tutorial for shared Google authentication works well for you too!

The Atlantic BT Manifesto

The Ultimate Guide To Planning A Complex Web Project

Insights

Atlantic BT's Insights

We’re sharing the latest concepts in tech, design, and software development. Learn more about our findings.

Questions & Answers

What is the best web development framework?
Many people commonly ask “what is a framework in web development?” Web development frameworks can easily be confused with web development tools, languages, or parts of the web development stack (like .NET, PHP, JavaScript, or Ruby).
Learn More about What is the best web development framework?
What is the best programming language for web development?
If there was one “best” programming language, then everything else would be obsolete. The reality is that there are so many different programming languages because there is no “best” language for any situation.
Learn More about What is the best programming language for web development?
How much does web development cost?
Web development can vary from a few hundred to millions of dollars depending on what is needed. You may simply need some changes to something that already exists, or you'd like to build a large or complex application.
Learn More about How much does web development cost?
What is JavaScript used for in web development?
Historically speaking, JavaScript was only commonly but sparingly used in web development. The multiple browsers in use at the time each supported different versions of JavaScript and were slow to render more complex Javascript.
Learn More about What is JavaScript used for in web development?
What is React web development?
React is a popular JavaScript library. It is primarily used for building interactive user interfaces (UI).
Learn More about What is React web development?
What is PHP web development?
PHP is a back end language primarily used for custom applications, content management systems (such as Wordpress), eCommerce engines (such as Magento), or even massive sites like Facebook.
Learn More about What is PHP web development?
What is the best way to become a web developer?
We get lots of questions from university students working on projects -- How do I get into web development? How long does it take to learn? How much do web developers make?
Learn More about What is the best way to become a web developer?