Author : HASSAN MD TAREQ | Updated : 2020/09/07

What is App Service Easy Auth

Create App Service



Azure AD Tenant and User

  • Create dedicated tenant and switch to that tenant
    • Do not use default tenant (use dedicated tenant)
    • Delete tenant after PoC/Demo
  • Create dedicated user and login once to change temporary password (Azure AD might ask you to setup authentication app)

Used in demo

tenant name: AppServiceEasyAuthTenant
domain (while creating tenant): EasyAuthDemoApp (=>

User in newly created tenant
Temporary pass: Wowo8300
Upadeted password: xxx

Create Azure AD Tenant and User Step 1

Create Azure AD Tenant and User Step 2

Create Azure AD Tenant and User Step 3

Create Azure AD Tenant and User Step 4

Create Azure AD Tenant and User Step 5

Create Azure AD Tenant and User Step 6

Create Azure AD Tenant and User Step 7

Create Azure AD Tenant and User Step 8

Create Azure AD Tenant and User Step 9

Create Azure AD Tenant and User Step 10

Create Azure AD Tenant and User Step 11

Create Azure AD Tenant and User Step 12

Create Azure AD Tenant and User Step 13

App Registration in Azure AD

  • For PoC/Demo, create new app registration
  • In case you want to use existing App registration, check and update following accordingly:
    • Branding
    • Authentication
    • Certificates & secrets
    • Expose an API
  • Go to Manifest & verify oauth2Permissions (+ other settings)

Register app in azure AD

Redirect URI: <app-url>/.auth/login/aad/callback


Gather required information for “App Service Easy Auth”

Client ID: 858430e8-169a-4d47-bbe9-ec4f2fda96d9
Tenant ID: d68fc4a4-063a-4ea9-be32-8178a5cc29c7
Client secret (optional): jXr.Ku7M.c9Koj6A.A7_W-fMvs4d4T.5dm
Application ID URI:


Scope name: user_impersonation
Admin consent display name: Access my app
Admin consent description: Access my app... bla bla bla

Register App in Azure AD Step 1

Register App in Azure AD Step 2

Register App in Azure AD Step 3

Register App in Azure AD Step 4

Register App in Azure AD Step 5

Register App in Azure AD Step 6

Register App in Azure AD Step 7

Register App in Azure AD Step 8

Register App in Azure AD Step 9

Register App in Azure AD Step 10

Register App in Azure AD Step 11

Register App in Azure AD Step 12

Register App in Azure AD Step 13

Configure App Service

App Service > Authentication/Authorization > Authentication Provider > Azure Active Directory > Advanced

Client ID: noted before (see above)
Client secret (optional): noted before (see above)
Application ID URI: noted before (see above)

Issuer Url: <authentication-endpoint>/<tenant-id>/v2.0

Don’t forget to save “App Service > Authentication/Authorization”

Configure App Service for Easy Auth Step 1

Configure App Service for Easy Auth Step 2

Configure App Service for Easy Auth Step 3

Configure App Service for Easy Auth Step 4

Configure App Service for Easy Auth Step 5

Configure App Service for Easy Auth Step 6

Creating Custom Middleware

  • Create a project or use existing project
  • Create folders if needed (i.e. Middlewares, Extensions)
  • populating identity data from app service using custom Middleware
    • After successfull login, app service passes identity information to app
    • identity information usrl:
  • Dependency: Install-Package NewtonSoft.Json (easy to parse json, in future use: System.Text.Json)
  • Notes:
    • You need to check ‘user_claims’ by going to: ‘’ If you are not using Azure AD Global
      • Issuer Url for global ==
      • Example ssuer Url for other Azure AD: ‘
    • Extract the claim you want: authState.User?.Claims?.FirstOrDefault(c => c.Type == "claim-type-you-want")?.Value;


using Microsoft.AspNetCore.Http;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;

namespace AzureAppServicesAuthDemo.Middlewares

    public class AzureAppServiceEasyAuthMiddleware
        private const string PrincipalId = "X-MS-CLIENT-PRINCIPAL-ID";
        private const string AuthMeEndPoint = @".auth/me";
        private const string UserClaimsKey = "user_claims";
        private const string ClaimTypeKey = "typ";
        private const string ClaimValueKey = "val";

        private readonly RequestDelegate _next;

        public AzureAppServiceEasyAuthMiddleware(RequestDelegate next)
            _next = next;

        public async Task InvokeAsync(HttpContext context)

            if (context.User == null || context.User.Claims == null || !context.User.Claims.Any())
                if (context.Request.Headers.ContainsKey(PrincipalId))
                    var azureAppServicePrincipalIdHeader = context.Request.Headers[PrincipalId][0];

                    var uriString = $"{context.Request.Scheme}://{context.Request.Host}";
                    var cookieContainer = new CookieContainer();
                    var handler = new HttpClientHandler()
                        CookieContainer = cookieContainer

                    foreach (var c in context.Request.Cookies)
                        cookieContainer.Add(new Uri(uriString), new Cookie(c.Key, c.Value));

                    var jsonResult = string.Empty;
                    using (var client = new HttpClient(handler))
                        var res = await client.GetAsync($"{uriString}/{AuthMeEndPoint}");
                        jsonResult = await res.Content.ReadAsStringAsync();

                    if (jsonResult != string.Empty)
                            var obj = JArray.Parse(jsonResult);

                            var claims = new List<Claim>();
                            foreach (var claim in obj[0][UserClaimsKey])
                                claims.Add(new Claim(claim[ClaimTypeKey].ToString(), claim[ClaimValueKey].ToString()));

                            var identity = new GenericIdentity(azureAppServicePrincipalIdHeader);

                            context.User = new GenericPrincipal(identity, null);
                        catch (Exception ex)
                            Log.Fatal(ex, ex.Message);

            await _next(context);


using AzureAppServicesAuthDemo.Middlewares;
using Microsoft.AspNetCore.Builder;

namespace AzureAppServicesAuthDemo.Extensions
    public static class AzureAppServiceEasyAuthMiddlewareExtension
        public static IApplicationBuilder UseAppServiceEasyAuth(this IApplicationBuilder builder)
            return builder.UseMiddleware<AzureAppServiceEasyAuthMiddleware>();

Configuration in Startup Class


using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using AzureAppServicesAuthDemo.Data;
using AzureAppServicesAuthDemo.Extensions;
using AzureAppServicesAuthDemo.Services;

namespace AzureAppServicesAuthDemo
    public class Startup
        // ... ... ...
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            // ... ... ...


            app.UseEndpoints(endpoints =>

Get Claims using AuthenticationStateTask

  • Add CascadingAuthenticationState
  • Use AuthorizeRouteView instead of RouteView


    <Router AppAssembly="@typeof(Program).Assembly">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
            <LayoutView Layout="@typeof(MainLayout)">
                <p>Sorry, there's nothing at this address.</p>


using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using System.Threading.Tasks;
using System.Security.Claims;
using System.Collections.Generic;
using System.Linq;

namespace AzureAppServicesAuthDemo.Pages
    public class IndexBase: ComponentBase
		public const string PREFERRED_USERNAME = "preferred_username";
		public const string DefaultLoggedInUser = "unknown (default)";

		private Task<AuthenticationState> AuthenticationStateTask { get; set; }

		public string CurrentLoggedInUserName { get; set; } = string.Empty;

		public IEnumerable<Claim> LoggedInUserClaims { get; set; } = Enumerable.Empty<Claim>();

        protected override async Task OnInitializedAsync()
			var authState = await AuthenticationStateTask;

			LoggedInUserClaims = authState.User?.Claims;

			var loggedInUserName = authState.User?.Claims?.FirstOrDefault(c => c.Type == PREFERRED_USERNAME)?.Value;

            if (string.IsNullOrWhiteSpace(loggedInUserName))
				loggedInUserName = DefaultLoggedInUser;

			CurrentLoggedInUserName = loggedInUserName;


@page "/"
@inherits IndexBase

<h3>Azure App Service Easy Auth PoC</h3>
<hr class="mb-sm-5" />

<h3 class="mb-sm-5">LoggedIn User Name: @CurrentLoggedInUserName </h3>

<h3>List of Claims: </h3>

@if (LoggedInUserClaims != null && LoggedInUserClaims.Any())
    @foreach (var claim in LoggedInUserClaims)
    <h3>No claims for loggedin user</h3>

Expose Logged In user Information from MainLayout

Based on above approach, we can make it better. A better approach would be:

  • Populate logged in user information in MainLayout using [CascadingParameter] protected Task<AuthenticationState> AuthenticationStateTask { get; set; }
  • MainLayout would expose logged in user information using <CascadingValue Value="@CurrentLoggedInUser">@Body</CascadingValue>
  • Since all components are rendered inside MainLayout, components would have access to logged in user info (exposed by MainLayout)
  • Create BaseComponent class and get logged in user information (exposed by MainLayout) using [CascadingParameter]protected LoggedInUser LoggedInUser { get; set; }

See demo application:

Deploy to App Service

  • Right click on project > Publish
  • Select App Service
  • Visual Studio will deploy the app and launch it
  • Use Azure AD credential to login and you can see email address and claim list (if not showing, there is error)