Azure Active Directory Authentication

This article explains the process of authenticating the users, using Azure Active Directory authentication. This article provides high level idea on an Azure AD authentication for a .NET Application and an Android App with .NET back-end.

How Azure AD authentication functions

In a normal AD authentication, all the systems/users in a network are a part of the directory and they can access the secured system with their AD credentials. However, Azure handles it with an Active Directory.

Azure creates a default Active Directory for you when you purchase an Azure subscription or an Office 365 subscription or any other Microsoft Service. We can also create active directories, and it’s free. Ideally, we should create an Active Directory for each environment.

All the users in an Active Directory can consume applications in the respective directory by providing their Azure credentials. Administrator has to create these users under Active Directory. Admin should generate a temporary password for the users, which the users have to change in their 1st login.

Create Active Directory

Navigate to Azure Active Directory. Select the domain names. Select "Add" on top. Provide a valid domain name. This domain name will be validated within 72 hours. If it’s a valid domain, an Active Directory will be created.

Azure

Fill in all the details for your domain and click "Verify". If the details provided by you are valid, the directory will be created within 72 hours.

Azure

For more details on domain creation, visit https://docs.microsoft.com/en-us/azure/active-directory/active-directory-add-domain

Create users under Active Directory

Navigate to Azure Active directory in classic portal. Select the directory in which you want to add the users. Select "Users". You should see the list of users in this directory. If you have not added any user, only the default user (account owner) should appear. Click ADD + in bottom.

Azure

A pop up should appear for filling the user details. Based on the type of the user; you select, you will find the user details. Fill them out.

For new users in your organization, Admin will get a temporary password, which he needs to send out to the user and the user has to change it on the first login.

Azure

Authentication flow for native Application to API

(From Microsoft documentation)

  1. Using a Browser pop-up, the native Application makes a request to the authorization endpoint in an Azure AD. This request includes the client ID and the redirect URL of the native Application is shown in the Management Portal and the Application ID URL for the Web API. If the user hasn’t already signed in, they are prompted to sign in again

  2. Azure AD authenticates the user. If it is a multi-tenant Application and consent is required to use the Application, the user will be required to consent, if they haven’t already done so. After granting consent and upon successful authentication, Azure AD issues an authorization code response back to the client Application’s redirected URL.

  3. When Azure AD issues an authorization code response back to the redirected URL, the client application stops browser interaction and extracts the authorization code from the response. Using this authorization code, the client application sends a request to Azure AD’s token endpoint that includes the authorization code, details about the client application (client ID and redirect URI), and the desired resource (application ID URI for the web API).

  4. The authorization code and information about the client application and web API are validated by Azure AD. Upon successful validation, Azure AD returns two tokens: a JWT access token and a JWT refresh token. In addition, Azure AD returns basic information about the user, such as their display name and tenant ID.

  5. Over HTTPS, the client application uses the returned JWT access token to add the JWT string with a “Bearer” designation in the Authorization header of the request to the web API. The web API then validates the JWT token, and if validation is successful, returns the desired resource.

  6. When the access token expires, the client application will receive an error that indicates the user needs to authenticate again. If the application has a valid refresh token, it can be used to acquire a new access token without prompting the user to sign in again. If the refresh token expires, the application will need to interactively authenticate the user once again.

Most of the protocol details such as the browser pop-up, token caching, and handling of refresh tokens are handled by AD Authentication Libraries.

Registering applications on Azure AD

We need to register one Web app and one native app in Azure AD directory.

Log in to Azure portal -> Azure Active Directory -> App Registration blade.

Azure

Here, you can see the list of applications created earlier. Click on “+ Add” to register a new application.

To register the API,

  • Give a user friendly name to your service.
  • Select “Web application and / or Web API” for type of application.
  • Give Sign-on URL where user can sign-in, which is generally the base URL.
  • Click on Create.

    Azure

To register the native app,

  • Give a user-friendly name to your service.
  • Select “Web application AND / OR web API” for type of application.
  • Give Redirect URI where user will be navigated after successful log in.
  • Click on Create.

    Azure
Configure Application on Azure AD

Now, we need to configure the newly registered apps.

To configure the Service App, navigate to Azure Active Directory → App Registrations → Service App → Properties blade → Copy the App ID URI.


Azure

Navigate to Azure Active Directory → App Registrations → Select the service App → Required permissions blade → select Windows Azure Active Directory → Select the application permissions & delegated permissions → Save it.

Azure

