Architecture of Azure App Service Authentication / Authorization

Authentication / Authorization (which I’ll refer to as Easy Auth throughout this post) is a feature of Azure App Service that allows you to easily integrate a variety of auth capabilities into your web app or API. It’s built directly into the platform and doesn’t require any particular languages, SDKs, security expertise, or even any code to utilize. This is why we call it easy – anybody can leverage it, even non-developers, with just a few clicks in the management portal.

In this post we will look at how Easy Auth is built and the various design tradeoffs involved. Be warned: We’ll go into deep technical detail in this post. If instead you’d like to learn more about what this feature is at a high level and how to use it, take a look at our overview topic in the Azure documentation and/or this recent announcement by my colleague Matthew Henderson. Otherwise, continue reading.

Architecture

Easy Auth is implemented as a native IIS module that runs in the same sandbox as your application. When enabled, every HTTP request dispatched to the IIS worker process must first pass through this module before your application code has a chance to react.

Easy Auth Runtime Architecture
The internal runtime architecture of an App Service application that runs the Easy Auth IIS module (click to enlarge).

As you can see, the module runs in the same sandbox as your application, but is still very much separate from your application. It’s automatically injected when enabled via the management portal. No SDKs, specific languages, or any code changes are required. It is configured using environment variables, which are internally populated by the portal (or the Azure Resource Management REST APIs).

Alternatives

The do-it-yourself way to accomplish this could have been to use include your favorite auth middleware directly into your application code. As a developer, this gives you a lot more control, but requires more work and requires you to know what you’re doing (OAuth 2, OpenID Connect, cookies, encryption, HMACs, CSRF, replay-attacks, etc.), which can be scary if it’s security-related. The reality is that some people don’t want to have to think about these things. Why not have the platform take care of it for you?

Another logical way to achieve the same outcome could have been to leverage an authentication proxy which sits in front of your app. You may have even seen some Microsoft products which do this, such as API Management or the preview versions of API and Mobile apps (i.e. those prior to November 2015) which deployed separate Gateway web apps. However, it was decided that this approach is not ideal for the most common types of application backends.

Platform Integration

The best part of incorporating the authentication layer directly into the platform is that it can integrate very nicely with the platform. This ultimately benefits you, the customer, in a variety of ways. A few examples:

  • Integrated Identity: If you’re writing an ASP.NET app, you can access the identity and claims associated with the authenticated user using the ClientPrincipal.CurrentPrincipal API. Web API attributes such as [Authorize] also work natively. Even PHP apps benefit because we automatically set the REMOTE_USER server variable, allowing PHP apps to infer the identity of the user. This is huge for easily enabling you to do things like creating corporate MediaWiki apps (something we do internally at Microsoft).
  • Logging: If you’re using the Application Logs feature of App Service (which is an awesome feature, by the way), you’ll notice that Easy Auth traces are included directly in your application traces. If you see an authentication error that you didn’t expect, you can conveniently find all the details by looking in your existing application logs.
  • Error Tracing: For more advanced debugging, you enable Failed Request Tracing in your application. Because Easy Auth is an IIS module that runs in-process with your app, you can see exactly what role it might have played in a failed request. Just looks for references to a module named EasyAuthModule_32/64. Auth middleware, on the other hand, does not have this advantage because IIS can’t distinguish it from your application code.
  • File System Storage: If you have the Easy Auth Token Store enabled, we can cache OAuth tokens directly on disk rather than needing to provision and manage a separate storage account. I’ll talk more about the token store in a future post.
  • Configuration: All Easy Auth configuration is surfaced to the application as app settings. This is useful because your application code can easily read these settings. Take a look at the Kudu environment page to see them for yourself – all Easy Auth settings are prefixed with WEBSITE_AUTH_. This also makes it easier for us to expose experimental features that you can turn on using app settings.
  • Updates: New features and improvements can be added to your app without requiring you redeploy any part of your application.

There may be other benefits that I’ve missed, but I think you get the basic idea of why we decided on this integrated approach to authentication in App Service.

Performance

In terms of performance, the goal of Easy Auth is to ensure that the overhead of this feature is non-noticeable and/or an improvement over alternative authentication solutions. This design is already an improvement over gateway-architectures simply because there is no additional network hop between clients and your application. The Easy Auth module runs in-process with the application host (w3wp.exe).

In terms of the code itself, Easy Auth is actually built using mostly managed code. The attentive reader may have noticed that I said this is a native module earlier in this post, and it still is. However, the native layer is just a small shim between IIS and the core module implementation. What this means practically is that we can engineer an IIS module in .NET without taking a dependency on ASP.NET and System.Web. This is important because traditional managed modules (or more specifically ASP.NET) can incur a relatively heavy performance penalty which serves no benefit when hosting non-ASP.NET applications (PHP, Node.js, etc.).

Wrapping Up

Hopefully this information is useful, interesting, or both. Let me know in the comments if you have any feedback on the content of this post. If you have general questions or if you’re running into issues, I suggest posting on StackOverflow (please tag your questions with azure-app-service or azure-web-sites) or the forums so that others can easily find, rate, and participate in the discussion. For the highest level of support, take a look at some of our support plans. This is absolutely the best way to get our attention and prioritize any issues you may encounter.

If you have feature requests, I suggest you post and/or vote on one of our UserVoice pages (web apps, mobile apps, API apps). I’m always trying to think about how we can improve the feature in ways that make the most sense to real-life developers.

Also, feel free to reach out to me directly on Twitter.

Author: cgillum

Principal Software Engineer at Microsoft.

8 thoughts on “Architecture of Azure App Service Authentication / Authorization”

  1. Easy Auth is really easy.
    But it would be great to have a way to let User be authenticated using his provider choise,
    rather than using the configured default provider when trying to access a [Authorize] method.
    Does exist something like context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);

    To be used with App Service to make a request like: …/.auth/login/”provider”/callback ?

  2. Solved.
    Just followed instructions on link:
    https://azure.microsoft.com/en-us/blog/announcing-app-service-authentication-authorization/

    “Your application can trigger the same redirect itself by navigating the user to the /.auth/login/ endpoint of your site, where is one of aad, facebook, google, microsoftaccount, and twitter. This option is perfect for sites featuring a login button and for many mobile applications.”

    Worked ok for me:

    RedirectToAction(string.Format(“login/{0}/callback”,provider), “.auth”);
    return RedirectToAction(“LoginCallBack”, “Home”);

  3. I’m developing an ASP.NET Core app and this does not work for me: “you can access the identity and claims associated with the authenticated user using the ClientPrincipal.CurrentPrincipal API”

    I’m trying different options:
    – HttpContext.User.Identity
    – Thread.CurrentPrincipal.Identity
    – ClaimsPrincipal.Current.Identity
    – User.Identity

    All of them are empty. Any suggestions?

    1. Unfortunately this is expected. ASP.NET core does not support flowing in the identity from an external module the way that classic ASP.NET does. Your alternative is to use the /.auth/me endpoint to get the user claims. I’m not yet up-to-speed on the latest ASP.NET Core updates, but if there is a way to look at IIS server variables, you could also get the claims from the MS_CLIENT_PRINCIPAL server variable. At some point I’m hoping we can build a piece of ASP.NET Core middle-ware to make this easier.

Leave a Reply