@microsoft/agents-hosting
Version:
Microsoft 365 Agents SDK for JavaScript
215 lines • 8.71 kB
JavaScript
;
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MsalTokenProvider = void 0;
const msal_node_1 = require("@azure/msal-node");
const logger_1 = require("@microsoft/agents-activity/logger");
const uuid_1 = require("uuid");
const fs_1 = __importDefault(require("fs"));
const crypto_1 = __importDefault(require("crypto"));
const audience = 'api://AzureADTokenExchange';
const logger = (0, logger_1.debug)('agents:msal');
/**
* Provides tokens using MSAL.
*/
class MsalTokenProvider {
constructor() {
this.sysOptions = {
loggerOptions: {
logLevel: msal_node_1.LogLevel.Trace,
loggerCallback: (level, message, containsPii) => {
if (containsPii) {
return;
}
switch (level) {
case msal_node_1.LogLevel.Error:
logger.error(message);
return;
case msal_node_1.LogLevel.Info:
logger.debug(message);
return;
case msal_node_1.LogLevel.Warning:
if (!message.includes('Warning - No client info in response')) {
logger.warn(message);
}
return;
case msal_node_1.LogLevel.Verbose:
logger.debug(message);
}
},
piiLoggingEnabled: false
}
};
}
/**
* Gets an access token.
* @param authConfig The authentication configuration.
* @param scope The scope for the token.
* @returns A promise that resolves to the access token.
*/
async getAccessToken(authConfig, scope) {
if (!authConfig.clientId && process.env.NODE_ENV !== 'production') {
return '';
}
let token;
if (authConfig.FICClientId !== undefined) {
token = await this.acquireAccessTokenViaFIC(authConfig, scope);
}
else if (authConfig.clientSecret !== undefined) {
token = await this.acquireAccessTokenViaSecret(authConfig, scope);
}
else if (authConfig.certPemFile !== undefined &&
authConfig.certKeyFile !== undefined) {
token = await this.acquireTokenWithCertificate(authConfig, scope);
}
else if (authConfig.clientSecret === undefined &&
authConfig.certPemFile === undefined &&
authConfig.certKeyFile === undefined) {
token = await this.acquireTokenWithUserAssignedIdentity(authConfig, scope);
}
else {
throw new Error('Invalid authConfig. ');
}
if (token === undefined) {
throw new Error('Failed to acquire token');
}
return token;
}
async acquireTokenOnBehalfOf(authConfig, scopes, oboAssertion) {
const cca = new msal_node_1.ConfidentialClientApplication({
auth: {
clientId: authConfig.clientId,
authority: `${authConfig.authority}/${authConfig.tenantId || 'botframework.com'}`,
clientSecret: authConfig.clientSecret
},
system: this.sysOptions
});
const token = await cca.acquireTokenOnBehalfOf({
oboAssertion,
scopes
});
return token === null || token === void 0 ? void 0 : token.accessToken;
}
/**
* Acquires a token using a user-assigned identity.
* @param authConfig The authentication configuration.
* @param scope The scope for the token.
* @returns A promise that resolves to the access token.
*/
async acquireTokenWithUserAssignedIdentity(authConfig, scope) {
const mia = new msal_node_1.ManagedIdentityApplication({
managedIdentityIdParams: {
userAssignedClientId: authConfig.clientId || ''
},
system: this.sysOptions
});
const token = await mia.acquireToken({
resource: scope
});
return token === null || token === void 0 ? void 0 : token.accessToken;
}
/**
* Acquires a token using a certificate.
* @param authConfig The authentication configuration.
* @param scope The scope for the token.
* @returns A promise that resolves to the access token.
*/
async acquireTokenWithCertificate(authConfig, scope) {
const privateKeySource = fs_1.default.readFileSync(authConfig.certKeyFile);
const privateKeyObject = crypto_1.default.createPrivateKey({
key: privateKeySource,
format: 'pem'
});
const privateKey = privateKeyObject.export({
format: 'pem',
type: 'pkcs8'
});
const pubKeyObject = new crypto_1.default.X509Certificate(fs_1.default.readFileSync(authConfig.certPemFile));
const cca = new msal_node_1.ConfidentialClientApplication({
auth: {
clientId: authConfig.clientId || '',
authority: `${authConfig.authority}/${authConfig.tenantId || 'botframework.com'}`,
clientCertificate: {
privateKey: privateKey,
thumbprint: pubKeyObject.fingerprint.replaceAll(':', ''),
x5c: Buffer.from(authConfig.certPemFile, 'base64').toString()
}
},
system: this.sysOptions
});
const token = await cca.acquireTokenByClientCredential({
scopes: [`${scope}/.default`],
correlationId: (0, uuid_1.v4)()
});
return token === null || token === void 0 ? void 0 : token.accessToken;
}
/**
* Acquires a token using a client secret.
* @param authConfig The authentication configuration.
* @param scope The scope for the token.
* @returns A promise that resolves to the access token.
*/
async acquireAccessTokenViaSecret(authConfig, scope) {
const cca = new msal_node_1.ConfidentialClientApplication({
auth: {
clientId: authConfig.clientId,
authority: `${authConfig.authority}/${authConfig.tenantId || 'botframework.com'}`,
clientSecret: authConfig.clientSecret
},
system: this.sysOptions
});
const token = await cca.acquireTokenByClientCredential({
scopes: [`${scope}/.default`],
correlationId: (0, uuid_1.v4)()
});
return token === null || token === void 0 ? void 0 : token.accessToken;
}
/**
* Acquires a token using a FIC client assertion.
* @param authConfig The authentication configuration.
* @param scope The scope for the token.
* @returns A promise that resolves to the access token.
*/
async acquireAccessTokenViaFIC(authConfig, scope) {
const scopes = [`${scope}/.default`];
const clientAssertion = await this.fetchExternalToken(authConfig.FICClientId);
const cca = new msal_node_1.ConfidentialClientApplication({
auth: {
clientId: authConfig.clientId,
authority: `${authConfig.authority}/${authConfig.tenantId}`,
clientAssertion
},
system: this.sysOptions
});
const token = await cca.acquireTokenByClientCredential({ scopes });
logger.debug('got token using FIC client assertion');
return token === null || token === void 0 ? void 0 : token.accessToken;
}
/**
* Fetches an external token.
* @param FICClientId The FIC client ID.
* @returns A promise that resolves to the external token.
*/
async fetchExternalToken(FICClientId) {
const managedIdentityClientAssertion = new msal_node_1.ManagedIdentityApplication({
managedIdentityIdParams: {
userAssignedClientId: FICClientId
},
system: this.sysOptions
});
const response = await managedIdentityClientAssertion.acquireToken({
resource: audience,
forceRefresh: true
});
logger.debug('got token for FIC');
return response.accessToken;
}
}
exports.MsalTokenProvider = MsalTokenProvider;
//# sourceMappingURL=msalTokenProvider.js.map