Azure App Services authentication to a foreign Azure Active Directory
Overview
You have some code you have created in your subscription and a customer wants to authenticate and use your application. You are not connected to any other Azure Active Directory authentication. This is bit of a contrived example but will give you some insight in to how Azure App Services authentication works.
Setup
Create a new Azure App Service Web in your Subscription. Ensure it is working fine and deploy it (do not specify any authentication yet). In my case the app is called ‘jsandersauthtoanotherazuread’ and the full URL is https://jsandersauthtoanotherazuread.azurewebsites.net/.
The name of the Azure AD tenant I want to do the auth for my app is jsandersrocks.onmicrosoft.com
The steps will then be:
- Give the URL to the Azure AD tenant admin of jsandersrocks so the callback URL can be assigned and the app created
- jsandersrocks Creates an Azure App Services in there tenant and give you the issuer, and application ID information
- You use this to configure your app for authentication
Walkthrough
When the app authenticates it will have a generated callback url that is of the format: https://jsandersauthtoanotherazuread.azurewebsites.net/.auth/login/aad/callback . I need to give this callback URL to the Azure AD tenant owner.
Tenant Directory owner tasks:
The owner of the Tenant Directory creates a dummy app (with any name) and sets the login url to the callback url above. The name will be the name that is shown when you login (see below). Choose wisely! The Sign-on URL should be the call back url above:
Then copies the generated app id to give to you from the properties of this new app: 512bf2b6-8a54-4c0b-9c8e-31350b16f606
and give you the issuer Directory ID from the Properties tab of the Active Directory page: 3151db49-e251-45a6-9f58-2e90469383de. You will use this to build the issuer ID.
Your tasks:
Turn on App Service Authentication for your app:
Configure the Azure Active Directory Authentication by clicking on the Advanced button and use the information the Tenant Directory owner gave you. The app ID is used for the Client ID field and the Issuer Url is constructed from the Directory ID of the form: https://sts.windows.net/DIRECTORYIDHERE
Be sure to save your changes.
Test the auth to ensure it works - https://jsandersauthtoanotherazuread.azurewebsites.net/.auth/login/aad
Errors
If you have trouble, the sign in page will tell you what the issue is. For example, if the callback URL in the Tenant Directory was not correct (I initially used http instead of https) you get an error like this:
Sign In
Sorry, but we’re having trouble signing you in.
We received a bad request.
- Additional technical information:
Correlation ID: cfe9995f-bae7-4fe2-a7d8-24649b92493c
Timestamp: 2017-06-09 18:29:44Z
AADSTS50011: The reply address 'https://jsandersauthtoanotherazuread.azurewebsites.net/.auth/login/aad/callback' does not match the reply addresses configured for the application: '512bf2b6-8a54-4c0b-9c8e-31350b16f606'. More details: not specified
Additional Tasks
Now that I am logged in, I will add a login button (if not logged in) and display the logged in user information. You can do this in global.asax, page level or in an on_authenticated method.
Login button
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="LoginButton.Default" %>
<!DOCTYPE html>
<html xmlns="https://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="Button1" runat="server" Text="Button" />
<asp:Label ID="Label1" runat="server" Text="Not Logged In"></asp:Label>
</div>
</form>
</body>
</html>
code:
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// if authenticated...
if (this.User.Identity.IsAuthenticated)
{
Button1.Visible = false;
Label1.Text = this.User.Identity.Name;
}
else {
Button1.Visible = true;
Label1.Text = "Not Authenticated";
}
}
protected void Button1_Click(object sender, EventArgs e)
{
Response.Clear();
Response.Redirect("/.auth/login/aad?post_login_redirect_url=/");
Response.Flush();
}
}
Starting an in-private or incognito browser session, when I first hit the page I am not authenticated but when I hit the button I go through the auth sequence and display the email address:
Conclusion
This just scratches the surface of what you can do. The point is, Azure App Services authentication can take the heavy lifting of authentication off or your plate and you can do some powerful things. This showed that as long as you configure the application with the correct issuer and app ID, it is able to validate and trust the token from a provider you do not have access to (with some cooperation from the sender).
If you want to do fancy things like authenticate to many different Azure AD tenants then you do need to utilize ADAL but that is beyond the scope of this post.
Drop me a note if you found this useful!
More references
The Bible of auth for me: https://www.microsoftpressstore.com/store/modern-authentication-with-azure-active-directory-for-9780735696945
Overview of auth scenarios: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-authentication-scenarios
App Roles: https://blogs.msdn.microsoft.com/waws/2017/03/09/azure-app-service-authentication-app-roles/
App Groups: https://blogs.msdn.microsoft.com/waws/2017/03/13/azure-app-service-authentication-aad-groups/