vue-msal
Version:
Vue plugin for using Microsoft Authentication Library (MSAL)
597 lines • 27.9 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var lodash_1 = __importDefault(require("lodash"));
var axios_1 = __importDefault(require("axios"));
var UserAgentApplicationExtended_1 = require("./UserAgentApplicationExtended");
var MSAL = /** @class */ (function () {
function MSAL(options) {
var _this = this;
this.options = options;
this.tokenExpirationTimers = {};
this.data = {
isAuthenticated: false,
accessToken: '',
idToken: '',
user: {},
graph: {},
custom: {}
};
this.callbackQueue = [];
this.auth = {
clientId: '',
authority: '',
tenantId: 'common',
tenantName: 'login.microsoftonline.com',
validateAuthority: true,
redirectUri: window.location.href,
postLogoutRedirectUri: window.location.href,
navigateToLoginRequestUrl: true,
requireAuthOnInitialize: false,
autoRefreshToken: true,
onAuthentication: function (error, response) { },
onToken: function (error, response) { },
beforeSignOut: function () { }
};
this.cache = {
cacheLocation: 'localStorage',
storeAuthStateInCookie: true
};
this.request = {
scopes: ["user.read"]
};
this.graph = {
callAfterInit: false,
endpoints: { profile: '/me' },
baseUrl: 'https://graph.microsoft.com/v1.0',
onResponse: function (response) { }
};
if (!options.auth.clientId) {
throw new Error('auth.clientId is required');
}
this.auth = Object.assign(this.auth, options.auth);
this.cache = Object.assign(this.cache, options.cache);
this.request = Object.assign(this.request, options.request);
this.graph = Object.assign(this.graph, options.graph);
this.lib = new UserAgentApplicationExtended_1.UserAgentApplicationExtended({
auth: {
clientId: this.auth.clientId,
authority: this.auth.authority || "https://" + this.auth.tenantName + "/" + this.auth.tenantId,
validateAuthority: this.auth.validateAuthority,
redirectUri: this.auth.redirectUri,
postLogoutRedirectUri: this.auth.postLogoutRedirectUri,
navigateToLoginRequestUrl: this.auth.navigateToLoginRequestUrl
},
cache: this.cache,
system: options.system
});
this.getSavedCallbacks();
this.executeCallbacks();
// Register Callbacks for redirect flow
this.lib.handleRedirectCallback(function (error, response) {
if (!_this.isAuthenticated()) {
_this.saveCallback('auth.onAuthentication', error, response);
}
else {
_this.acquireToken();
}
});
if (this.auth.requireAuthOnInitialize) {
this.signIn();
}
this.data.isAuthenticated = this.isAuthenticated();
if (this.data.isAuthenticated) {
this.data.user = this.lib.getAccount();
this.acquireToken().then(function () {
if (_this.graph.callAfterInit) {
_this.initialMSGraphCall();
}
});
}
this.getStoredCustomData();
}
MSAL.prototype.signIn = function () {
if (!this.lib.isCallback(window.location.hash) && !this.lib.getAccount()) {
// request can be used for login or token request, however in more complex situations this can have diverging options
this.lib.loginRedirect(this.request);
}
};
MSAL.prototype.signOut = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!this.options.auth.beforeSignOut) return [3 /*break*/, 2];
return [4 /*yield*/, this.options.auth.beforeSignOut(this)];
case 1:
_a.sent();
_a.label = 2;
case 2:
this.lib.logout();
return [2 /*return*/];
}
});
});
};
MSAL.prototype.isAuthenticated = function () {
return !this.lib.isCallback(window.location.hash) && !!this.lib.getAccount();
};
MSAL.prototype.acquireToken = function (request, retries) {
if (request === void 0) { request = this.request; }
if (retries === void 0) { retries = 0; }
return __awaiter(this, void 0, void 0, function () {
var response, error_1;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 2, , 6]);
return [4 /*yield*/, this.lib.acquireTokenSilent(request)];
case 1:
response = _a.sent();
this.handleTokenResponse(null, response);
return [2 /*return*/, response];
case 2:
error_1 = _a.sent();
if (!this.requiresInteraction(error_1.errorCode)) return [3 /*break*/, 3];
this.lib.acquireTokenRedirect(request);
return [3 /*break*/, 5];
case 3:
if (!(retries > 0)) return [3 /*break*/, 5];
return [4 /*yield*/, new Promise(function (resolve) {
setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
var res;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.acquireToken(request, retries - 1)];
case 1:
res = _a.sent();
resolve(res);
return [2 /*return*/];
}
});
}); }, 60 * 1000);
})];
case 4: return [2 /*return*/, _a.sent()];
case 5: return [2 /*return*/, false];
case 6: return [2 /*return*/];
}
});
});
};
MSAL.prototype.handleTokenResponse = function (error, response) {
if (error) {
this.saveCallback('auth.onToken', error, null);
return;
}
var setCallback = false;
if (response.tokenType === 'access_token' && this.data.accessToken !== response.accessToken) {
this.setToken('accessToken', response.accessToken, response.expiresOn, response.scopes);
setCallback = true;
}
if (this.data.idToken !== response.idToken.rawIdToken) {
this.setToken('idToken', response.idToken.rawIdToken, new Date(response.idToken.expiration * 1000), [this.auth.clientId]);
setCallback = true;
}
if (setCallback) {
this.saveCallback('auth.onToken', null, response);
}
};
MSAL.prototype.setToken = function (tokenType, token, expiresOn, scopes) {
var _this = this;
var expirationOffset = this.lib.config.system.tokenRenewalOffsetSeconds * 1000;
var expiration = expiresOn.getTime() - (new Date()).getTime() - expirationOffset;
if (expiration >= 0) {
this.data[tokenType] = token;
}
if (this.tokenExpirationTimers[tokenType])
clearTimeout(this.tokenExpirationTimers[tokenType]);
this.tokenExpirationTimers[tokenType] = window.setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!this.auth.autoRefreshToken) return [3 /*break*/, 2];
return [4 /*yield*/, this.acquireToken({ scopes: scopes }, 3)];
case 1:
_a.sent();
return [3 /*break*/, 3];
case 2:
this.data[tokenType] = '';
_a.label = 3;
case 3: return [2 /*return*/];
}
});
}); }, expiration);
};
MSAL.prototype.requiresInteraction = function (errorCode) {
if (!errorCode || !errorCode.length) {
return false;
}
return errorCode === "consent_required" ||
errorCode === "interaction_required" ||
errorCode === "login_required";
};
// MS GRAPH
MSAL.prototype.initialMSGraphCall = function () {
return __awaiter(this, void 0, void 0, function () {
var callback, initEndpoints, resultsObj_1, forcedIds, endpoints, id, storedIds, storedData, _a, singleRequests, batchRequests_1, singlePromises, batchPromises, mixedResults, resultsToSave_1, error_2;
var _this = this;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
callback = this.graph.onResponse;
initEndpoints = this.graph.endpoints;
if (!(typeof initEndpoints === 'object' && !lodash_1.default.isEmpty(initEndpoints))) return [3 /*break*/, 5];
resultsObj_1 = {};
forcedIds = [];
_b.label = 1;
case 1:
_b.trys.push([1, 3, , 4]);
endpoints = {};
for (id in initEndpoints) {
endpoints[id] = this.getEndpointObject(initEndpoints[id]);
if (endpoints[id].force) {
forcedIds.push(id);
}
}
storedIds = [];
storedData = this.lib.store.getItem("msal.msgraph-" + this.data.accessToken);
if (storedData) {
storedData = JSON.parse(storedData);
storedIds = Object.keys(storedData);
Object.assign(resultsObj_1, storedData);
}
_a = this.categorizeRequests(endpoints, lodash_1.default.difference(storedIds, forcedIds)), singleRequests = _a.singleRequests, batchRequests_1 = _a.batchRequests;
singlePromises = singleRequests.map(function (endpoint) { return __awaiter(_this, void 0, void 0, function () {
var res, _a, _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
res = {};
_a = res;
_b = endpoint.id;
return [4 /*yield*/, this.msGraph(endpoint)];
case 1:
_a[_b] = _c.sent();
return [2 /*return*/, res];
}
});
}); });
batchPromises = Object.keys(batchRequests_1).map(function (key) {
var batchUrl = (key === 'default') ? undefined : key;
return _this.msGraph(batchRequests_1[key], batchUrl);
});
return [4 /*yield*/, Promise.all(__spreadArrays(singlePromises, batchPromises))];
case 2:
mixedResults = _b.sent();
mixedResults.map(function (res) {
for (var key in res) {
res[key] = res[key].body;
}
Object.assign(resultsObj_1, res);
});
resultsToSave_1 = __assign({}, resultsObj_1);
forcedIds.map(function (id) { return delete resultsToSave_1[id]; });
this.lib.store.setItem("msal.msgraph-" + this.data.accessToken, JSON.stringify(resultsToSave_1));
this.data.graph = resultsObj_1;
return [3 /*break*/, 4];
case 3:
error_2 = _b.sent();
console.error(error_2);
return [3 /*break*/, 4];
case 4:
if (callback)
this.saveCallback('graph.onResponse', this.data.graph);
_b.label = 5;
case 5: return [2 /*return*/];
}
});
});
};
MSAL.prototype.msGraph = function (endpoints, batchUrl) {
if (batchUrl === void 0) { batchUrl = undefined; }
return __awaiter(this, void 0, void 0, function () {
var error_3;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 5, , 6]);
if (!Array.isArray(endpoints)) return [3 /*break*/, 2];
return [4 /*yield*/, this.executeBatchRequest(endpoints, batchUrl)];
case 1: return [2 /*return*/, _a.sent()];
case 2: return [4 /*yield*/, this.executeSingleRequest(endpoints)];
case 3: return [2 /*return*/, _a.sent()];
case 4: return [3 /*break*/, 6];
case 5:
error_3 = _a.sent();
throw error_3;
case 6: return [2 /*return*/];
}
});
});
};
MSAL.prototype.executeBatchRequest = function (endpoints, batchUrl) {
if (batchUrl === void 0) { batchUrl = this.graph.baseUrl; }
return __awaiter(this, void 0, void 0, function () {
var requests, data, result, keys, numKeys;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
requests = endpoints.map(function (endpoint, index) { return _this.createRequest(endpoint, index); });
return [4 /*yield*/, axios_1.default.request({
url: batchUrl + "/$batch",
method: 'POST',
data: { requests: requests },
headers: { Authorization: "Bearer " + this.data.accessToken },
responseType: 'json'
})];
case 1:
data = (_a.sent()).data;
result = {};
data.responses.map(function (response) {
var key = response.id;
delete response.id;
return result[key] = response;
});
keys = Object.keys(result);
numKeys = keys.sort().filter(function (key, index) {
if (key.search('defaultID-') === 0) {
key = key.replace('defaultID-', '');
}
return parseInt(key) === index;
});
if (numKeys.length === keys.length) {
result = lodash_1.default.values(result);
}
return [2 /*return*/, result];
}
});
});
};
MSAL.prototype.executeSingleRequest = function (endpoint) {
return __awaiter(this, void 0, void 0, function () {
var request, res;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
request = this.createRequest(endpoint);
if (request.url.search('http') !== 0) {
request.url = this.graph.baseUrl + request.url;
}
return [4 /*yield*/, axios_1.default.request(lodash_1.default.defaultsDeep(request, {
url: request.url,
method: request.method,
responseType: 'json',
headers: { Authorization: "Bearer " + this.data.accessToken }
}))];
case 1:
res = _a.sent();
return [2 /*return*/, {
status: res.status,
headers: res.headers,
body: res.data
}];
}
});
});
};
MSAL.prototype.createRequest = function (endpoint, index) {
if (index === void 0) { index = 0; }
var request = {
url: '',
method: 'GET',
id: "defaultID-" + index
};
endpoint = this.getEndpointObject(endpoint);
if (endpoint.url) {
Object.assign(request, endpoint);
}
else {
throw ({ error: 'invalid endpoint', endpoint: endpoint });
}
return request;
};
MSAL.prototype.categorizeRequests = function (endpoints, excludeIds) {
var res = {
singleRequests: [],
batchRequests: {}
};
for (var key in endpoints) {
var endpoint = __assign({ id: key }, endpoints[key]);
if (!lodash_1.default.includes(excludeIds, key)) {
if (endpoint.batchUrl) {
var batchUrl = endpoint.batchUrl;
delete endpoint.batchUrl;
if (!res.batchRequests.hasOwnProperty(batchUrl)) {
res.batchRequests[batchUrl] = [];
}
res.batchRequests[batchUrl].push(endpoint);
}
else {
res.singleRequests.push(endpoint);
}
}
}
return res;
};
MSAL.prototype.getEndpointObject = function (endpoint) {
if (typeof endpoint === "string") {
endpoint = { url: endpoint };
}
if (typeof endpoint === "object" && !endpoint.url) {
throw new Error('invalid endpoint url');
}
return endpoint;
};
// CUSTOM DATA
MSAL.prototype.saveCustomData = function (key, data) {
if (!this.data.custom.hasOwnProperty(key)) {
this.data.custom[key] = null;
}
this.data.custom[key] = data;
this.storeCustomData();
};
MSAL.prototype.storeCustomData = function () {
if (!lodash_1.default.isEmpty(this.data.custom)) {
this.lib.store.setItem('msal.custom', JSON.stringify(this.data.custom));
}
else {
this.lib.store.removeItem('msal.custom');
}
};
MSAL.prototype.getStoredCustomData = function () {
var customData = {};
var customDataStr = this.lib.store.getItem('msal.custom');
if (customDataStr) {
customData = JSON.parse(customDataStr);
}
this.data.custom = customData;
};
// CALLBACKS
MSAL.prototype.saveCallback = function (callbackPath) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
if (lodash_1.default.get(this.options, callbackPath)) {
var callbackQueueObject_1 = {
id: lodash_1.default.uniqueId("cb-" + callbackPath),
callback: callbackPath,
arguments: args
};
lodash_1.default.remove(this.callbackQueue, function (obj) { return obj.id === callbackQueueObject_1.id; });
this.callbackQueue.push(callbackQueueObject_1);
this.storeCallbackQueue();
this.executeCallbacks([callbackQueueObject_1]);
}
};
MSAL.prototype.getSavedCallbacks = function () {
var callbackQueueStr = this.lib.store.getItem('msal.callbackqueue');
if (callbackQueueStr) {
this.callbackQueue = __spreadArrays(this.callbackQueue, JSON.parse(callbackQueueStr));
}
};
MSAL.prototype.executeCallbacks = function (callbacksToExec) {
if (callbacksToExec === void 0) { callbacksToExec = this.callbackQueue; }
return __awaiter(this, void 0, void 0, function () {
var _loop_1, this_1, _a, _b, _i, i;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
if (!callbacksToExec.length) return [3 /*break*/, 4];
_loop_1 = function (i) {
var cb, callback, e_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
cb = callbacksToExec[i];
callback = lodash_1.default.get(this_1.options, cb.callback);
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, callback.apply(void 0, __spreadArrays([this_1], cb.arguments))];
case 2:
_a.sent();
lodash_1.default.remove(this_1.callbackQueue, function (currentCb) {
return cb.id === currentCb.id;
});
this_1.storeCallbackQueue();
return [3 /*break*/, 4];
case 3:
e_1 = _a.sent();
console.warn("Callback '" + cb.id + "' failed with error: ", e_1.message);
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
}
});
};
this_1 = this;
_a = [];
for (_b in callbacksToExec)
_a.push(_b);
_i = 0;
_c.label = 1;
case 1:
if (!(_i < _a.length)) return [3 /*break*/, 4];
i = _a[_i];
return [5 /*yield**/, _loop_1(i)];
case 2:
_c.sent();
_c.label = 3;
case 3:
_i++;
return [3 /*break*/, 1];
case 4: return [2 /*return*/];
}
});
});
};
MSAL.prototype.storeCallbackQueue = function () {
if (this.callbackQueue.length) {
this.lib.store.setItem('msal.callbackqueue', JSON.stringify(this.callbackQueue));
}
else {
this.lib.store.removeItem('msal.callbackqueue');
}
};
return MSAL;
}());
exports.MSAL = MSAL;
//# sourceMappingURL=main.js.map