Modernize your legacy API authentication with Microsoft.Identity.Web and Azure AD
Tags: security, azure
Published: 2021-02-10 01:32:46

In a previous [blog post](https://dev.to/425show/migrating-from-old-authentication-code-in-asp-net-with-microsoft-identity-web-and-azure-ad-2132), we looked at how to migrate the authentication code of a front-end solution written with ASP.NET Core to using the latest [Microsoft.Identity.Web](https://github.com/AzureAD/microsoft-identity-web) library for .NET. That was part 1 of our short series. For part 2, we will look at how to modernize the auth code in our back-end API using Microsoft.Identity.Web again. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/mh4ysnvi0oce1caaieso.gif)

## Updating the Web API

I was quite excited upgrading the API to .NET 5 because not only I could get rid of unnecessary code but I was also able to harden the security of the API at the same time. The majority of the redundant code was the identity-related extension classes 
- `AzureAdAuthenticationBuilderExtension.cs` 
- `AzureAdOptions` 

The code in these classes is part of the Microsoft.Identity.Web now :)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/82qx7l23c6bt4e7xuanq.png)

Once these files are removed, we can update the *.csproj file and change it from this:
```
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
  </ItemGroup>

</Project>
```
to this
```
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Identity.Web" Version="1.3.0"/>
  </ItemGroup>

</Project>
```

The only dependency on the updated project is Microsoft.Identity.Web. We can now proceed with the code updates. Open `Startup.cs` and update the `ConfigureServices()` method from this
```
public void ConfigureServices(IServiceCollection services)
{
     services.AddAuthentication(sharedOptions =>
     {
         sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
     })
     .AddAzureAdBearer(options => Configuration.Bind("AzureAd", options));

     services.AddMvc();
}
```
to this

```
public void ConfigureServices(IServiceCollection services)
{
   services.AddMicrosoftIdentityWebApiAuthentication(Configuration);
     services.AddControllers();
}
```
Finally, we need to update the `ToDoListController.cs` to take advantage of the newer, simplified way to authorize and validate incoming tokens. The old code

```
[Authorize]
[Route("api/[controller]")]
public class TodoListController : Controller
{
    static ConcurrentBag<TodoItem> todoStore = new ConcurrentBag<TodoItem>();

    // GET: api/values
    [HttpGet]
    public IEnumerable<TodoItem> Get()
    {
        string owner = (User.FindFirst(ClaimTypes.NameIdentifier))?.Value;
        return todoStore.Where(t => t.Owner == owner).ToList();
    }

    // POST api/values
    [HttpPost]
    public void Post([FromBody]TodoItem Todo)
    {
        string owner = (User.FindFirst(ClaimTypes.NameIdentifier))?.Value;
        todoStore.Add(new TodoItem { Owner = owner, Title = Todo.Title });
    }
}
```
Can be updated to this:
```
[Authorize]
[Route("[controller]")]
public class TodoListController : Controller
{
    static ConcurrentBag<TodoItem> todoStore = new ConcurrentBag<TodoItem>();
    static readonly string[] scopeRequiredByApi = new string[] { "access_as_user" };

    // GET: api/values
    [HttpGet]
    public IEnumerable<TodoItem> Get()
    {
            HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
        string owner = (User.FindFirst(ClaimTypes.NameIdentifier))?.Value;
        return todoStore.Where(t => t.Owner == owner).ToList();
     }

     // POST api/values
     [HttpPost]
     public void Post([FromBody]TodoItem Todo)
     {
        string owner = (User.FindFirst(ClaimTypes.NameIdentifier))?.Value;
        todoStore.Add(new TodoItem { Owner = owner, Title = Todo.Title });
     }
}
```
The important change here is the new addition of `HttpContext.VerifyUserHasAnyAcceptedScope()` which ensures that the incoming access token has the right scopes.

## Source Code
There is a fully working solution showing how the code works end to end on GitHub.

[Before the migration](https://github.com/cmatskas/aspnetcoreaadauth)
[After the migration](https://github.com/cmatskas/aspnetcoreaadauth/tree/net5.0)

## Conclusion
Microsoft.Identity.Web has made developers' lives much easier when it comes to authenticating users and acquiring or managing tokens. Although not groundbreaking, the new code is much simpler and more secure by leveraging the Microsoft.Identity.Web library.