Skip to content

Instantly share code, notes, and snippets.

@phillipharding
Forked from paulryan/adal_lib.js
Created June 20, 2017 13:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save phillipharding/20a455951a7b1a85f060c5a725e4ddd7 to your computer and use it in GitHub Desktop.
Save phillipharding/20a455951a7b1a85f060c5a725e4ddd7 to your computer and use it in GitHub Desktop.
Custom "adal" implementation for OAuth implict flow
var CC = CC || {};
CC.CORE = CC.CORE || {};
CC.CORE.Log = function (errMsg) {
// console.log is undefined in IE10 and earlier unless in debug mode, so must check for it
if (typeof window.console === "object" && typeof console.log === "function") {
console.log(errMsg);
}
};
CC.CORE.Adal = (function () {
"use strict";
var appTokenFactory = function (aadAppClientId, resource) {
// redirectUrl is the URL which the iframe will redirect to once auth occurs.
// we use blank.gif as it is a very low payload
var redirectUrl = _spPageContextInfo.webAbsoluteUrl + "/_layouts/images/blank.gif";
// NOTE on security: include the userId in the cache key to prevent the case where a user logs out but
// leaves the tab open and a new user logs in on the same tab. The first user's calender
// would be returned if we didn't associate the cache key with the current user.
var cacheKey = "candc_cache_adal_" + _spPageContextInfo.userId + "_" + aadAppClientId + "_" + resource;
this.params = {
clientId: aadAppClientId,
redirectUrl: redirectUrl,
resource: resource,
cacheKey: cacheKey
};
var getAuthorizeUri = function (params, redirectUrl) {
var authUri = "https://login.microsoftonline.com/common/oauth2/authorize" +
"?client_id=" + params.clientId +
"&response_type=token" +
"&redirect_uri=" + encodeURIComponent(redirectUrl) +
"&resource=" + encodeURIComponent(params.resource);
return authUri;
};
var getQueryStringParameterByName = function (name, url) {
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&#]" + name + "(=([^&#]*)|&|#|$)");
var results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
};
// create iframe, set its href, set listener for when loaded
// to parse the query string. Deferred returns upon parse of query string in iframe.
var acquirePassiveToken = function (params) {
var deferred = jQuery.Deferred();
// create iframe and inject into dom
var iframe = jQuery("<iframe />").attr({
width: 1,
height: 1,
src: getAuthorizeUri(params, params.redirectUrl)
})
jQuery(document.body).append(iframe);
// bind event handler to iframe for parse query string on load
iframe.on("load", function (iframeData) {
parseAccessTokenFromIframe(iframeData, deferred);
});
return deferred.promise();
};
// handle iframe once it has loaded
var parseAccessTokenFromIframe = function (iframeData, deferred) {
// read the iframe href
var frameHref = "";
try {
// this will throw a cross-domain error for any issue other than success
// as the iframe will diplay the error on the login.microsoft domain
frameHref = iframeData.currentTarget.contentWindow.location.href;
}
catch (error) {
deferred.reject(error);
return;
}
// parse iframe query string parameters
var accessToken = getQueryStringParameterByName("access_token", frameHref);
var expiresInSeconds = getQueryStringParameterByName("expires_in", frameHref);
// delete the iframe, and event handler.
var iframe = jQuery(iframeData.currentTarget);
iframe.remove();
// resolve promise
deferred.resolve({
accessToken: accessToken,
expiresInSeconds: expiresInSeconds
});
};
// get the most recent token from the cache, or if not available,
// fetch a new token via iframe
var getToken = function (params) {
var deferred = jQuery.Deferred();
// check for cached token
var tokenFromCache = CC.CORE.Cache.Get(params.cacheKey);
if (!tokenFromCache) {
// fetch token via iframe
acquirePassiveToken(params)
.done(function (tokenFromIframe) {
CC.CORE.Log("ADAL: Fetched token from iframe.");
// expire cache a minute before token expires to be safe
var cacheTimeout = (tokenFromIframe.expiresInSeconds - 60) * 1000;
CC.CORE.Cache.Set(params.cacheKey, tokenFromIframe, cacheTimeout);
// resolve the promise
deferred.resolve(tokenFromIframe);
})
.fail(function (error) {
// Logs when rejection is caught
deferred.reject(error);
});
}
else {
CC.CORE.Log("ADAL: Fetched token from cache.");
// resolve the promise
deferred.resolve(tokenFromCache);
}
return deferred.promise();
};
this.ExecuteQuery = function (query, additionalHeaders) {
var deferred = jQuery.Deferred();
var params = this.params;
// get token from cache or via iframe
getToken(params)
.done(function (token) {
// submit request with token in header
var ajaxHeaders = {
'Authorization': 'Bearer ' + token.accessToken
};
if (typeof additionalHeaders === "object") {
jQuery.extend(ajaxHeaders, additionalHeaders);
}
jQuery.ajax({
type: "GET",
url: params.resource + query,
headers: ajaxHeaders
}).done(function (response) {
deferred.resolve(response);
}).fail(function (error) {
deferred.reject({
error: error
});
});
})
.fail(function (error) {
CC.CORE.Log('ADAL error occurred: ' + error);
deferred.reject({
error: error,
authorizeUrl: getAuthorizeUri(params, window.location.href)
});
});
return deferred.promise();
};
};
return {
AppTokenFactory: appTokenFactory
};
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment