How can I pass windows authentication to webservice using jQuery?

Go To StackoverFlow.com

33

I'm using jQuery to call a .Net web service like this:

var service_url = "https://example.com/myservice.asmx"
$.ajax({
    type: "GET",
    url: service_url,
    dataType: "xml",
    data: "ParamId=" + FormId.value,
    processData: false,
    error: function(XMLHttpRequest, textStatus, errorThrown) { ajaxError(XMLHttpRequest, textStatus, errorThrown); },
    success: function(xml) { DoSomething(xml); }
});

Now I want to wrap "https://example.com/myservice.asmx" in Windows Authentication. How can I pass credentials to the service using jQuery/javascript?

Ideally I'd like to use the current user's credentials but if needed I can use 1 master credential for all service calls.

2009-06-16 15:17
by brendan


10

It seems that you need to set the request header with the base64 auth data manually.

The instructions are here: http://coderseye.com/2007/how-to-do-http-basic-auth-in-ajax.html

You first need to take the following code from here: http://www.webtoolkit.info/javascript-base64.html to do the base64 encoding

/**
*
*  Base64 encode / decode
*  http://www.webtoolkit.info/
*
**/

var Base64 = {

    // private property
    _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

    // public method for encoding
    encode : function (input) {
        var output = "";
        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        var i = 0;

        input = Base64._utf8_encode(input);

        while (i < input.length) {

            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }

            output = output +
            this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
            this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

        }

        return output;
    },

    // public method for decoding
    decode : function (input) {
        var output = "";
        var chr1, chr2, chr3;
        var enc1, enc2, enc3, enc4;
        var i = 0;

        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

        while (i < input.length) {

            enc1 = this._keyStr.indexOf(input.charAt(i++));
            enc2 = this._keyStr.indexOf(input.charAt(i++));
            enc3 = this._keyStr.indexOf(input.charAt(i++));
            enc4 = this._keyStr.indexOf(input.charAt(i++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;

            output = output + String.fromCharCode(chr1);

            if (enc3 != 64) {
                output = output + String.fromCharCode(chr2);
            }
            if (enc4 != 64) {
                output = output + String.fromCharCode(chr3);
            }

        }

        output = Base64._utf8_decode(output);

        return output;

    },

    // private method for UTF-8 encoding
    _utf8_encode : function (string) {
        string = string.replace(/\r\n/g,"\n");
        var utftext = "";

        for (var n = 0; n < string.length; n++) {

            var c = string.charCodeAt(n);

            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        }

        return utftext;
    },

    // private method for UTF-8 decoding
    _utf8_decode : function (utftext) {
        var string = "";
        var i = 0;
        var c = c1 = c2 = 0;

        while ( i < utftext.length ) {

            c = utftext.charCodeAt(i);

            if (c < 128) {
                string += String.fromCharCode(c);
                i++;
            }
            else if((c > 191) && (c < 224)) {
                c2 = utftext.charCodeAt(i+1);
                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                i += 2;
            }
            else {
                c2 = utftext.charCodeAt(i+1);
                c3 = utftext.charCodeAt(i+2);
                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                i += 3;
            }

        }

        return string;
    }

}

Then you'll need the code to construct the auth data, it's just a base64 of the user and password:

function make_base_auth(user, password) {
  var tok = user + ':' + password;
  var hash = Base64.encode(tok);
  return "Basic " + hash;
}

And then you just add the header with jQuery before making the request:

var service_url = "https://example.com/myservice.asmx"
$.ajax({
    type: "GET",
    url: service_url,
    dataType: "xml",
    data: "ParamId=" + FormId.value,
    processData: false,
    beforeSend : function(req) {
         req.setRequestHeader('Authorization', 
               make_base_auth ('USERNAME', 'PASSWORD'));
    },
    error: function(XMLHttpRequest, textStatus, errorThrown) {   
         ajaxError(XMLHttpRequest, textStatus, errorThrown); 
    },
    success: function(xml) { DoSomething(xml); }
});
2009-06-16 15:29
by albertein
this is basic authentication - aF. 2011-10-28 12:31
this didn't work for me !! , to authenticate with windows authenticatio - Mahmoud Farahat 2012-09-10 09:06
if i encrypt userid & pwd with base64 encrypt then i guess i need to write extrac code at service end to decrypt the data? am i right - Thomas 2014-05-11 20:33
@Thomas : it is also not working for me. have you found any solution - Khurshid Ansari 2018-08-26 06:48


75

I think nowadays you can just set the withCredentials property of the request object to true, e.g.:

$.ajax({
    type: "GET",
    url: service_url,
    dataType: "xml",
    data: "ParamId=" + FormId.value,
    processData: false,
    xhrFields: {
        withCredentials: true
    },
    error: function(XMLHttpRequest, textStatus, errorThrown) { ajaxError(XMLHttpRequest, textStatus, errorThrown); },
    success: function(xml) { DoSomething(xml); }
});

That causes existing authentication headers/cookies to be passed along in the AJAX request, works for me. No need to do your own Base encoding, etc.

2011-11-18 23:07
by Maxy-B
does this work on internet explorer ? - Mahmoud Farahat 2013-03-03 15:52
You don't say what version of IE, but this is just using the jquery API, so in theory it should work on every version of IE that jquery supports. Try it and see - Maxy-B 2013-03-04 20:51
great, works perfectly for me (NTLM authentication - Trapias 2013-05-17 09:49
How can I Send json? - Atish Dipongkor 2013-11-23 18:34
where did u pass user name & password? if some one need to pass explicitly userid & password then how withCredentials can help - Thomas 2014-05-11 20:32
worked for me . thank you ! - David 2015-06-17 16:37
if you stumble upon this thread and are using isomorphic-fetch for async redux, use credentials: 'include'Mike Casas 2016-08-10 21:18
@Thomas The question asked for Windows Authentication which are the credentials of the caller implicitly passed. Not explicit. So the question was how to NOT explicitly pass credentials - Shiv 2016-09-14 05:08
Hi, I tried this to call a webapi but it pops up with username password request window. both websites (requester and web api) are enabled windows authentication. It requested credential to lunch the website then why it requests again when calling the api - Afshin 2017-11-29 00:35
@Afshin in which browser? Not all browsers can automatically retrieve the Kerberos token. Firefox in particular does not support this, and so falls back to NTLM, and asks the user for credentials in order to generate the token - ADyson 2018-06-22 14:52
this should be the accepted answer IMH - ADyson 2018-06-22 14:53
@ADyson, I've tried on Chrome, Firefox and IE. neither can send the credentials in cross-domain requests - Afshin 2018-07-20 04:48
@Afshin I use code almost identical to this all the time and it works fine. When you say "neither can send the credentials", you mean it asks for username and password in a prompt? That's not the same as being unable to send the credentials - it just means it doesn't have any credentials which it can use automatically, and has to ask the user for them before it can send them. I assume that once you enter the right username and password, it works correctly? One reason it might prompt for credentials is that the computer where the browser is running is not on the same NT domain as the server - ADyson 2018-07-20 09:33
@ADyson both UI and API are on the same server, same domain, same Authentication settings on IIS (windows authentication enabled only). what happens is when user browses the UI a credential is requested by the browser, after user enters them scripts and page content load. at this point ajax requests to the API website is made by the scripts to load content. now another credential window pops up for the user to enter - Afshin 2018-08-02 01:27
@Afshin Whether the UI and API are on the same server doesn't matter if the client is not on the domain. What I actually asked was where the client (the machine running the browser) is located - is it part of the same Active Directory domain as the server? Is it currently running on the same LAN and not trying to access the server from the public internet? This is all occurring before we even get to the question of cross domain (note this means domain in a different sense) Ajax requests, since you mention that the dialog box occurs even when loading the U - ADyson 2018-08-02 06:04
@ADyson sorry, yes both client and server machines running on the same AD domain - Afshin 2018-08-05 23:35
Ads