Sayan Pal
Sayan Pal

Reputation: 4956

ADAL JS not attaching user token while invoking WebApi

I am using ADAL JS for authenticating the users against Azure AD. And as I am new to ADAL JS, I started reading with following articles, which I find very informative:

After reading the articles, I had the impression that ADAL JS intercepts the service calls and if the service url is registered as one of the endpoint in AuthenticationContext configuration, it attaches the JWT token as Authentication Bearer information.

However, I found the same is not happening in my case. And after some digging, it seemed to me that it is only possible, if adal-angular counter part is also used, which I am not using currently, simply because my web application is not based on Angular.

Please let me know if my understanding is correct or not. If I need to add the bearer information explicitly, the same can be done, but I am more concerned whether I am missing some out-of-the-box facility or not.

Additional Details: My present configuration looks like following:

private endpoints: any = {
    "https://myhost/api": "here_goes_client_id"
}
...
private config: any;
private authContext: any = undefined;
....
this.config = {
    tenant: "my_tenant.onmicrosoft.com",
    clientId: "client_id_of_app_in_tenant_ad",
    postLogoutRedirectUri: window.location.origin,
    cacheLocation: "sessionStorage",
    endpoints: this.endpoints
};
this.authContext = new (window["AuthenticationContext"])(this.config);

Also on server-side (WebApi), Authentication configuration (Startup.Auth) is as follows:

public void ConfigureOAuth(IAppBuilder app, HttpConfiguration httpConfig)
{
    app.UseWindowsAzureActiveDirectoryBearerAuthentication(
        new WindowsAzureActiveDirectoryBearerAuthenticationOptions
        {
            Tenant = "my_tenant.onmicrosoft.com",
            TokenValidationParameters = new TokenValidationParameters
            {
                ValidAudience = "client_id_of_app_in_tenant_ad"
            }
         });
}

However, the Authorization is always null in request.Headers.

UPDATE: It seems that the same applies for auto-renewal of tokens as well; when used in conjunction with adal-angular, the renewal of token works seamlessly by calling AuthenticationContext.acquireToken(resource, callback) under the hood. Please correct me if I am wrong.

Upvotes: 0

Views: 1807

Answers (2)

mike nelson
mike nelson

Reputation: 22136

ADAL.JS is incompatible with v2.0 implicit flow. I could not get it working since I set my project up recently and don't think projects are backwards compatible.

This was very confusing and took me a long time to figure out that I was mixing up the versions, and can't use ADAL.JS with v2.0. Once I removed it, things went much smoother, just did a couple of XHR requests and a popup window, no magic actually required!

Here is code for v2:

function testNoADAL() {
    var clientId = "..guid..";
    var redirectUrl = "..your one.."
    var authServer = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?";
    var responseType = "token";
    var stateParam = Math.random() * new Date().getTime();

    var authUrl = authServer +
                                "response_type=" + encodeURI(responseType) +
                                "&client_id=" + encodeURI(clientId) +
                                "&scope=" + encodeURI("https://outlook.office.com/Mail.ReadWrite") +
                                "&redirect_uri=" + encodeURI(redirectUrl) +
                                "&state=" + stateParam;

    var popupWindow = window.open(authUrl, "Login", 'width=' + 300 + ', height=' + 600 + ', top=' + 10 + ', left=' + 10 + ',location=no,toolbar=yes');
    if (popupWindow.focus) {
        popupWindow.focus();
    }
}

Note: redirectUrl will appear in popup window, needs to have code in it to pass location hash, such as this:

<script>window.opener.processMicrosoftAuthResultUrl(location.hash);window.close();</script>

function processMicrosoftAuthResultUrl(hash) {
    if (hash.indexOf("#") == 0) {
        hash = hash.substr(1);
    }
    var obj = getUrlParameters(hash);
    if (obj.error) {
        if (obj.error == "invalid_resource") {
            errorDialog("Your Office 365 needs to be configured to enable access to Outlook Mail.");
        } else {
            errorDialog("ADAL: " + obj.error_description);
        }
    } else {
        if (obj.access_token) {
            console.log("ADAL got access token!");
            var token = obj.access_token;
            var url = "https://outlook.office.com/api/v2.0/me/MailFolders/Inbox/messages";
            $.ajax({
                type: "GET",
                url: url,
                headers: {
                    'Authorization': 'Bearer ' + token,
                },
            }).done(function (data) {
                console.log("got data!", data);
                var message = "Your latest email is: " + data.value[0].Subject + " from " + data.value[0].From.EmailAddress.Name+ " on " + df_FmtDateTime(new Date(data.value[0].ReceivedDateTime));
                alertDialog(message);

            }).fail(function () {
                console.error('Error getting todo list data')
            });
        }
    }
}

function getUrlParameters(url) {
    // get querystring and turn it into an object
    if (!url) return {};
    if (url.indexOf("?") > -1) {
        url = url.split("?")[1];
    }
    if (url.indexOf("#") > -1) {
        url = url.split("#")[0];
    }
    if (!url) return {};
    url = url.split('&')
    var b = {};
    for (var i = 0; i < url.length; ++i) {
        var p = url[i].split('=', 2);
        if (p.length == 1) {
            b[p[0]] = "";
        } else {
            b[decodeURIComponent(p[0])] = decodeURIComponent(p[1].replace(/\+/g, " "));
        }
    }
    return b;
}

Upvotes: 0

ezile
ezile

Reputation: 571

After reading the articles, I had the impression that ADAL JS intercepts the service calls and if the service url is registered as one of the endpoint in AuthenticationContext configuration, it attaches the JWT token as Authentication Bearer information.

This will work only if your application is angular based. As you mentioned, the logic for this lives in adal-angular.

If, however, you want to stick to pure JS, you will not get the automatic "get-access-token-and-attach-it-to-header" support. You can use acquireToken(resource, callback api to get a token for the endpoint. But you will have to do some work in the controller that is sending the request to the api.

This might give you some idea: https://github.com/Azure-Samples/active-directory-javascript-singlepageapp-dotnet-webapi/blob/master/TodoSPA/App/Scripts/Ctrls/todoListCtrl.js. This sample does not uses angular.

Upvotes: 2

Related Questions