UNPKG

@microsoft/agents-hosting

Version:

Microsoft 365 Agents SDK for JavaScript

215 lines 8.71 kB
"use strict"; /** * 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