@azure/identity
Version:
Provides credential implementations for Azure SDK libraries that can authenticate with Microsoft Entra ID
476 lines (475 loc) • 20.6 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var msalClient_exports = {};
__export(msalClient_exports, {
createMsalClient: () => createMsalClient,
generateMsalConfiguration: () => generateMsalConfiguration
});
module.exports = __toCommonJS(msalClient_exports);
var msal = __toESM(require("@azure/msal-node"));
var import_logging = require("../../util/logging.js");
var import_msalPlugins = require("./msalPlugins.js");
var import_utils = require("../utils.js");
var import_errors = require("../../errors.js");
var import_identityClient = require("../../client/identityClient.js");
var import_regionalAuthority = require("../../regionalAuthority.js");
var import_logger = require("@azure/logger");
var import_tenantIdUtils = require("../../util/tenantIdUtils.js");
const msalLogger = (0, import_logging.credentialLogger)("MsalClient");
function generateMsalConfiguration(clientId, tenantId, msalClientOptions = {}) {
const resolvedTenant = (0, import_tenantIdUtils.resolveTenantId)(
msalClientOptions.logger ?? msalLogger,
tenantId,
clientId
);
const authority = (0, import_utils.getAuthority)(resolvedTenant, (0, import_utils.getAuthorityHost)(msalClientOptions));
const httpClient = new import_identityClient.IdentityClient({
...msalClientOptions.tokenCredentialOptions,
authorityHost: authority,
loggingOptions: msalClientOptions.loggingOptions
});
const msalConfig = {
auth: {
clientId,
authority,
knownAuthorities: (0, import_utils.getKnownAuthorities)(
resolvedTenant,
authority,
msalClientOptions.disableInstanceDiscovery
)
},
system: {
networkClient: httpClient,
loggerOptions: {
loggerCallback: (0, import_utils.defaultLoggerCallback)(msalClientOptions.logger ?? msalLogger),
logLevel: (0, import_utils.getMSALLogLevel)((0, import_logger.getLogLevel)()),
piiLoggingEnabled: msalClientOptions.loggingOptions?.enableUnsafeSupportLogging
}
}
};
return msalConfig;
}
function createMsalClient(clientId, tenantId, createMsalClientOptions = {}) {
const state = {
msalConfig: generateMsalConfiguration(clientId, tenantId, createMsalClientOptions),
cachedAccount: createMsalClientOptions.authenticationRecord ? (0, import_utils.publicToMsal)(createMsalClientOptions.authenticationRecord) : null,
pluginConfiguration: import_msalPlugins.msalPlugins.generatePluginConfiguration(createMsalClientOptions),
logger: createMsalClientOptions.logger ?? msalLogger
};
const publicApps = /* @__PURE__ */ new Map();
async function getPublicApp(options = {}) {
const appKey = options.enableCae ? "CAE" : "default";
let publicClientApp = publicApps.get(appKey);
if (publicClientApp) {
state.logger.getToken.info("Existing PublicClientApplication found in cache, returning it.");
return publicClientApp;
}
state.logger.getToken.info(
`Creating new PublicClientApplication with CAE ${options.enableCae ? "enabled" : "disabled"}.`
);
const cachePlugin = options.enableCae ? state.pluginConfiguration.cache.cachePluginCae : state.pluginConfiguration.cache.cachePlugin;
state.msalConfig.auth.clientCapabilities = options.enableCae ? ["cp1"] : void 0;
publicClientApp = new msal.PublicClientApplication({
...state.msalConfig,
broker: { nativeBrokerPlugin: state.pluginConfiguration.broker.nativeBrokerPlugin },
cache: { cachePlugin: await cachePlugin }
});
publicApps.set(appKey, publicClientApp);
return publicClientApp;
}
const confidentialApps = /* @__PURE__ */ new Map();
async function getConfidentialApp(options = {}) {
const appKey = options.enableCae ? "CAE" : "default";
let confidentialClientApp = confidentialApps.get(appKey);
if (confidentialClientApp) {
state.logger.getToken.info(
"Existing ConfidentialClientApplication found in cache, returning it."
);
return confidentialClientApp;
}
state.logger.getToken.info(
`Creating new ConfidentialClientApplication with CAE ${options.enableCae ? "enabled" : "disabled"}.`
);
const cachePlugin = options.enableCae ? state.pluginConfiguration.cache.cachePluginCae : state.pluginConfiguration.cache.cachePlugin;
state.msalConfig.auth.clientCapabilities = options.enableCae ? ["cp1"] : void 0;
confidentialClientApp = new msal.ConfidentialClientApplication({
...state.msalConfig,
broker: { nativeBrokerPlugin: state.pluginConfiguration.broker.nativeBrokerPlugin },
cache: { cachePlugin: await cachePlugin }
});
confidentialApps.set(appKey, confidentialClientApp);
return confidentialClientApp;
}
async function getTokenSilent(app, scopes, options = {}) {
if (state.cachedAccount === null) {
state.logger.getToken.info("No cached account found in local state.");
throw new import_errors.AuthenticationRequiredError({ scopes });
}
if (options.claims) {
state.cachedClaims = options.claims;
}
const silentRequest = {
account: state.cachedAccount,
scopes,
claims: state.cachedClaims
};
if (state.pluginConfiguration.broker.isEnabled) {
silentRequest.extraQueryParameters ||= {};
if (state.pluginConfiguration.broker.enableMsaPassthrough) {
silentRequest.extraQueryParameters["msal_request_type"] = "consumer_passthrough";
}
}
if (options.proofOfPossessionOptions) {
silentRequest.shrNonce = options.proofOfPossessionOptions.nonce;
silentRequest.authenticationScheme = "pop";
silentRequest.resourceRequestMethod = options.proofOfPossessionOptions.resourceRequestMethod;
silentRequest.resourceRequestUri = options.proofOfPossessionOptions.resourceRequestUrl;
}
state.logger.getToken.info("Attempting to acquire token silently");
try {
return await app.acquireTokenSilent(silentRequest);
} catch (err) {
throw (0, import_utils.handleMsalError)(scopes, err, options);
}
}
function calculateRequestAuthority(options) {
if (options?.tenantId) {
return (0, import_utils.getAuthority)(options.tenantId, (0, import_utils.getAuthorityHost)(createMsalClientOptions));
}
return state.msalConfig.auth.authority;
}
async function withSilentAuthentication(msalApp, scopes, options, onAuthenticationRequired) {
let response = null;
try {
response = await getTokenSilent(msalApp, scopes, options);
} catch (e) {
if (e.name !== "AuthenticationRequiredError") {
throw e;
}
if (options.disableAutomaticAuthentication) {
throw new import_errors.AuthenticationRequiredError({
scopes,
getTokenOptions: options,
message: "Automatic authentication has been disabled. You may call the authentication() method."
});
}
}
if (response === null) {
try {
response = await onAuthenticationRequired();
} catch (err) {
throw (0, import_utils.handleMsalError)(scopes, err, options);
}
}
(0, import_utils.ensureValidMsalToken)(scopes, response, options);
state.cachedAccount = response?.account ?? null;
state.logger.getToken.info((0, import_logging.formatSuccess)(scopes));
return {
token: response.accessToken,
expiresOnTimestamp: response.expiresOn.getTime(),
refreshAfterTimestamp: response.refreshOn?.getTime(),
tokenType: response.tokenType
};
}
async function getTokenByClientSecret(scopes, clientSecret, options = {}) {
state.logger.getToken.info(`Attempting to acquire token using client secret`);
state.msalConfig.auth.clientSecret = clientSecret;
const msalApp = await getConfidentialApp(options);
try {
const response = await msalApp.acquireTokenByClientCredential({
scopes,
authority: calculateRequestAuthority(options),
azureRegion: (0, import_regionalAuthority.calculateRegionalAuthority)(),
claims: options?.claims
});
(0, import_utils.ensureValidMsalToken)(scopes, response, options);
state.logger.getToken.info((0, import_logging.formatSuccess)(scopes));
return {
token: response.accessToken,
expiresOnTimestamp: response.expiresOn.getTime(),
refreshAfterTimestamp: response.refreshOn?.getTime(),
tokenType: response.tokenType
};
} catch (err) {
throw (0, import_utils.handleMsalError)(scopes, err, options);
}
}
async function getTokenByClientAssertion(scopes, clientAssertion, options = {}) {
state.logger.getToken.info(`Attempting to acquire token using client assertion`);
state.msalConfig.auth.clientAssertion = clientAssertion;
const msalApp = await getConfidentialApp(options);
try {
const response = await msalApp.acquireTokenByClientCredential({
scopes,
authority: calculateRequestAuthority(options),
azureRegion: (0, import_regionalAuthority.calculateRegionalAuthority)(),
claims: options?.claims,
clientAssertion
});
(0, import_utils.ensureValidMsalToken)(scopes, response, options);
state.logger.getToken.info((0, import_logging.formatSuccess)(scopes));
return {
token: response.accessToken,
expiresOnTimestamp: response.expiresOn.getTime(),
refreshAfterTimestamp: response.refreshOn?.getTime(),
tokenType: response.tokenType
};
} catch (err) {
throw (0, import_utils.handleMsalError)(scopes, err, options);
}
}
async function getTokenByClientCertificate(scopes, certificate, options = {}) {
state.logger.getToken.info(`Attempting to acquire token using client certificate`);
state.msalConfig.auth.clientCertificate = certificate;
const msalApp = await getConfidentialApp(options);
try {
const response = await msalApp.acquireTokenByClientCredential({
scopes,
authority: calculateRequestAuthority(options),
azureRegion: (0, import_regionalAuthority.calculateRegionalAuthority)(),
claims: options?.claims
});
(0, import_utils.ensureValidMsalToken)(scopes, response, options);
state.logger.getToken.info((0, import_logging.formatSuccess)(scopes));
return {
token: response.accessToken,
expiresOnTimestamp: response.expiresOn.getTime(),
refreshAfterTimestamp: response.refreshOn?.getTime(),
tokenType: response.tokenType
};
} catch (err) {
throw (0, import_utils.handleMsalError)(scopes, err, options);
}
}
async function getTokenByDeviceCode(scopes, deviceCodeCallback, options = {}) {
state.logger.getToken.info(`Attempting to acquire token using device code`);
const msalApp = await getPublicApp(options);
return withSilentAuthentication(msalApp, scopes, options, () => {
const requestOptions = {
scopes,
cancel: options?.abortSignal?.aborted ?? false,
deviceCodeCallback,
authority: calculateRequestAuthority(options),
claims: options?.claims
};
const deviceCodeRequest = msalApp.acquireTokenByDeviceCode(requestOptions);
if (options.abortSignal) {
options.abortSignal.addEventListener("abort", () => {
requestOptions.cancel = true;
});
}
return deviceCodeRequest;
});
}
async function getTokenByUsernamePassword(scopes, username, password, options = {}) {
state.logger.getToken.info(`Attempting to acquire token using username and password`);
const msalApp = await getPublicApp(options);
return withSilentAuthentication(msalApp, scopes, options, () => {
const requestOptions = {
scopes,
username,
password,
authority: calculateRequestAuthority(options),
claims: options?.claims
};
return msalApp.acquireTokenByUsernamePassword(requestOptions);
});
}
function getActiveAccount() {
if (!state.cachedAccount) {
return void 0;
}
return (0, import_utils.msalToPublic)(clientId, state.cachedAccount);
}
async function getTokenByAuthorizationCode(scopes, redirectUri, authorizationCode, clientSecret, options = {}) {
state.logger.getToken.info(`Attempting to acquire token using authorization code`);
let msalApp;
if (clientSecret) {
state.msalConfig.auth.clientSecret = clientSecret;
msalApp = await getConfidentialApp(options);
} else {
msalApp = await getPublicApp(options);
}
return withSilentAuthentication(msalApp, scopes, options, () => {
return msalApp.acquireTokenByCode({
scopes,
redirectUri,
code: authorizationCode,
authority: calculateRequestAuthority(options),
claims: options?.claims
});
});
}
async function getTokenOnBehalfOf(scopes, userAssertionToken, clientCredentials, options = {}) {
msalLogger.getToken.info(`Attempting to acquire token on behalf of another user`);
if (typeof clientCredentials === "string") {
msalLogger.getToken.info(`Using client secret for on behalf of flow`);
state.msalConfig.auth.clientSecret = clientCredentials;
} else if (typeof clientCredentials === "function") {
msalLogger.getToken.info(`Using client assertion callback for on behalf of flow`);
state.msalConfig.auth.clientAssertion = clientCredentials;
} else {
msalLogger.getToken.info(`Using client certificate for on behalf of flow`);
state.msalConfig.auth.clientCertificate = clientCredentials;
}
const msalApp = await getConfidentialApp(options);
try {
const response = await msalApp.acquireTokenOnBehalfOf({
scopes,
authority: calculateRequestAuthority(options),
claims: options.claims,
oboAssertion: userAssertionToken
});
(0, import_utils.ensureValidMsalToken)(scopes, response, options);
msalLogger.getToken.info((0, import_logging.formatSuccess)(scopes));
return {
token: response.accessToken,
expiresOnTimestamp: response.expiresOn.getTime(),
refreshAfterTimestamp: response.refreshOn?.getTime(),
tokenType: response.tokenType
};
} catch (err) {
throw (0, import_utils.handleMsalError)(scopes, err, options);
}
}
function createBaseInteractiveRequest(scopes, options) {
return {
openBrowser: async (url) => {
const open = await import("open");
await open.default(url, { newInstance: true });
},
scopes,
authority: calculateRequestAuthority(options),
claims: options?.claims,
loginHint: options?.loginHint,
errorTemplate: options?.browserCustomizationOptions?.errorMessage,
successTemplate: options?.browserCustomizationOptions?.successMessage,
prompt: options?.loginHint ? "login" : "select_account"
};
}
async function getBrokeredTokenInternal(scopes, useDefaultBrokerAccount, options = {}) {
msalLogger.verbose("Authentication will resume through the broker");
const app = await getPublicApp(options);
const interactiveRequest = createBaseInteractiveRequest(scopes, options);
if (state.pluginConfiguration.broker.parentWindowHandle) {
interactiveRequest.windowHandle = Buffer.from(
state.pluginConfiguration.broker.parentWindowHandle
);
} else {
msalLogger.warning(
"Parent window handle is not specified for the broker. This may cause unexpected behavior. Please provide the parentWindowHandle."
);
}
if (state.pluginConfiguration.broker.enableMsaPassthrough) {
(interactiveRequest.extraQueryParameters ??= {})["msal_request_type"] = "consumer_passthrough";
}
if (useDefaultBrokerAccount) {
interactiveRequest.prompt = "none";
msalLogger.verbose("Attempting broker authentication using the default broker account");
} else {
msalLogger.verbose("Attempting broker authentication without the default broker account");
}
if (options.proofOfPossessionOptions) {
interactiveRequest.shrNonce = options.proofOfPossessionOptions.nonce;
interactiveRequest.authenticationScheme = "pop";
interactiveRequest.resourceRequestMethod = options.proofOfPossessionOptions.resourceRequestMethod;
interactiveRequest.resourceRequestUri = options.proofOfPossessionOptions.resourceRequestUrl;
}
try {
return await app.acquireTokenInteractive(interactiveRequest);
} catch (e) {
msalLogger.verbose(`Failed to authenticate through the broker: ${e.message}`);
if (options.disableAutomaticAuthentication) {
throw new import_errors.AuthenticationRequiredError({
scopes,
getTokenOptions: options,
message: "Cannot silently authenticate with default broker account."
});
}
if (useDefaultBrokerAccount) {
return getBrokeredTokenInternal(scopes, false, options);
} else {
throw e;
}
}
}
async function getBrokeredToken(scopes, useDefaultBrokerAccount, options = {}) {
msalLogger.getToken.info(
`Attempting to acquire token using brokered authentication with useDefaultBrokerAccount: ${useDefaultBrokerAccount}`
);
const response = await getBrokeredTokenInternal(scopes, useDefaultBrokerAccount, options);
(0, import_utils.ensureValidMsalToken)(scopes, response, options);
state.cachedAccount = response?.account ?? null;
state.logger.getToken.info((0, import_logging.formatSuccess)(scopes));
return {
token: response.accessToken,
expiresOnTimestamp: response.expiresOn.getTime(),
refreshAfterTimestamp: response.refreshOn?.getTime(),
tokenType: response.tokenType
};
}
async function getTokenByInteractiveRequest(scopes, options = {}) {
msalLogger.getToken.info(`Attempting to acquire token interactively`);
const app = await getPublicApp(options);
return withSilentAuthentication(app, scopes, options, async () => {
const interactiveRequest = createBaseInteractiveRequest(scopes, options);
if (state.pluginConfiguration.broker.isEnabled) {
return getBrokeredTokenInternal(
scopes,
state.pluginConfiguration.broker.useDefaultBrokerAccount ?? false,
options
);
}
if (options.proofOfPossessionOptions) {
interactiveRequest.shrNonce = options.proofOfPossessionOptions.nonce;
interactiveRequest.authenticationScheme = "pop";
interactiveRequest.resourceRequestMethod = options.proofOfPossessionOptions.resourceRequestMethod;
interactiveRequest.resourceRequestUri = options.proofOfPossessionOptions.resourceRequestUrl;
}
return app.acquireTokenInteractive(interactiveRequest);
});
}
return {
getActiveAccount,
getBrokeredToken,
getTokenByClientSecret,
getTokenByClientAssertion,
getTokenByClientCertificate,
getTokenByDeviceCode,
getTokenByUsernamePassword,
getTokenByAuthorizationCode,
getTokenOnBehalfOf,
getTokenByInteractiveRequest
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
createMsalClient,
generateMsalConfiguration
});
//# sourceMappingURL=msalClient.js.map