From 7a12b149abce1233e2722b473d15ab2bb4888028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Rodr=C3=ADguez?= Date: Mon, 11 Oct 2021 13:57:32 -0400 Subject: [PATCH] [Identity] AuthenticationRequiredError options (#17987) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR comes from the feedback from @xirzec on the API review for the upcoming Identity release. The feedback stated that these optional parameters to AuthenticationRequiredError should be in an options bag, and that the `getTokenOptions` public property in that error class should be optional. This PR: - Moves the optional parameters of AuthenticationRequiredError to an options bag. - And also moves the two errors we expose into the same file, in a more convenient location. Feedback appreciated 🙏 --- sdk/identity/identity/CHANGELOG.md | 2 + sdk/identity/identity/review/identity.api.md | 12 +++-- .../identity/src/client/identityClient.ts | 2 +- .../src/credentials/azureCliCredential.ts | 2 +- .../credentials/azurePowerShellCredential.ts | 2 +- .../src/credentials/chainedTokenCredential.ts | 2 +- .../src/credentials/environmentCredential.ts | 2 +- .../managedIdentityCredential/arcMsi.ts | 2 +- .../managedIdentityCredential/imdsMsi.ts | 2 +- .../managedIdentityCredential/index.ts | 2 +- .../credentials/visualStudioCodeCredential.ts | 2 +- .../identity/src/{client => }/errors.ts | 46 +++++++++++++++++++ sdk/identity/identity/src/index.ts | 23 +++++----- .../src/msal/browserFlows/browserCommon.ts | 14 +++--- .../src/msal/browserFlows/msalAuthCode.ts | 18 ++++++-- sdk/identity/identity/src/msal/errors.ts | 24 ---------- .../src/msal/nodeFlows/msalOpenBrowser.ts | 2 +- .../identity/src/msal/nodeFlows/nodeCommon.ts | 18 +++++--- sdk/identity/identity/src/msal/utils.ts | 11 ++--- .../public/chainedTokenCredential.spec.ts | 9 ++-- 20 files changed, 121 insertions(+), 76 deletions(-) rename sdk/identity/identity/src/{client => }/errors.ts (81%) delete mode 100644 sdk/identity/identity/src/msal/errors.ts diff --git a/sdk/identity/identity/CHANGELOG.md b/sdk/identity/identity/CHANGELOG.md index 4006cdbbd966..ba3c5298ad29 100644 --- a/sdk/identity/identity/CHANGELOG.md +++ b/sdk/identity/identity/CHANGELOG.md @@ -110,6 +110,8 @@ Azure Service Fabric support hasn't been added on the initial version 2 of Ident - Renamed the `ApplicationCredential` to `AzureApplicationCredential`. - Removed the `CredentialPersistenceOptions` from `DefaultAzureCredential` and `EnvironmentCredential`. - Merged the configuration and the options bag on the `OnBehalfOfCredential` into a single options bag. +- `AuthenticationRequiredError` (introduced in 2.0.0-beta.1) now has its parameters into a single options bag. +- `AuthenticationRequiredError` (introduced in 2.0.0-beta.1) now has its parameters in a single options bag, `AuthenticationRequiredErrorOptions`. ### Bugs Fixed diff --git a/sdk/identity/identity/review/identity.api.md b/sdk/identity/identity/review/identity.api.md index 21e176820158..52145796d357 100644 --- a/sdk/identity/identity/review/identity.api.md +++ b/sdk/identity/identity/review/identity.api.md @@ -43,9 +43,15 @@ export interface AuthenticationRecord { // @public export class AuthenticationRequiredError extends Error { constructor( - scopes: string[], - getTokenOptions?: GetTokenOptions, message?: string); - getTokenOptions: GetTokenOptions; + options: AuthenticationRequiredErrorOptions); + getTokenOptions?: GetTokenOptions; + scopes: string[]; +} + +// @public +export interface AuthenticationRequiredErrorOptions { + getTokenOptions?: GetTokenOptions; + message?: string; scopes: string[]; } diff --git a/sdk/identity/identity/src/client/identityClient.ts b/sdk/identity/identity/src/client/identityClient.ts index b71070ff5cc2..9d6428949445 100644 --- a/sdk/identity/identity/src/client/identityClient.ts +++ b/sdk/identity/identity/src/client/identityClient.ts @@ -12,7 +12,7 @@ import { PipelineRequest } from "@azure/core-rest-pipeline"; import { AbortController, AbortSignalLike } from "@azure/abort-controller"; -import { AuthenticationError, AuthenticationErrorName } from "./errors"; +import { AuthenticationError, AuthenticationErrorName } from "../errors"; import { getIdentityTokenEndpointSuffix } from "../util/identityTokenEndpoint"; import { DefaultAuthorityHost } from "../constants"; import { createSpan } from "../util/tracing"; diff --git a/sdk/identity/identity/src/credentials/azureCliCredential.ts b/sdk/identity/identity/src/credentials/azureCliCredential.ts index e0dd2f6a84f6..cf743d0d1332 100644 --- a/sdk/identity/identity/src/credentials/azureCliCredential.ts +++ b/sdk/identity/identity/src/credentials/azureCliCredential.ts @@ -4,7 +4,7 @@ import { TokenCredential, GetTokenOptions, AccessToken } from "@azure/core-auth"; import { createSpan } from "../util/tracing"; -import { CredentialUnavailableError } from "../client/errors"; +import { CredentialUnavailableError } from "../errors"; import { SpanStatusCode } from "@azure/core-tracing"; import { credentialLogger, formatSuccess, formatError } from "../util/logging"; import child_process from "child_process"; diff --git a/sdk/identity/identity/src/credentials/azurePowerShellCredential.ts b/sdk/identity/identity/src/credentials/azurePowerShellCredential.ts index 2e2a5000a184..47eecd8036a0 100644 --- a/sdk/identity/identity/src/credentials/azurePowerShellCredential.ts +++ b/sdk/identity/identity/src/credentials/azurePowerShellCredential.ts @@ -3,7 +3,7 @@ import { TokenCredential, GetTokenOptions, AccessToken } from "@azure/core-auth"; -import { CredentialUnavailableError } from "../client/errors"; +import { CredentialUnavailableError } from "../errors"; import { credentialLogger, formatSuccess, formatError } from "../util/logging"; import { trace } from "../util/tracing"; import { ensureValidScope, getScopeResource } from "../util/scopeUtils"; diff --git a/sdk/identity/identity/src/credentials/chainedTokenCredential.ts b/sdk/identity/identity/src/credentials/chainedTokenCredential.ts index 40cb82058e07..1276318648bd 100644 --- a/sdk/identity/identity/src/credentials/chainedTokenCredential.ts +++ b/sdk/identity/identity/src/credentials/chainedTokenCredential.ts @@ -3,7 +3,7 @@ import { AccessToken, TokenCredential, GetTokenOptions } from "@azure/core-auth"; -import { AggregateAuthenticationError, CredentialUnavailableError } from "../client/errors"; +import { AggregateAuthenticationError, CredentialUnavailableError } from "../errors"; import { createSpan } from "../util/tracing"; import { SpanStatusCode } from "@azure/core-tracing"; import { credentialLogger, formatSuccess, formatError } from "../util/logging"; diff --git a/sdk/identity/identity/src/credentials/environmentCredential.ts b/sdk/identity/identity/src/credentials/environmentCredential.ts index 5b1ca011585b..d5a1c378a64c 100644 --- a/sdk/identity/identity/src/credentials/environmentCredential.ts +++ b/sdk/identity/identity/src/credentials/environmentCredential.ts @@ -6,7 +6,7 @@ import { AccessToken, TokenCredential, GetTokenOptions } from "@azure/core-auth" import { credentialLogger, processEnvVars, formatSuccess, formatError } from "../util/logging"; import { TokenCredentialOptions } from "../client/identityClient"; import { ClientSecretCredential } from "./clientSecretCredential"; -import { AuthenticationError, CredentialUnavailableError } from "../client/errors"; +import { AuthenticationError, CredentialUnavailableError } from "../errors"; import { checkTenantId } from "../util/checkTenantId"; import { trace } from "../util/tracing"; import { ClientCertificateCredential } from "./clientCertificateCredential"; diff --git a/sdk/identity/identity/src/credentials/managedIdentityCredential/arcMsi.ts b/sdk/identity/identity/src/credentials/managedIdentityCredential/arcMsi.ts index 589107ab4cb5..8523e6938fe2 100644 --- a/sdk/identity/identity/src/credentials/managedIdentityCredential/arcMsi.ts +++ b/sdk/identity/identity/src/credentials/managedIdentityCredential/arcMsi.ts @@ -13,7 +13,7 @@ import { credentialLogger } from "../../util/logging"; import { IdentityClient } from "../../client/identityClient"; import { mapScopesToResource, msiGenericGetToken } from "./utils"; import { azureArcAPIVersion } from "./constants"; -import { AuthenticationError } from "../../client/errors"; +import { AuthenticationError } from "../../errors"; const msiName = "ManagedIdentityCredential - Azure Arc MSI"; const logger = credentialLogger(msiName); diff --git a/sdk/identity/identity/src/credentials/managedIdentityCredential/imdsMsi.ts b/sdk/identity/identity/src/credentials/managedIdentityCredential/imdsMsi.ts index cd94e98dfacb..e25fbf3c60d5 100644 --- a/sdk/identity/identity/src/credentials/managedIdentityCredential/imdsMsi.ts +++ b/sdk/identity/identity/src/credentials/managedIdentityCredential/imdsMsi.ts @@ -16,7 +16,7 @@ import { createSpan } from "../../util/tracing"; import { imdsApiVersion, imdsEndpointPath, imdsHost } from "./constants"; import { MSI, MSIConfiguration } from "./models"; import { mapScopesToResource, msiGenericGetToken } from "./utils"; -import { AuthenticationError } from "../../client/errors"; +import { AuthenticationError } from "../../errors"; const msiName = "ManagedIdentityCredential - IMDS"; const logger = credentialLogger(msiName); diff --git a/sdk/identity/identity/src/credentials/managedIdentityCredential/index.ts b/sdk/identity/identity/src/credentials/managedIdentityCredential/index.ts index e5623df773ce..503627090ba8 100644 --- a/sdk/identity/identity/src/credentials/managedIdentityCredential/index.ts +++ b/sdk/identity/identity/src/credentials/managedIdentityCredential/index.ts @@ -5,7 +5,7 @@ import { SpanStatusCode } from "@azure/core-tracing"; import { AccessToken, GetTokenOptions, TokenCredential } from "@azure/core-auth"; import { IdentityClient, TokenCredentialOptions } from "../../client/identityClient"; -import { AuthenticationError, CredentialUnavailableError } from "../../client/errors"; +import { AuthenticationError, CredentialUnavailableError } from "../../errors"; import { credentialLogger, formatSuccess, formatError } from "../../util/logging"; import { appServiceMsi2017 } from "./appServiceMsi2017"; import { createSpan } from "../../util/tracing"; diff --git a/sdk/identity/identity/src/credentials/visualStudioCodeCredential.ts b/sdk/identity/identity/src/credentials/visualStudioCodeCredential.ts index 48f33dfaee76..970f01bb318f 100644 --- a/sdk/identity/identity/src/credentials/visualStudioCodeCredential.ts +++ b/sdk/identity/identity/src/credentials/visualStudioCodeCredential.ts @@ -7,7 +7,7 @@ import fs from "fs"; import os from "os"; import path from "path"; -import { CredentialUnavailableError } from "../client/errors"; +import { CredentialUnavailableError } from "../errors"; import { IdentityClient, TokenCredentialOptions } from "../client/identityClient"; import { AzureAuthorityHosts } from "../constants"; import { checkTenantId } from "../util/checkTenantId"; diff --git a/sdk/identity/identity/src/client/errors.ts b/sdk/identity/identity/src/errors.ts similarity index 81% rename from sdk/identity/identity/src/client/errors.ts rename to sdk/identity/identity/src/errors.ts index dfe225f5b2ef..48931ebeece1 100644 --- a/sdk/identity/identity/src/client/errors.ts +++ b/sdk/identity/identity/src/errors.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. +import { GetTokenOptions } from "@azure/core-auth"; + /** * See the official documentation for more details: * @@ -182,3 +184,47 @@ function convertOAuthErrorResponseToErrorResponse(errorBody: OAuthErrorResponse) traceId: errorBody.trace_id }; } + +/** + * Optional parameters to the {@link AuthenticationRequiredError} + */ +export interface AuthenticationRequiredErrorOptions { + /** + * The list of scopes for which the token will have access. + */ + scopes: string[]; + /** + * The options passed to the getToken request. + */ + getTokenOptions?: GetTokenOptions; + /** + * The message of the error. + */ + message?: string; +} + +/** + * Error used to enforce authentication after trying to retrieve a token silently. + */ +export class AuthenticationRequiredError extends Error { + /** + * The list of scopes for which the token will have access. + */ + public scopes: string[]; + /** + * The options passed to the getToken request. + */ + public getTokenOptions?: GetTokenOptions; + + constructor( + /** + * Optional parameters. A message can be specified. The {@link GetTokenOptions} of the request can also be specified to more easily associate the error with the received parameters. + */ + options: AuthenticationRequiredErrorOptions + ) { + super(options.message); + this.scopes = options.scopes; + this.getTokenOptions = options.getTokenOptions; + this.name = "AuthenticationRequiredError"; + } +} diff --git a/sdk/identity/identity/src/index.ts b/sdk/identity/identity/src/index.ts index 8348225dddf6..643edee90d88 100644 --- a/sdk/identity/identity/src/index.ts +++ b/sdk/identity/identity/src/index.ts @@ -8,8 +8,19 @@ export { IdentityPlugin } from "./plugins/provider"; import { TokenCredential } from "@azure/core-auth"; import { DefaultAzureCredential } from "./credentials/defaultAzureCredential"; +export { + AuthenticationError, + ErrorResponse, + AggregateAuthenticationError, + AuthenticationErrorName, + AggregateAuthenticationErrorName, + CredentialUnavailableError, + CredentialUnavailableErrorName, + AuthenticationRequiredError, + AuthenticationRequiredErrorOptions +} from "./errors"; + export { AuthenticationRecord } from "./msal/types"; -export { AuthenticationRequiredError } from "./msal/errors"; export { serializeAuthenticationRecord, deserializeAuthenticationRecord } from "./msal/utils"; export { TokenCredentialOptions } from "./client/identityClient"; @@ -71,16 +82,6 @@ export { export { TokenCachePersistenceOptions } from "./msal/nodeFlows/tokenCachePersistenceOptions"; -export { - AuthenticationError, - ErrorResponse, - AggregateAuthenticationError, - AuthenticationErrorName, - AggregateAuthenticationErrorName, - CredentialUnavailableError, - CredentialUnavailableErrorName -} from "./client/errors"; - export { TokenCredential, GetTokenOptions, AccessToken } from "@azure/core-auth"; export { logger } from "./util/logging"; diff --git a/sdk/identity/identity/src/msal/browserFlows/browserCommon.ts b/sdk/identity/identity/src/msal/browserFlows/browserCommon.ts index 3a362dc266af..e5c9fa89eedc 100644 --- a/sdk/identity/identity/src/msal/browserFlows/browserCommon.ts +++ b/sdk/identity/identity/src/msal/browserFlows/browserCommon.ts @@ -7,14 +7,13 @@ import { AccessToken } from "@azure/core-auth"; import { DefaultTenantId } from "../../constants"; import { resolveTenantId } from "../../util/resolveTenantId"; +import { processMultiTenantRequest } from "../../util/validateMultiTenant"; import { BrowserLoginStyle } from "../../credentials/interactiveBrowserCredentialOptions"; +import { AuthenticationRequiredError, CredentialUnavailableError } from "../../errors"; import { getAuthority, getKnownAuthorities, MsalBaseUtilities } from "../utils"; import { MsalFlow, MsalFlowOptions } from "../flows"; import { AuthenticationRecord } from "../types"; import { CredentialFlowGetTokenOptions } from "../credentials"; -import { AuthenticationRequiredError } from "../errors"; -import { CredentialUnavailableError } from "../../client/errors"; -import { processMultiTenantRequest } from "../../util/validateMultiTenant"; /** * Union of the constructor parameters that all MSAL flow types take. @@ -160,11 +159,12 @@ export abstract class MsalBrowser extends MsalBaseUtilities implements MsalBrows throw err; } if (options?.disableAutomaticAuthentication) { - throw new AuthenticationRequiredError( + throw new AuthenticationRequiredError({ scopes, - options, - "Automatic authentication has been disabled. You may call the authentication() method." - ); + 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}` diff --git a/sdk/identity/identity/src/msal/browserFlows/msalAuthCode.ts b/sdk/identity/identity/src/msal/browserFlows/msalAuthCode.ts index a81004fba11e..0bc7bbb2e32d 100644 --- a/sdk/identity/identity/src/msal/browserFlows/msalAuthCode.ts +++ b/sdk/identity/identity/src/msal/browserFlows/msalAuthCode.ts @@ -5,11 +5,11 @@ import * as msalBrowser from "@azure/msal-browser"; import { AccessToken } from "@azure/core-auth"; -import { MsalBrowserFlowOptions, MsalBrowser } from "./browserCommon"; +import { AuthenticationRequiredError } from "../../errors"; import { defaultLoggerCallback, msalToPublic, publicToMsal } from "../utils"; import { AuthenticationRecord } from "../types"; -import { AuthenticationRequiredError } from "../errors"; import { CredentialFlowGetTokenOptions } from "../credentials"; +import { MsalBrowserFlowOptions, MsalBrowser } from "./browserCommon"; // We keep a copy of the redirect hash. const redirectHash = self.location.hash; @@ -158,7 +158,12 @@ To work with multiple accounts for the same Client ID and Tenant ID, please prov ): Promise { const account = await this.getActiveAccount(); if (!account) { - throw new AuthenticationRequiredError(scopes, options); + throw new AuthenticationRequiredError({ + scopes, + getTokenOptions: options, + message: + "Silent authentication failed. We couldn't retrieve an active account from the cache." + }); } const parameters: msalBrowser.SilentRequest = { @@ -187,7 +192,12 @@ To work with multiple accounts for the same Client ID and Tenant ID, please prov ): Promise { const account = await this.getActiveAccount(); if (!account) { - throw new AuthenticationRequiredError(scopes, options); + throw new AuthenticationRequiredError({ + scopes, + getTokenOptions: options, + message: + "Silent authentication failed. We couldn't retrieve an active account from the cache." + }); } const parameters: msalBrowser.RedirectRequest = { diff --git a/sdk/identity/identity/src/msal/errors.ts b/sdk/identity/identity/src/msal/errors.ts deleted file mode 100644 index 71ee673d5fb1..000000000000 --- a/sdk/identity/identity/src/msal/errors.ts +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { GetTokenOptions } from "@azure/core-auth"; - -/** - * Error used to enforce authentication after trying to retrieve a token silently. - */ -export class AuthenticationRequiredError extends Error { - constructor( - /** - * The list of scopes for which the token will have access. - */ - public scopes: string[], - /** - * The options used to configure the getToken request. - */ - public getTokenOptions: GetTokenOptions = {}, - message?: string - ) { - super(message); - this.name = "AuthenticationRequiredError"; - } -} diff --git a/sdk/identity/identity/src/msal/nodeFlows/msalOpenBrowser.ts b/sdk/identity/identity/src/msal/nodeFlows/msalOpenBrowser.ts index ed1eb4c602aa..4009d447807d 100644 --- a/sdk/identity/identity/src/msal/nodeFlows/msalOpenBrowser.ts +++ b/sdk/identity/identity/src/msal/nodeFlows/msalOpenBrowser.ts @@ -11,9 +11,9 @@ import open from "open"; import stoppable from "stoppable"; import { credentialLogger, formatError, formatSuccess } from "../../util/logging"; +import { CredentialUnavailableError } from "../../errors"; import { MsalNodeOptions, MsalNode } from "./nodeCommon"; import { msalToPublic } from "../utils"; -import { CredentialUnavailableError } from "../../client/errors"; import { CredentialFlowGetTokenOptions } from "../credentials"; /** diff --git a/sdk/identity/identity/src/msal/nodeFlows/nodeCommon.ts b/sdk/identity/identity/src/msal/nodeFlows/nodeCommon.ts index 340063d483c1..9b5a1b31c4fb 100644 --- a/sdk/identity/identity/src/msal/nodeFlows/nodeCommon.ts +++ b/sdk/identity/identity/src/msal/nodeFlows/nodeCommon.ts @@ -10,9 +10,9 @@ import { AbortSignalLike } from "@azure/abort-controller"; import { DeveloperSignOnClientId } from "../../constants"; import { IdentityClient, TokenCredentialOptions } from "../../client/identityClient"; import { resolveTenantId } from "../../util/resolveTenantId"; +import { AuthenticationRequiredError } from "../../errors"; import { CredentialFlowGetTokenOptions } from "../credentials"; import { MsalFlow, MsalFlowOptions } from "../flows"; -import { AuthenticationRequiredError } from "../errors"; import { AuthenticationRecord } from "../types"; import { defaultLoggerCallback, @@ -242,7 +242,12 @@ To work with multiple accounts for the same Client ID and Tenant ID, please prov ): Promise { await this.getActiveAccount(); if (!this.account) { - throw new AuthenticationRequiredError(scopes, options); + throw new AuthenticationRequiredError({ + scopes, + getTokenOptions: options, + message: + "Silent authentication failed. We couldn't retrieve an active account from the cache." + }); } const silentRequest: msalNode.SilentFlowRequest = { @@ -291,11 +296,12 @@ To work with multiple accounts for the same Client ID and Tenant ID, please prov throw err; } if (options?.disableAutomaticAuthentication) { - throw new AuthenticationRequiredError( + throw new AuthenticationRequiredError({ scopes, - options, - "Automatic authentication has been disabled. You may call the authentication() method." - ); + 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.`); return this.doGetToken(scopes, options); diff --git a/sdk/identity/identity/src/msal/utils.ts b/sdk/identity/identity/src/msal/utils.ts index eafb02ab3597..61b8f982651d 100644 --- a/sdk/identity/identity/src/msal/utils.ts +++ b/sdk/identity/identity/src/msal/utils.ts @@ -8,10 +8,9 @@ import { AbortError } from "@azure/abort-controller"; import { v4 as uuidv4 } from "uuid"; import { CredentialLogger, formatError, formatSuccess } from "../util/logging"; -import { CredentialUnavailableError } from "../client/errors"; +import { CredentialUnavailableError, AuthenticationRequiredError } from "../errors"; import { DefaultAuthorityHost, DefaultTenantId } from "../constants"; import { AuthenticationRecord, MsalAccountInfo, MsalResult, MsalToken } from "./types"; -import { AuthenticationRequiredError } from "./errors"; import { MsalFlowOptions } from "./flows"; /** @@ -32,11 +31,11 @@ export function ensureValidMsalToken( ): void { const error = (message: string): Error => { logger.getToken.info(message); - return new AuthenticationRequiredError( - Array.isArray(scopes) ? scopes : [scopes], + return new AuthenticationRequiredError({ + scopes: Array.isArray(scopes) ? scopes : [scopes], getTokenOptions, message - ); + }); }; if (!msalToken) { throw error("No response"); @@ -190,7 +189,7 @@ export class MsalBaseUtilities { ) { return error; } - return new AuthenticationRequiredError(scopes, getTokenOptions, error.message); + return new AuthenticationRequiredError({ scopes, getTokenOptions, message: error.message }); } } diff --git a/sdk/identity/identity/test/public/chainedTokenCredential.spec.ts b/sdk/identity/identity/test/public/chainedTokenCredential.spec.ts index f4c90a9dc390..cc17697b5c5c 100644 --- a/sdk/identity/identity/test/public/chainedTokenCredential.spec.ts +++ b/sdk/identity/identity/test/public/chainedTokenCredential.spec.ts @@ -24,11 +24,10 @@ describe("ChainedTokenCredential", function() { mockCredential(Promise.reject(new CredentialUnavailableError("unavailable."))), mockCredential( Promise.reject( - new AuthenticationRequiredError( - ["https://vault.azure.net/.default"], - {}, - "authentication-required." - ) + new AuthenticationRequiredError({ + scopes: ["https://vault.azure.net/.default"], + message: "authentication-required." + }) ) ), mockCredential(Promise.resolve({ token: "firstToken", expiresOnTimestamp: 0 })),