Calling Azure AD Secured Azure Function Externally From JavaScript

My customer recently had a need to securely call an HTTP trigger on an Azure Function remotely from an arbitrary client web application.  In this scenario securely meant ensuring that the user has logged into Azure Active Directory (AAD), but any number of authentication providers could be used.  The SharePoint Patterns and Practices (PnP) team had posted a video (SharePoint PnP Webcast – Calling external APIs securely from SharePoint Framework) that used the SharePoint Framework but my team needed to do this from vanilla JavaScript.  Many thanks to the PnP team and my peer Srinivas Varukala for their inspiration and code samples.

Overview

The key components to this solution involve the following:

  • Azure AD app registration (used to enforce authentication on Azure Function)
  • Azure Function configured to enforce Azure AD authentication
  • Client web application with JavaScript code to call the Azure Function

Azure Function

In the Azure Portal create a new Azure Function.  Choose an HTTP Trigger and use the language of choice (I’m using C# script in this example).  The Azure Function will validate if a claims principal exists on the incoming request and then output to the logs the name of the user if authenticated.

<Update 2018-05-02>

Note: the Azure portal currently does not support the headers required for CORS (cross-origin resource sharing) requests that contain credentials.  Feedback (source) has been provided to the Azure App Service team to support this but was declined.  As such the manual processing of CORS  requests is not supported at this time.  You will need to determine if this workaround works for you or not.

</Update 2018-05-02>

using System.Net;
using System.Security.Claims;
using System.Threading;
public static HttpResponseMessage Run(HttpRequestMessage req, TraceWriter log)
{
  log.Info("C# HTTP trigger function processed a request.");
// check for authenticated user on incoming request
  if (!ClaimsPrincipal.Current.Identity.IsAuthenticated)
  {
    log.Info("Claims: Not authenticated");
  }
  else
  {
    log.Info("Claims: Authenticated as " + ClaimsPrincipal.Current.Identity.Name);
  }

  var resp = req.CreateResponse(HttpStatusCode.OK, "Hello there " + ClaimsPrincipal.Current.Identity.Name);

  // manually process CORS request
  if (req.Headers.Contains("Origin"))
  {
    var origin = req.Headers.GetValues("origin").FirstOrDefault();
    resp.Headers.Add("Access-Control-Allow-Credentials", "true");
    resp.Headers.Add("Access-Control-Allow-Origin", origin);
    resp.Headers.Add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
    resp.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Set-Cookie");
  }
  return resp;
}

Azure AD App

In order to enforce Azure AD authentication on the Azure Function an Azure AD app registration needs to be created.  Log into the Azure AD admin portal.  Under Azure Active Directory –> App Registrations create a new app registration.

SecureCallAFFromJS1

Take note of the Application ID (also known as client ID) for the application created.  This will be used later in the Azure App Service authentication / authorization configuration.

SecureCallAFFromJS2

The default permissions for the Azure AD app registration (delegated: sign in and read user profile) will be sufficient.

SecureCallAFFromJS3

SecureCallAFFromJS4

Enforce authentication

Return to the Azure Function and navigate to the Platform features –> Authentication / Authorization screen.  Turn App Service Authentication to On, set “Action to take…” to “Log in with Azure Active Directory”, then click the Azure Active Directory authentication provider to configure it as follows.

SecureCallAFFromJS5

Fill in the Application ID / Client ID from the previously created Azure AD app registration.  Specify the IssuerUrl of the Azure AD domain (typically https://login.microsoftonline.com/TENANT_NAME_GOES_HERE.onmicrosoft.com).

SecureCallAFFromJS6

Remove CORS configuration

As noted previously, the Azure portal currently (as of writing May 1, 2018) does not support Azure App Service processing CORS requests that contain credentials.  As such removing all domains from the CORS configuration in Azure Portal is unsupported.  Please validate if this workaround works for you or not.

SecureCallAFFromJS7

Client code

In this example I started with a .Net Framework MVC project from Visual Studio 2017 v15.6.7 but the code could be hosted on any page with HTML, JavaScript, and a logged in user to Azure AD.  Note that the MVC project allows enforcing Azure AD authentication which is what I was most interested in.

SecureCallAFFromJS8

SecureCallAFFromJS9
HTML snippet to include inside of an IFRAME element with source pointing to root of Azure Function.

SecureCallAFFromJS13

JavaScript snippet to call HTTP trigger of Azure Function.

Note that in a production scenario you would want to ensure that the IFRAME has loaded fully (and thus authentication cookie set) prior to the Azure Function being called.

  $(document).ready(function () {
    $("#btnExternalCall").click(function (e) {

      var serviceURL = "https://NAME_OF_AZURE_FUNCTION_GOES_HERE.azurewebsites.net/api/HttpTriggerCSharp1";

      $.ajax({
        url: serviceURL,
        type: "GET",
        xhrFields: {
          withCredentials: true
        },
        crossDomain: true,
        success: function (data) {
          alert("Success: " + data);
        },
        error: function (ex) {
          alert("Failure getting user token");
      }
    });
  });
});

Testing

When all has been configured you can test scenario.  If you enter F12 developer tools from your browser of choice you should see the authentication cookie for both the client web application as well as the Azure Function domains.

SecureCallAFFromJS10

After issuing the call to the HTTP Trigger on the Azure Function you should see that the call was indeed authenticated and the ClaimsPrincipal is returned.

SecureCallAFFromJS11SecureCallAFFromJS12

Conclusion

This is a very powerful capability being able to ensure that an HTTP trigger on an Azure Function only allows authenticated users to call the endpoint.  Hopefully this post helps others who have a similar need.  Please leave and questions or feedback in the comments below.

-Frog Out

Converting An Enter Key Press Into A Tab Key Press For Web Forms

How many times have you been filling out an online form and halfway through filling in your responses you accidentally press the Enter key which then attempts to submit the form?  This can be a common problem when the online form is wired up to have a “submit” button be the default form button on a page.

The most complete solution to this issue is having your submit process be able to handle all scenarios of submission (incomplete, invalid, etc).  If you are looking for a quick (partial) fix though, it is possible to trap the Enter key press and convert it to another key press (e.g. Tab key.)  A  few simple lines of JavaScript and adding a client-side event handler to your input controls can accomplish that.  I wish I could claim the credit for this, but I found this on many online resources (reference 1 and reference 2.)  Note: My example focuses on Internet Explorer; I have not tested against other browsers at this time.  Please read these references for more information on cross-browser compatibility.

ConvertVans1

My silly attempt at humor

First, you’ll need to add a JavaScript function to trap the Enter key press (keyCode 13) and convert it to a Tab key press (keyCode 9).  Since my current work is on SharePoint development I place most of my JavaScript functions into an external file (previous blog post details) to be referenced by web part code.  Below are two examples, first on an HTML or ASPX page (includes tag) and second in an external file (without tag.)

"JavaScript">

function ModifyEnterKeyPressAsTab() {

    if (window.event && window.event.keyCode == 13) {

        window.event.keyCode = 9;

    }

}


JavaScript block on HTML/ASPX page
function ModifyEnterKeyPressAsTab() {

    if (window.event && window.event.keyCode == 13) {

        window.event.keyCode = 9;

    }

}

JavaScript block in external file

    The next step is to call the above JavaScript function from an added client-side event handler to any input controls users will be filling out.  These input controls include textboxes, radio buttons, etc.  A client-side event handler (vs. server-side) are used so that  any key press will be intercepted before the server is able to respond (e.g. accept a premature form submit.)  Below is an example of adding the event handler to a Textbox.

TextBox textbox1 = new TextBox();

textbox1.Attributes.Add("onKeyDown", "ModifyEnterKeyPressAsTab();");

In the above example, any time a user has focus on the Textbox and presses a key our JavaScript function will be called.  If the key press is Enter, the function will return a Tab key press which moves focus to the next control in TabIndex order.  Note: Since we are converting to a Tab key press, you’ll want to make sure the TabIndex of your controls is set appropriately so user’s are progressed in the desired order down/across the page.

Conclusion

Converting your Enter key press into another key press, such as Tab, is a rather crude workaround to a common problem of early form submission, but it’s a starting point to alleviating issues your end users may run into.  If you read the resources I linked to above you’ll notice there is additional information on how to make this solution more cross-browser friendly (specifically for FireFox vs. IE.)  If you have any comments on this topic or found this post helpful, feel free to leave feedback below.

-Frog Out

Register External JavaScript and CSS Files On SharePoint 2007 WebPart

     If mathematics teaches us anything, it’s that there are usually multiple solutions for one problem.  When you need to add a reference to a JavaScript or CSS file for a .Net web application (such as SharePoint) from the code behind you have many options available to you.  Below are two SharePoint specific methods that you can use to reference a JavaScript and CSS file from within a web part (or any other custom code solution.)

 

Registering Javascript 

   The first example registers an external JavaScript file.  Typically when you reference an external JavaScript file it is cached by the browser so it doesn’t need to be re-downloaded each time the page is loaded.  This is good for improving performance, but can be an issue when you update your JavaScript file and find that you are still executing the old JavaScript.  Using the below method appends a unique postfix to the JavaScript filename so that a new version is downloaded as needed without having to reset browser files or do other sorts of trickery.

using Microsoft.SharePoint.WebControls;

ScriptLink.Register(this.Page, <JS_FILE_NAME>, true);

Example of output

"text/javascript" language="javascript" 

src="/_layouts/1033/MyAppCommon/JS_File_Name.js?97XRFCZSv%2BI8aGRCPfUgTg%3D%3D">

 

Registering CSS

     The second example registers a cascading style sheet.  This is useful for when you have a CSS file that contains branding styles that you need to include with a web part but don’t want to include on a master page.  This method will handle adding the link to the <head> tag of the page as needed.

using Microsoft.SharePoint.WebControls;

CssRegistration.Register(CSS_FILE_NAME);

Example of output

<link rel="stylesheet" type="text/css" href="/_layouts/MyAppCommon/Css_FileName.css"/>

 

Conclusion

    These are both very simplistic methods that can be utilized on your SharePoint web parts to help you include JavaScript and CSS files.  On my current project we have used these quite a bit to pair custom JavaScript and CSS with individual web parts instead of at a higher level where they may not be appropriate.  Perhaps you’ll be able to make use of these as well.  Until next time, happy SharePoint’ing.

Links

Scriptlink.Register MSDN page

CSSRegistration.Register MSDN page

 

     -Frog Out