Files
2025-03-07 19:22:02 +01:00

116 lines
5.0 KiB
JavaScript

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { AuthenticationRequiredError, CredentialUnavailableError } from "../../errors.js";
import { formatSuccess } from "../../util/logging.js";
import { ensureValidMsalToken, getAuthority, getKnownAuthorities, msalToPublic } from "../utils.js";
import { processMultiTenantRequest, resolveAdditionallyAllowedTenantIds, resolveTenantId, } from "../../util/tenantIdUtils.js";
import { DefaultTenantId } from "../../constants.js";
/**
* Generates a MSAL configuration that generally works for browsers
* @internal
*/
export function defaultBrowserMsalConfig(options) {
const tenantId = options.tenantId || DefaultTenantId;
const authority = getAuthority(tenantId, options.authorityHost);
return {
auth: {
clientId: options.clientId,
authority,
knownAuthorities: getKnownAuthorities(tenantId, authority, options.disableInstanceDiscovery),
// If the users picked redirect as their login style,
// but they didn't provide a redirectUri,
// we can try to use the current page we're in as a default value.
redirectUri: options.redirectUri || self.location.origin,
},
};
}
/**
* MSAL partial base client for the browsers.
*
* It completes the input configuration with some default values.
* It also provides with utility protected methods that can be used from any of the clients,
* which includes handlers for successful responses and errors.
*
* @internal
*/
export class MsalBrowser {
constructor(options) {
var _a;
this.logger = options.logger;
this.loginStyle = options.loginStyle;
if (!options.clientId) {
throw new CredentialUnavailableError("A client ID is required in browsers");
}
this.clientId = options.clientId;
this.additionallyAllowedTenantIds = resolveAdditionallyAllowedTenantIds((_a = options === null || options === void 0 ? void 0 : options.tokenCredentialOptions) === null || _a === void 0 ? void 0 : _a.additionallyAllowedTenants);
this.tenantId = resolveTenantId(this.logger, options.tenantId, options.clientId);
this.authorityHost = options.authorityHost;
this.msalConfig = defaultBrowserMsalConfig(options);
this.disableAutomaticAuthentication = options.disableAutomaticAuthentication;
if (options.authenticationRecord) {
this.account = Object.assign(Object.assign({}, options.authenticationRecord), { tenantId: this.tenantId });
}
}
/**
* In the browsers we don't need to init()
*/
async init() {
// Nothing to do here.
}
/**
* Clears MSAL's cache.
*/
async logout() {
var _a;
(_a = this.app) === null || _a === void 0 ? void 0 : _a.logout();
}
/**
* Attempts to retrieve an authenticated token from MSAL.
*/
async getToken(scopes, options = {}) {
const tenantId = processMultiTenantRequest(this.tenantId, options, this.additionallyAllowedTenantIds) ||
this.tenantId;
if (!options.authority) {
options.authority = getAuthority(tenantId, this.authorityHost);
}
// We ensure that redirection is handled at this point.
await this.handleRedirect();
if (!(await this.getActiveAccount()) && !this.disableAutomaticAuthentication) {
await this.login(scopes);
}
return this.getTokenSilent(scopes).catch((err) => {
if (err.name !== "AuthenticationRequiredError") {
throw err;
}
if (options === null || options === void 0 ? void 0 : options.disableAutomaticAuthentication) {
throw new AuthenticationRequiredError({
scopes,
getTokenOptions: options,
message: "Automatic authentication has been disabled. You may call the authentication() method.",
});
}
this.logger.info(`Silent authentication failed, falling back to interactive method ${this.loginStyle}`);
return this.doGetToken(scopes);
});
}
/**
* Handles the MSAL authentication result.
* If the result has an account, we update the local account reference.
* If the token received is invalid, an error will be thrown depending on what's missing.
*/
handleResult(scopes, result, getTokenOptions) {
var _a;
if (result === null || result === void 0 ? void 0 : result.account) {
this.account = msalToPublic(this.clientId, result.account);
}
ensureValidMsalToken(scopes, result, getTokenOptions);
this.logger.getToken.info(formatSuccess(scopes));
return {
token: result.accessToken,
expiresOnTimestamp: result.expiresOn.getTime(),
refreshAfterTimestamp: (_a = result.refreshOn) === null || _a === void 0 ? void 0 : _a.getTime(),
tokenType: "Bearer",
};
}
}
//# sourceMappingURL=msalBrowserCommon.js.map