'How can I pass windows authentication to webservice using jQuery?

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.



Solution 1:[1]

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); }
});

Solution 2:[2]

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.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Cœur
Solution 2 Nathan Phillips