Navigate to Azure Active Directory → App Registrations → Select the service App → Select Keys blade → Generate a key. (Fill Description & expires fields, azure will create a secret key. Copy the secret key & save safely as you can’t recover it once you leave this blade)

Azure

To configure the Native App,

Navigate to Azure Active Directory → App Registrations → Select the native App → Select Required Permissions Blade → Select windows azure active directory → Select the application permissions & Delegated permissions → Save it

Azure

Now we need to allow our client app consume our service application.

Navigate to Azure Active Directory → App Registrations → Select the native App → Select Required Permissions Blade → Click on “+ Add” → Select “Select an API” blade → Type name of the service app → azure will auto populate the service → select your service → Click on “Select”

Azure

Select “Select Permissions” blade → Give access to “Access <Service_App name>” → Click on “Select” → Click on “Done”

Azure

Again back in the permission to the other applications section of configure screen, click on the delegated permission drop down of the newly added service and select “Access <Service_Name>”. Click on save.

Server-side Implementation
  1. We need to install the following nuget packages.

    1. Owin.Security.ActiveDirectory
    2. Owin.Security.Owin
    3. Owin.Security.Jwt

  2. To safeguard our service, we will update IsAuthorized() of AuthorizeUserFilter to validate if request is coming from trusted client.
    1. private static string trustedCallerClientId = ConfigurationManager.AppSettings["ida:TrustedCallerClientId"];  
    2. protected override bool IsAuthorized(HttpActionContext actionContext)  
    3.         {  
    4.             bool isAuthenticated = false;  
    5.             try  
    6.             {  
    7.                 string currentCallerClientId = ClaimsPrincipal.Current.FindFirst("appid").Value;  
    8.                 isAuthenticated = currentCallerClientId == trustedCallerClientId;  
    9.             }  
    10.             catch (Exception ex)  
    11.             {  
    12.                 new CustomLogger().LogError(ex, "Invalid User");  
    13.                 isAuthenticated = false;  
    14.             }  
    15.             return isAuthenticated;  
    16.         }  

We have AuthorizeUserFilter registered globally as follows in

  • MobileApp.cs for mobile service
  • cs for web app.

    config.Filters.Add(new AuthorizeUserFilter());
  1. To make a user or native client get validated before accessing our service, we need to enable azure AD authentication in startup method.

    We will add following code block in ConfigureMobileApp() of startup class in MobileApp.cs file
    1. app.UseWindowsAzureActiveDirectoryBearerAuthentication(  
    2.                 new WindowsAzureActiveDirectoryBearerAuthenticationOptions  
    3.                 {  
    4.                     TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters()  
    5.                     {  
    6.                         ValidAudience = ConfigurationManager.AppSettings["ida:Audience"]  
    7.                     },  
    8.                     Tenant = ConfigurationManager.AppSettings["ida:Tenant"]  
    9.                 });  
  1. We need to have following keys in web.config/ App settings
    1. <!--Directory_Name.onmicrosoft.com-->  
    2. <add key="ida:Tenant" value="Directoryname.onmicrosoft.com" />  
    3. <!--App ID URI of service APP-->  
    4. <add key="ida:Audience" value="https://Directoryname.onmicrosoft.com/00000000-0000-0000-0000-000000000000" />  
    5. <!--Client Application Client ID-->  
    6. <add key="ida:TrustedCallerClientId" value="00000000-0000-0000-0000-000000000000" />  
Mobile Implementation

Azure

Azure

