Atlantic Business Technologies, Inc.

Category: JavaScript

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

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

    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!

  • Building a Custom Application to Reimagine Digital Strategy

    Building a Custom Application to Reimagine Digital Strategy

    One of the most influential life lessons that I follow every day is about planning—which teaches us that if you fail to plan, then you are planning to fail. You may wonder if planning really is that important. Uh, yes—yes, it is.

    As part of a digital agency, planning is one of the core phases of every project we engage with. The ability for us to strategize as a team really feels like a game of chess. Every piece has a purpose, and if you plan well in advance, you just might make it out alive.

    When it came to planning, communicating, and documenting data architecture, I noticed that our organization had some inefficiencies— repeated issues that chewed up both time and money. This past year, I sought out to design and develop a tool that would build in efficiency into our process—and look good while doing it too.

    Digital strategy has always been about connecting people to information through well-informed navigation.

    For most projects we’ve engaged with, there had been some level of documentation around research and data architecture. Who is this product for? What information are they seeking? How will they get to this information? Digital strategy boils down into a few primary areas.

    3 Primary Areas of Digital Strategy

    1. People

    Until the robot apocalypse occurs (it’s only a matter of time), the products we design and develop are to be consumed and engaged by people. Whether we put together assumptions on personas or we conduct user research and interview actual people, it’s important that we document the characteristics of these people to help us understand them better. The better we understand, the more accurate our recommendations become. Empathy is a powerful emotion that we can use to connect with people.

    2. Information

    Information can come in many forms, such as products or services. They can also tell stories and evoke emotions. We use content strategy methodologies to define and organize content that audiences seek. More specifically, content models help document information with a brand and define the relationship between them. These relationships help shape data types, taxonomies, and templates.

    3. Navigation

    The bridge that connects people to the information they desire is through well-informed navigation. Even the most desired information becomes useless if people cannot ultimately find it. We frame our content and navigation around sitemaps. Sitemaps help us show connections between our content, giving us a bird’s eye view of the product. Keeping our content well-organized allows us to provide better design solutions.

    Identifying Documentation Pain Points

    After countless hours of reviewing documentation across various projects, I was able to audit how we were documenting and setting ourselves up for digital success. Spoiler alert—it wasn’t pretty.

    Each project was almost entirely different in their approach to documentation, yet they all shared similar problems, like:

    • Too many documents
    • Too many file formats
    • Too many locations
    • Inconsistent branding
    • Proprietary software or hardware

    Needless to say, our documentation was fragmented and ineffective.

    Challenges With Visual Sitemaps

    One document that we typically produce in projects is called a visual sitemap. These are graphical representations of a website or applications content, and the connections made between them. What makes them unique is how we apply illustrations that best represent the kind of information each page may have. Visual sitemaps can give us a glimpse into user journeys, template architecture, and so much more. Often times, we print these sitemaps on a wide-format printer, which gives us a tangible poster for the team to review collectively.

    As you can imagine, large-scale sites or apps can make for some impressively large visual sitemaps. When producing these sitemaps projects can end up wasting lots of paper and ink – especially when you account for multiple revisions.

    Challenges With Standard Tools

    Using Google Drive as our repository for documentation was ineffective due to cultural diversity in technology and inadequate governance policies. For example, documents were being created in various applications based on personal preferences, projects were not being shared properly to team members, and nothing appeared to be brand-compliant. Drive was supposed to be the answer for us, but wasn’t measuring up to our standards.

    We also tried making visual sitemaps in Omnigraffle. Personally, I love Omnigraffle for making diagrams. However, if the designers weren’t available to make edits, the rest of our team could not help; Omnigraffle requires both macOS and a paid license.

    To make matters worse, additional methods for documentation got out of hand. Some details were posted as activity notes in our project management platform (which almost always gets lost), while others were simply emailed between one another. As if that weren’t bad enough, we’ve ran across files that were stored on people’s desktops—or worse—in their trash bin.

    If you were not part of the project team from the very beginning, getting involved became almost impossible. The landscape of how we documented and stored our plan of actions was chaotic. When you can’t effectively communicate with your team or even comprehend what is going on, you lose efficiency.

    Designing a New, Inclusive Application

    It was time to design an inclusive, customized app to promote improved team communication and strategy. I wanted to design and build an application that:

    • Centralized documentation into a single location
    • Allowed access cross-platform
    • Automatically applied branding to all documentation
    • Reduced dependency on 3rd party software
    • Eliminated ink and paper waste

    By creating an app to address the issues, my goals were:

    • Reduce Costs: Remove time-intensive inefficiencies, and uncover problems quickly with real-time metrics.
    • Increase Product Quality: Allow teams to spend more time making awesome products.

    What if we could use technology to help us make better decisions and improve planning? By allowing the application to display real-time metrics— like page counts, page title lengths, and persona distribution—we could make well-informed decisions around the data architecture.

    I branded and called the app Sapphire—for its clarity, strength, and beauty around providing value to us. Sapphire’s core value is about being a real-time data architecture planning tool that can help us strategize digital products at any scale.

    Benefits of Sapphire

    More Empathy for People in Design

    Sapphire makes it very easy to define and explore personas for projects. Every project can create as many personas as necessary, with just the right amount of information at a glance. It’s incredibly easy for team members—especially designers—to empathize with a person’s goals or frustrations.

    Better Organization for Content

    Creating well-organized architecture around a project became effortless. Each project can have content broken into data types, taxonomies, templates, and pages. In fact, you can also create relationships between pages and people. This allows us to understand who our target audience truly is.

    Clear Perspective on Navigation

    In the past, we had to document the same information multiple times. The best part about Sapphire is that both branding and visual sitemaps are automatically generated in real-time. If I could get people to focus on the content and nothing else, Sapphire could handle the rest. Visual sitemaps are fully interactive, allowing anyone to explore pages and their architecture.

    Inside the Single-Page App 

    In order to provide such a rich experience, I wanted to ensure Sapphire was using the latest technology. With performance being an important factor, I needed to choose technologies that were built for speed.

    Sapphire was built on React—as both a progressive web app and single page app—and used Google Firebase for its NoSQL real-time database. Users were authenticated securely using Google Domain Authentication and was securely hosted through Google Cloud Hosting. All of these technologies were relatively easy to learn and integrate.

    To power our intuitive sitemaps, I opted for jsPlumb framework over something like D3—primarily due to time constraints and the amount of effort required. I’ll admit, jsPlumb integrated extremely well with React and allowed me the power to customize as I needed to match the desired functionality.

    Final Thoughts on Digital Strategy

    Documentation allows teams to communicate and work together on projects of any scale, and digital strategy around architecture plays an important role in documenting how products should work. When we ignore documentation—or simply allow it to deteriorate over time— we are hurting our ability to communicate effectively.

    By recognizing these problems, I was able to design, develop, and deploy a tool that helps us reimagine digital strategy and how we document data architecture. When we can work better together as a team, anything is possible. Make something people love!

    This article was originally posted by Mark Riggan on Medium