Authentication with Angular

For a customer I have been looking at the best way to handle the authentication for their new application. I quickly concluded that I should just use Windows Authentication for this application.

Since, I did not know how to do this in Angular and with .NET core, I took a few google-fu moves and found a workable way. To help other people with the same problem I created some documentation, which you will find below:

Please, check!

Important, before you try start, make sure you have the following installed:

Angular Apps usually (well most of the time) get their data from a backend service. The backend service usually checks if a user is authorized for a certain action on the server. So let’s make this backend service using .NET core! Since I only want to make a simple service we can leave it at the generated service. Now make sure you have .NET Core installed before attempting anything with .NET Core.

Open a terminal window and navigate to a directory where you want your project created. In this directory create a new directory and name it something like “WinAuthApi” because we will be doing something with Windows Authentication!

Next navigate into this directory and type “dotnet new webapi”

This creates a new project in this folder with a simple WebApi template and a ValuesController.

The ValuesController is an excellent candidate to secure with windows authentication! Since we want to secure the ValuesController with windows authentication but the software does not “know how to” , we need to “tell” it to use Windows Authentication!

The easiest way for the software to know to expect some sort of authentication, is to add an [Authorize]  attribute above the code. This basically means the controller only excepts authenticated calls.

[Authorize]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
     …..
}

Because we currently have the attribute in place and we have to specify yet what kind of authentication to use, no user will be able to access the Api.

Luckily .NET Core has great integration with IIS, which I will be using for this example. To use the IIS integration, we need to add it to the services in the “ConfigureServices”  method:

Note: Make sure you have installed the nuget package ‘Microsoft.AspNetCore.Server.IISIntegration’

public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(IISDefaults.AuthenticationScheme);
       services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

This will ensure the Api uses the authentication from IIS.

Add a web config with the following content in the directory:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="bin\IISSupport\VSIISExeLauncher.exe" argument="-argFile IISExeLauncherArgs.txt" stdoutLogEnabled="false" forwardWindowsAuthToken="true" />
</system.WebServer>
</configuration>

Note the forwardWindowsAuthToken=”true” , do not forget this!  If you do not set this flag, Windows Authentication will not be forwarded to the Api meaning that no one will be allowed to access the Api.

Now that we have everything in place, everyone should work r-right??

Setting up IIS

N-no? I need to do more? Yes, you have to set up IIS. We only configured the application part, IIS is the hosting part which needs to be configured also.

Since we want to use the configured AuthenticationScheme from IIS and we have not configured IIS at all, Windows Authentication will not work, because the code is expecting IIS to send some sort of credentials, but IIS is not sending anything to the code at this time. IIS needs a bit of configuring to send the credentials to the application.

Open IIS under your Default Web Site or Any Website you want to add your Application. Add a new Website and name it ‘Api’ . For Physical path put in the C:\temp\<your proj>, because this is what we want to serve, our newly made Api.

Press ‘Ok’ so it is going to create.

Next select your newly created website.

You will see the following on the right.

Select ‘Authentication’ and in this window Enable Windows Authentication and Anonymous Authentication.

And that is it. We now have a WebApi secured by Windows Authentication.

Setting up Angular

We now have a WebApi, but no sane person would want to use an Api directly, right? Let’s slap Angular as a provider for some fancy HTML elements that consumes our created API.

Now make sure you have installed angular. After you’ve installed angular, find yourself a directory on your PC where you would like to make a brand new angular project (I choose C:\temp\ ). Open a terminal window in this location and type “ ng new angularwinauth “ . Don’t accept the routing for now and select whatever styling you’d like to work with.

You will see a lot of fancy things happening in your terminal. Do not worry, angular is setting up a new project!

Once it is done you will have to navigate into this newly created directory “angularwinauth”  and type some more magic. Type “ng g c values” . You will see a lot happening again.

This command generates a new component (the ‘g’ is generate and the ‘c’ is component) . Angular works with Components, and these together consist of your application, so we needed one!

Since I don’t want to take a deep dive into how Angular works, you’ll just have to trust me that this works! So open up app.component.html and replace everything in the file with:

<app-values></app-values>

Basically Angular tells this “Use our newly created values component” , since we will be using that to display data.

