Connecting ADFS to a Cordova application

Rory Braybrook
The new control plane
5 min readJan 9, 2018

I’ve assisted with a lot of integrations with ADFS and ADAL e.g. Android, command line, WPF etc. but then I was asked about Cordova.

This was one technology I wasn’t familiar with but to quote Vittorio:

Apache Cordova is a set of device APIs that allow a mobile app developer to access native device function such as the camera or accelerometer from JavaScript. Combined with a UI framework such as jQuery Mobile or Dojo Mobile or Sencha Touch, this allows a smartphone app to be developed with just HTML, CSS, and JavaScript. When using the Cordova APIs, an app can be built without any native code (Java, Objective-C, etc) from the app developer. Instead, web technologies are used, and they are hosted in the app itself locally (generally not on a remote http server). And because these JavaScript APIs are consistent across multiple device platforms and built on web standards, the app should be portable to other device platforms with minimal to no changes.

So I looked around for some references for this and found nothing. The closest was this link from Auth0 where you take two pieces that you know work viz.

  • Auth0 and Cordova
  • Auth0 and ADFS

and then chain them together:

Cordova → Auth0 → ADFS

The starting point is this article (aka sample) around integrating Azure AD with an Apache Cordova application. To make it easy, we are going to run on Windows and not bother about actual devices or emulators.

If you have an Azure AD tenant, run this sample and confirm that it works. It points to an existing Azure AD application but you won’t be able to authenticate because you don’t know the credentials of this tenant. So change the config. to use your tenant and confirm that it all works.

You should see:

Now for ADFS. First off, this has to be ADFS running on Windows Server 2016 (aka ADFS 4.0). This version has full OpenID Connect / OAuth support.

Obviously, the sample is not going to work as is because it calls the Graph API and this has no meaning for ADFS.

To simplify matters, we’ll use a built- in ADFS web API instead — the “userinfo” endpoint.

To configure ADFS, we know from the Azure AD article that we need a native client.

The ADFS equivalent is “Native application accessing a web API”.

We create the native application by following the steps in the ADFS wizard. Note the client ID. We will use this later.

Now create the web API.

The identifier is:

https://my-adfs/adfs/userinfo

Set the policy to “Permit everyone”.

Set the scope to “openid”.

In index.js in the sample, change the existing code to:

var authority = “https://my-adfs/adfs",
redirectUri = “http://MyDirectorySearcherApp",
resourceUri = “urn:microsoft:userinfo”,
clientId = “77403d77-fcd0–49c6–9bb7-c114ae05e349”,
graphApiVersion = “2013–11–08”;

Note the “clientId” is derived from the configuration above.

As per this article, we know that ADFS requires:

authContext = new AuthenticationContext(authority, false);

so we change the call in index.js to:

app.context = new Microsoft.ADAL.AuthenticationContext(authority, false);

The changed index.js code be found in this gist with all changes marked by:

“// ADFS”.

So we run up the application:

cordova run windows

and it just hangs with no obvious error indication. Can we use VS to debug?

cordova build windows

We note there are two VS solution files.

…\DirSearchClient\platforms\windows

CordovaApp.sln

CordovaApp.vs2013.sln

Running the first in VS 2017 produced a number of “incompatible with this version” error messages so I just ran the second VS 2013 solution.

Note: If you are using VS 2013 and see a ‘WinRTError: Class not registered’ runtime error on Windows make sure Visual Studio Update 5 is installed.

Once the issues have been sorted out, when we run the application, we first get the ADFS HRD screen.

And then the standard login screen.

We authenticate, get an access token and then pass it to the userinfo endpoint as proof of authentication.

Tip: If you get 403 errors when trying to connect to the userinfo endpoint, have a look at the access token returned using something like jwt.io.

Most of these types of problems are caused by an incorrect “aud” or “iss”.

After calling the userinfo endpoint, we see in the debug:

We use debug to display the userinfo payload to avoid rewriting the logic that used to display the Graph API details 😄.

The only element in the userinfo payload in ADFS is the “sub” as above.

Update

Since I wrote this, I’ve been looking at a SPA application with ADFS and Angular.

This has a web API that controls a Todo list.

You can see I’ve already added two very informative tasks! “aaa” and “sss”.

So I thought I would change the sample to access this web API instead of the “userinfo” endpoint.

The SPA sample runs on:

https://localhost:44326/

so the configuration changes to:

var authority = “https://my-adfs/adfs",
redirectUri = “http://MyDirectorySearcherApp",
resourceUri = “
https://localhost:44326/",
clientId = “77403d77-fcd0–49c6–9bb7-c114ae05e349”,
graphApiVersion = “2013–11–08”;

Only the resourceUri has changed.

The web API code in index.js changes to:

// ADFS
// var url = “https://my-adfs/adfs/userinfo";
var url = “https://localhost:44326/#/TodoList";

For the ADFS changes, we need to add permissions to the web API. Under the “Client Permissions” tab, we allow the original SPA Angular application and the Cordova application to access the web API.

Just for completeness, this is the web API configuration.

Using the same debug trick as above to access the payload, when we call the web API we see:

All good!

--

--

Rory Braybrook
The new control plane

NZ Microsoft Identity dude and MVP. Azure AD/B2C/ADFS/Auth0/identityserver. StackOverflow: https://bit.ly/2XU4yvJ Presentations: http://bit.ly/334ZPt5