Easy Auth for Azure App Service
Tags: easyauth, 502, badgateway, azureauthentication
Published: 2023-04-09 18:07:31

**What is Easy Auth** ?

Authentication is a key element for any LOB application. Developers spend considerable time writing code to address various elements of authentication such as authenticating users, injecting user identity etc., Easy Auth is a built-in authentication module available for Azure App Service. This setup unburdens the developers from having to:

1. Authenticate users and client with Azure AD(e.g. enable identity provider middleware in the code)
2. Collect, validate, store and refresh OAuth tokens issued  by Azure AD
3. Manage the authenticated session
4. Make identity information(user id, email etc.,) available in HTTP request headers using a framework-agnostic approach
5. Maintain the authentication solution in line with the latest security and browser updates

Easy Auth feature is easily configurable from the azure portal. With the introduction of this feature on Azure App Service which already has in-built features like Auto Scaling, Load balancing, etc.,  makes it the most desirable option for hosting web applications.


In our case we had Azure Functions integrated with an Angular Front end, both hosted on Azure App Service. Each app had its integration setup with its own application registered on Azure AD. Azure Functions was handling the business logic which included code to validate token etc., that was required to be invoked and present in every function method. The idea behind incorporating Easy Auth into the application was to have a clean code. It is a good design to separate out cross-cutting concerns such authentication, authorization, logging from the business logic.

**Challenges in setting up Easy Auth**

As soon as the Easy Auth was setup - things went crazy and noticed that the Angular app was on a loop, continuously getting redirected to the home page.

We decided to test Azure Functions directly from postman. The request returned a 502 bad gateway error. The only helpful information was the presence of the "Microsoft-Azure- Application-Gateway/v2" text in the error response.


![502 Bad Gateway](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mdvwxhr094f5qw99iou0.png)

Now it is a common enterprise design to setup an application gateway or proxy in front of a web application to filter and protect it from malicious attacks. Requests are filtered by the application gateway before routing it to the appropriate web servers.

What is Azure Application Gateway ?

https://learn.microsoft.com/en-us/azure/application-gateway/overview

**What is the issue ?**

The app gateway uses a health probe request to determine if a set of servers are healthy and available. As long as the servers return a healthy status code (200-399) in response to the health check, clients are allowed to access the target service. Typically app gateway would return a "502 Bad Gateway" error response to the client if the backend servers(app service instances in this case) configured on the gateway return an **unhealthy status** in response to its health check request. This mechanism actually blocks the clients from connecting to back-end services that are not available or non-responsive due to a failure. That makes sense!! 

**Unhealthy Status ?**

Let's explore why the application gateway returns a "502 Bad Gateway" error  in spite of the services being healthy and available:

1. The app gateway sends a periodic health probe request to each app service instance
2. Since Easy Auth is set on the entire site, it will intercept every incoming request and check for authentication before being handled by the application
3. Health check is a plain http request without any identity information. Therefore a "401 (unauthorised)" status code will be sent back to the app gateway by the target app service instance configured with Easy Auth
4. On receiving a 401 from all the app service instances, app gateway marks the service as unhealthy and returns a 502 status code to any incoming requests to the service. By default HTTP status codes in the range of 200-399 are considered healthy by the app gateway
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2rn3zbbzkmuztkhujv3m.png)

The "401 (Unauthorised)" indicator from the target service is considered unhealthy by the app gateway and hence it blocks all further requests to the service. As described earlier, by returning a "502 Bad Gateway" response to the client, app gateway is indicating that there are no service instances to service the request.

In the absence of Easy Auth, app gateway is able to connect to app service instances directly and make the health checks without any issues.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1xpfa6kx3lv5mwwn5fh3.png)
**Solution:**

**Modify app gateway health probe response to include 401 status code as a healthy response**

Powershell script to update health probe response:

```
# FQDN of the web app
$webappFQDN = "<enter your webapp FQDN i.e mywebsite.azurewebsites.net>"`

# Retrieve an existing application gateway
$gw = Get-AzureRmApplicationGateway -Name AppGatewayAAD -ResourceGroupName AppGatewayAADBlog

# Define the status codes to match for the probe
$match=New-AzureRmApplicationGatewayProbeHealthResponseMatch -StatusCode 200-401

# Add a new probe to the application gateway
Add-AzureRmApplicationGatewayProbeConfig -name AppGatewayAADProbe -ApplicationGateway $gw -Protocol Https -Path / -Interval 30 -Timeout 120 -UnhealthyThreshold 3 -PickHostNameFromBackendHttpSettings -Match $match

# Retrieve the newly added probe
$probe = Get-AzureRmApplicationGatewayProbeConfig -name AppGatewayAADProbe -ApplicationGateway $gw

# Configure an existing backend http settings
Set-AzureRmApplicationGatewayBackendHttpSettings -Name appGatewayBackendHttpSettings -ApplicationGateway $gw -HostName "<enter your custom domain i.e www.contoso.com>" -Port 443 -Protocol https -CookieBasedAffinity Disabled -RequestTimeout 30 -Probe $probe

# Add the web app to the backend pool
Set-AzureRmApplicationGatewayBackendAddressPool -Name appGatewayBackendPool -ApplicationGateway $gw -BackendFqdns $webappFQDN

# Update the application gateway
Set-AzureRmApplicationGateway -ApplicationGateway $gw`

```
Post modification the application gateway still receives a 401 response from the app service instance. This time it will start treating 401 response as a healthy status code and allow requests from client to reach the target app service instance. Logically, a 401 is still an indication that the underlying service is available.

This is how the request flow will look like post modification:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lg56ddwi5h1xpn4s2id4.png)
If adding 401 as a healthy response status code to the health response match is not acceptable as a solution, there is an alternate way which I will cover in the next article.