Download and install Azure AD SDK using the following statement in app module gradle file.

  1.  dependencies {  
  2.    compile('com.microsoft.aad:adal:1.1.1') {  
  3.        exclude group: 'com.android.support'  
  4.    }  
  5. }   
  1. Register AuthenticationActivity in manifest
  2. After successful installation of SDK, We need to initialize Azure AD by specifying authority for their internal caching purpose. Add onActivityResult() as shown in below.
    1. try {  
    2.    AuthenticationContext mAuthContext =   
    3.          new AuthenticationContext(ToDoActivity.this, Constants.AUTHORITY_URL,  
    4.                                     false);  
    5.       
    6.   
    7.     mAuthContext.acquireToken(context, RESOURCE_ID,  
    8.             CLIENT_ID, REDIRECT_URL, USER_HINT, "nux=1&" + EXTRA_QP,  
    9.             new AuthenticationCallback<AuthenticationResult>() {  
    10.   
    11.                 @Override  
    12.                 public void onError(Exception e) {  
    13.                     //on Error  
    14.                 }  
    15.   
    16.                 @Override  
    17.                 public void onSuccess(AuthenticationResult result) {  
    18.                     //success retrieve the Access token from result            }  
    19.             });  
    20. catch (Exception e) {  
    21.     //error  
    22. }  
    23.   
    24.   
    25. @Override  
    26. protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
    27.     super.onActivityResult(requestCode, resultCode, data);  
    28.     mAuthContext.onActivityResult(requestCode, resultCode, data);  
    29. }  
  1. Invoking acquireToken(..) using AuthenticationContext instance causes Login screen to shown on top of host activity as shown in above screenshots.After successful authentication we will get callback as
    1. mAuthContext.acquireToken(this, RESOURCE_ID, CLIENT_ID, REDIRECT_URL, USER_HINT, "nux=1&" + EXTRA_QP,  
    2.         new AuthenticationCallback<AuthenticationResult>() {  
    3.             @Override  
    4.             public void onSuccess(AuthenticationResult result) {  
    5.                  // Get AccessToken, RefreshToken, UserInfo from result   
    6.             }  
    7.   
    8.             @Override  
    9.             public void onError(Exception e) {  
    10.                 // Failure  
    11.             }  
    12.         });  
  1. After successful authentication using acquirToken() call, we can get access token, refresh token, user.

  2. To avoid asking username and password for each authentication we use acquireTokenSilent() to do authentication at background without user notice.For that we need Azure user id which we will get from
    1. mAuthContext.acquireTokenSilent(RESOURCE_ID, CLIENT_ID, USER_AZURE_ID,   
    2. new AuthenticationCallback<AuthenticationResult>() {  
    3. @Override  
    4.             public void onSuccess(AuthenticationResult result) {  
    5.                  // Get AccessToken, RefreshToken, UserInfo from result   
    6.             }  
    7.   
    8.             @Override  
    9.             public void onError(Exception e) {  
    10.                 // Failure  
    11.             }  
    12.         });  
  1. While configuring login screen, we need to mention tenant URL, client Id of our subscription.
  1. Once the validation is successful, it triggers the callback method with AuthorizationResult object which has Access Token, we will save in preferences for later use.
    1. appPreferences.setUserLoggedIn(true);  
    2. appPreferences.setAzureUserId(result.getUserInfo().getUserId());  
    3. appPreferences.setUserDisplayableId(result.getUserInfo().getDisplayableId());  
    4. appPreferences.setAccessToken(result.getAccessToken());  
    5. appPreferences.setRefreshToken(result.getRefreshToken());  
  1. On successful retrieving of access token, access token in cached in mobile and added in header as part of every request and user will be navigated to home screen.

  2. While user launches the application in offline mode, it will verify for cached access token and navigates user to home screen accordingly.

  3. Offline mode require access token to verify, but it is not recommended because in offline mode access token verified i.e expired or not. Expired access token requires app to be online to generate new accesstoken.

  4. If no access token available, then user can’t be able to navigate to home screen.

  5. In offline mode, Only silent authentication is supported because it will not ask user credentials to authenticate instead it will use cached access token, user id to do this.

Logout

  1. public void doLogout(){  
  2.     appPreferences.clear();  
  3.     mAuthContext.getCache().removeAll();  
  4.     CookieManager cookieManager = CookieManager.getInstance();  
  5.     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {  
  6.         CookieSyncManager.createInstance(this);  
  7.     }  
  8.     cookieManager.removeSessionCookie();  
  9.     CookieSyncManager.getInstance().sync();  
  10.   
  11.   
  12.     Log.d(TAG, "User logged out");  
  13.   
  14.     // launch login screen  
  15.     doUserAuthentication();  
  16. }  

We need to specify  the following constants to work azure ad authentication at mobile client (eg).

  1. // https://login.microsoftonline.com/<Directory_Id>  
  2. public static String AUTHORITY_URL = "https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000";  
  3. // Client Id of client app AppID  
  4. public static String CLIENT_ID = "00000000-0000-0000-0000-000000000000";  
  5. // App ID of service AppID URI  
  6. public static String RESOURCE_ID = "https://Directoryname.onmicrosoft.com/00000000-0000-0000-0000-000000000000";  
  7. //Service url   
  8. public static String REDIRECT_URL = "https://demo";  
  9.   
  10. public static String CORRELATION_ID = "";  
  11. public static String USER_HINT = "";  
  12. public static String EXTRA_QP = ""