Running an Angular app locally can be done quite easily, by typing “ng serve –open”  in the terminal window, while in the Angular directory, that we’ve created when we typed “ng new”. Doing so will start the Angular app on port 4200. Since we specified –open, your browser should open up and display the page. The page will display that “values works!”.

B-but what about our backend? Well…. we could call it and have some data from the backend. So lets just do this.

Calling the Api

Luckily, Angular has a HttpClient that makes a call to an Api super easy! Open up “src\app\values\values.component.ts” .

Paste the following into this file and replace <yourapi> with the Api you created in IIS, since this is the address that needs to be called! (In the example I named it Api, making the request “api/api/values”, super silly! )

import { Component, OnInit } from '@angular/core' 
import { HttpClient } from '@angular/common/http'; 
import { Observable } from 'rxjs'; 

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

  public values: Observable<string>; 
  constructor(private http: HttpClient) { } 
 
  ngOnInit() {
    this.getData(); 
  } 

  getData() 
  { 
    this.values = this.http.get<string>("http://localhost/<yourapi>/api/values", {withCredentials:true}); 
  } 
}

Note: See that part “withCredentials: true“? That’s what we need to do for Angular to send the credentials along!

Basically this code exposes a list of information from the server and puts it in an observable to display this data. But to do this, we need to modify the view part of this component.

Normally you should create a service which handles the call to Api. But here I am being lazy and showing you a dirty way to get some data! So keep in mind, if you want to properly do this, create a service for retrieving data.

Now we need to add some HTML to “src\app\values\values.component.html” .

Just again, replace the whole file with the following:

div *ngFor="let s of values | async" >
  {{ s }}
</div>

This piece of “HTML” basically  binds to the data in the other .ts file. It looks for values and if there are any, it will display them. So everything in place, lets type “ng serve” in our terminal, so we run our angular application, like we did before!

Do not worry, the white page you are getting right now is totally correct. If you press F12 and refresh your page, you will see an error in the Console, something to do with CORS. Hmm…..

Basically this means we are not allowed to make this request. Our request is coming from localhost:4200 which differs from the URL our Angular App is hosted on. Luckily we can add a rule to the .NET Core application, so that we are allowed to make this call!

It’s a bit annoying that you need to add an extra rule so that we can make a request coming from another URL, but it is some extra security on the Api. This security limits who can request something. So let us try to limit our requesters, but allow our Angular App to call the Api.

In the C# project, go to startup.cs . Add a CORS policy to the “ConfigureServices” method.

The CORS policy is as follows:

services.AddCors(options => 
{ 
  options.AddPolicy(MyAllowSpecificOrigins, builder => { 
    builder.WithOrigins("http://localhost:4200").AllowCredentials(); 
    }); 
  });
}

It should now look something like:

private readonly string MyAllowedSpecificOrigins = "_MyOriginPolicy";
public void ConfigureService(IServiceCollection services)
{
   services.AddAuthentication(IISDefaults.AuthenticationScheme);
   services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
   services.AddCors(options =>
   {
     options.AddPolicy(MyAllowedSpecificOrigins, builder =>
     {
        builder.WithOrigins("http://localhost:4200").AllowCredentials();
     });
   });
}

But this is not everything that is needed. We defined the policy, but we also need to tell .NET Core we want to use it … everywhere.

So in the “Configure” method add:

    app.UseCors(MyAllowSpecificOrigins);

So you’ll end up with something similar to this:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseHsts();
    }
    app.UseCors(MyAllowedSpecificOrigins);
    app.UseHttpsRedirection();
    app.UseMvc();
}

Run agan, it works! I-I think…

If you are seeing value1 and value2 it works.

So it is pretty easy to get this going. Now you can read the username from the context by:

HttpContext.User.Identity.Name

Or if you would want to check if the user is in a role just do:

[HttpGet] 
public ActionResult<IEnumerable<string>> Get() 
{ 
  if (HttpContext.User.IsInRole("MyRole")) 
     { 
        ….

 

So it is up to you what you want do with it next!

So now you know how to setup a simple .NET Core project with Windows Authentication and how to consume it with Angular. Don’t forget to add CORS to your .NET Core project so that Angular can actually call the service and make sure you configure IIS properly. Have fun with angular and .NET Core!