UNPKG

@azure/msal-common

Version:
1,318 lines (1,300 loc) 344 kB
/*! @azure/msal-common v15.12.0 2025-08-19 */ 'use strict'; 'use strict'; /* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ const Constants = { LIBRARY_NAME: "MSAL.JS", SKU: "msal.js.common", // default authority DEFAULT_AUTHORITY: "https://login.microsoftonline.com/common/", DEFAULT_AUTHORITY_HOST: "login.microsoftonline.com", DEFAULT_COMMON_TENANT: "common", // ADFS String ADFS: "adfs", DSTS: "dstsv2", // Default AAD Instance Discovery Endpoint AAD_INSTANCE_DISCOVERY_ENDPT: "https://login.microsoftonline.com/common/discovery/instance?api-version=1.1&authorization_endpoint=", // CIAM URL CIAM_AUTH_URL: ".ciamlogin.com", AAD_TENANT_DOMAIN_SUFFIX: ".onmicrosoft.com", // Resource delimiter - used for certain cache entries RESOURCE_DELIM: "|", // Placeholder for non-existent account ids/objects NO_ACCOUNT: "NO_ACCOUNT", // Claims CLAIMS: "claims", // Consumer UTID CONSUMER_UTID: "9188040d-6c67-4c5b-b112-36a304b66dad", // Default scopes OPENID_SCOPE: "openid", PROFILE_SCOPE: "profile", OFFLINE_ACCESS_SCOPE: "offline_access", EMAIL_SCOPE: "email", CODE_GRANT_TYPE: "authorization_code", RT_GRANT_TYPE: "refresh_token", S256_CODE_CHALLENGE_METHOD: "S256", URL_FORM_CONTENT_TYPE: "application/x-www-form-urlencoded;charset=utf-8", AUTHORIZATION_PENDING: "authorization_pending", NOT_DEFINED: "not_defined", EMPTY_STRING: "", NOT_APPLICABLE: "N/A", NOT_AVAILABLE: "Not Available", FORWARD_SLASH: "/", IMDS_ENDPOINT: "http://169.254.169.254/metadata/instance/compute/location", IMDS_VERSION: "2020-06-01", IMDS_TIMEOUT: 2000, AZURE_REGION_AUTO_DISCOVER_FLAG: "TryAutoDetect", REGIONAL_AUTH_PUBLIC_CLOUD_SUFFIX: "login.microsoft.com", KNOWN_PUBLIC_CLOUDS: [ "login.microsoftonline.com", "login.windows.net", "login.microsoft.com", "sts.windows.net", ], SHR_NONCE_VALIDITY: 240, INVALID_INSTANCE: "invalid_instance", }; const HttpStatus = { SUCCESS: 200, SUCCESS_RANGE_START: 200, SUCCESS_RANGE_END: 299, REDIRECT: 302, CLIENT_ERROR: 400, CLIENT_ERROR_RANGE_START: 400, BAD_REQUEST: 400, UNAUTHORIZED: 401, NOT_FOUND: 404, REQUEST_TIMEOUT: 408, GONE: 410, TOO_MANY_REQUESTS: 429, CLIENT_ERROR_RANGE_END: 499, SERVER_ERROR: 500, SERVER_ERROR_RANGE_START: 500, SERVICE_UNAVAILABLE: 503, GATEWAY_TIMEOUT: 504, SERVER_ERROR_RANGE_END: 599, MULTI_SIDED_ERROR: 600, }; const HttpMethod = { GET: "GET", POST: "POST", }; const OIDC_DEFAULT_SCOPES = [ Constants.OPENID_SCOPE, Constants.PROFILE_SCOPE, Constants.OFFLINE_ACCESS_SCOPE, ]; const OIDC_SCOPES = [...OIDC_DEFAULT_SCOPES, Constants.EMAIL_SCOPE]; /** * Request header names */ const HeaderNames = { CONTENT_TYPE: "Content-Type", CONTENT_LENGTH: "Content-Length", RETRY_AFTER: "Retry-After", CCS_HEADER: "X-AnchorMailbox", WWWAuthenticate: "WWW-Authenticate", AuthenticationInfo: "Authentication-Info", X_MS_REQUEST_ID: "x-ms-request-id", X_MS_HTTP_VERSION: "x-ms-httpver", }; /** * Persistent cache keys MSAL which stay while user is logged in. */ const PersistentCacheKeys = { ACTIVE_ACCOUNT_FILTERS: "active-account-filters", // new cache entry for active_account for a more robust version for browser }; /** * String constants related to AAD Authority */ const AADAuthorityConstants = { COMMON: "common", ORGANIZATIONS: "organizations", CONSUMERS: "consumers", }; /** * Claims request keys */ const ClaimsRequestKeys = { ACCESS_TOKEN: "access_token", XMS_CC: "xms_cc", }; /** * we considered making this "enum" in the request instead of string, however it looks like the allowed list of * prompt values kept changing over past couple of years. There are some undocumented prompt values for some * internal partners too, hence the choice of generic "string" type instead of the "enum" */ const PromptValue = { LOGIN: "login", SELECT_ACCOUNT: "select_account", CONSENT: "consent", NONE: "none", CREATE: "create", NO_SESSION: "no_session", }; /** * allowed values for codeVerifier */ const CodeChallengeMethodValues = { PLAIN: "plain", S256: "S256", }; /** * Allowed values for response_type */ const OAuthResponseType = { CODE: "code", IDTOKEN_TOKEN: "id_token token", IDTOKEN_TOKEN_REFRESHTOKEN: "id_token token refresh_token", }; /** * allowed values for server response type * @deprecated Use ResponseMode instead */ const ServerResponseType = { QUERY: "query", FRAGMENT: "fragment", }; /** * allowed values for response_mode */ const ResponseMode = { QUERY: "query", FRAGMENT: "fragment", FORM_POST: "form_post", }; /** * allowed grant_type */ const GrantType = { IMPLICIT_GRANT: "implicit", AUTHORIZATION_CODE_GRANT: "authorization_code", CLIENT_CREDENTIALS_GRANT: "client_credentials", RESOURCE_OWNER_PASSWORD_GRANT: "password", REFRESH_TOKEN_GRANT: "refresh_token", DEVICE_CODE_GRANT: "device_code", JWT_BEARER: "urn:ietf:params:oauth:grant-type:jwt-bearer", }; /** * Account types in Cache */ const CacheAccountType = { MSSTS_ACCOUNT_TYPE: "MSSTS", ADFS_ACCOUNT_TYPE: "ADFS", MSAV1_ACCOUNT_TYPE: "MSA", GENERIC_ACCOUNT_TYPE: "Generic", // NTLM, Kerberos, FBA, Basic etc }; /** * Separators used in cache */ const Separators = { CACHE_KEY_SEPARATOR: "-", CLIENT_INFO_SEPARATOR: ".", }; /** * Credential Type stored in the cache */ const CredentialType = { ID_TOKEN: "IdToken", ACCESS_TOKEN: "AccessToken", ACCESS_TOKEN_WITH_AUTH_SCHEME: "AccessToken_With_AuthScheme", REFRESH_TOKEN: "RefreshToken", }; /** * Combine all cache types */ const CacheType = { ADFS: 1001, MSA: 1002, MSSTS: 1003, GENERIC: 1004, ACCESS_TOKEN: 2001, REFRESH_TOKEN: 2002, ID_TOKEN: 2003, APP_METADATA: 3001, UNDEFINED: 9999, }; /** * More Cache related constants */ const APP_METADATA = "appmetadata"; const CLIENT_INFO$1 = "client_info"; const THE_FAMILY_ID = "1"; const AUTHORITY_METADATA_CONSTANTS = { CACHE_KEY: "authority-metadata", REFRESH_TIME_SECONDS: 3600 * 24, // 24 Hours }; const AuthorityMetadataSource = { CONFIG: "config", CACHE: "cache", NETWORK: "network", HARDCODED_VALUES: "hardcoded_values", }; const SERVER_TELEM_CONSTANTS = { SCHEMA_VERSION: 5, MAX_LAST_HEADER_BYTES: 330, MAX_CACHED_ERRORS: 50, CACHE_KEY: "server-telemetry", CATEGORY_SEPARATOR: "|", VALUE_SEPARATOR: ",", OVERFLOW_TRUE: "1", OVERFLOW_FALSE: "0", UNKNOWN_ERROR: "unknown_error", }; /** * Type of the authentication request */ const AuthenticationScheme = { BEARER: "Bearer", POP: "pop", SSH: "ssh-cert", }; /** * Constants related to throttling */ const ThrottlingConstants = { // Default time to throttle RequestThumbprint in seconds DEFAULT_THROTTLE_TIME_SECONDS: 60, // Default maximum time to throttle in seconds, overrides what the server sends back DEFAULT_MAX_THROTTLE_TIME_SECONDS: 3600, // Prefix for storing throttling entries THROTTLING_PREFIX: "throttling", // Value assigned to the x-ms-lib-capability header to indicate to the server the library supports throttling X_MS_LIB_CAPABILITY_VALUE: "retry-after, h429", }; const Errors = { INVALID_GRANT_ERROR: "invalid_grant", CLIENT_MISMATCH_ERROR: "client_mismatch", }; /** * Password grant parameters */ const PasswordGrantConstants = { username: "username", password: "password", }; /** * Region Discovery Sources */ const RegionDiscoverySources = { FAILED_AUTO_DETECTION: "1", INTERNAL_CACHE: "2", ENVIRONMENT_VARIABLE: "3", IMDS: "4", }; /** * Region Discovery Outcomes */ const RegionDiscoveryOutcomes = { CONFIGURED_NO_AUTO_DETECTION: "2", AUTO_DETECTION_REQUESTED_SUCCESSFUL: "4", AUTO_DETECTION_REQUESTED_FAILED: "5", }; /** * Specifies the reason for fetching the access token from the identity provider */ const CacheOutcome = { // When a token is found in the cache or the cache is not supposed to be hit when making the request NOT_APPLICABLE: "0", // When the token request goes to the identity provider because force_refresh was set to true. Also occurs if claims were requested FORCE_REFRESH_OR_CLAIMS: "1", // When the token request goes to the identity provider because no cached access token exists NO_CACHED_ACCESS_TOKEN: "2", // When the token request goes to the identity provider because cached access token expired CACHED_ACCESS_TOKEN_EXPIRED: "3", // When the token request goes to the identity provider because refresh_in was used and the existing token needs to be refreshed PROACTIVELY_REFRESHED: "4", }; const JsonWebTokenTypes = { Jwt: "JWT", Jwk: "JWK", Pop: "pop", }; const ONE_DAY_IN_MS = 86400000; // Token renewal offset default in seconds const DEFAULT_TOKEN_RENEWAL_OFFSET_SEC = 300; const EncodingTypes = { BASE64: "base64", HEX: "hex", UTF8: "utf-8", }; /* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ /** * AuthErrorMessage class containing string constants used by error codes and messages. */ const unexpectedError = "unexpected_error"; const postRequestFailed = "post_request_failed"; var AuthErrorCodes = /*#__PURE__*/Object.freeze({ __proto__: null, postRequestFailed: postRequestFailed, unexpectedError: unexpectedError }); /* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ const AuthErrorMessages = { [unexpectedError]: "Unexpected error in authentication.", [postRequestFailed]: "Post request failed from the network, could be a 4xx/5xx or a network unavailability. Please check the exact error code for details.", }; /** * AuthErrorMessage class containing string constants used by error codes and messages. * @deprecated Use AuthErrorCodes instead */ const AuthErrorMessage = { unexpectedError: { code: unexpectedError, desc: AuthErrorMessages[unexpectedError], }, postRequestFailed: { code: postRequestFailed, desc: AuthErrorMessages[postRequestFailed], }, }; /** * General error class thrown by the MSAL.js library. */ class AuthError extends Error { constructor(errorCode, errorMessage, suberror) { const errorString = errorMessage ? `${errorCode}: ${errorMessage}` : errorCode; super(errorString); Object.setPrototypeOf(this, AuthError.prototype); this.errorCode = errorCode || Constants.EMPTY_STRING; this.errorMessage = errorMessage || Constants.EMPTY_STRING; this.subError = suberror || Constants.EMPTY_STRING; this.name = "AuthError"; } setCorrelationId(correlationId) { this.correlationId = correlationId; } } function createAuthError(code, additionalMessage) { return new AuthError(code, additionalMessage ? `${AuthErrorMessages[code]} ${additionalMessage}` : AuthErrorMessages[code]); } /* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ const clientInfoDecodingError = "client_info_decoding_error"; const clientInfoEmptyError = "client_info_empty_error"; const tokenParsingError = "token_parsing_error"; const nullOrEmptyToken = "null_or_empty_token"; const endpointResolutionError = "endpoints_resolution_error"; const networkError = "network_error"; const openIdConfigError = "openid_config_error"; const hashNotDeserialized = "hash_not_deserialized"; const invalidState = "invalid_state"; const stateMismatch = "state_mismatch"; const stateNotFound = "state_not_found"; const nonceMismatch = "nonce_mismatch"; const authTimeNotFound = "auth_time_not_found"; const maxAgeTranspired = "max_age_transpired"; const multipleMatchingTokens = "multiple_matching_tokens"; const multipleMatchingAccounts = "multiple_matching_accounts"; const multipleMatchingAppMetadata = "multiple_matching_appMetadata"; const requestCannotBeMade = "request_cannot_be_made"; const cannotRemoveEmptyScope = "cannot_remove_empty_scope"; const cannotAppendScopeSet = "cannot_append_scopeset"; const emptyInputScopeSet = "empty_input_scopeset"; const deviceCodePollingCancelled = "device_code_polling_cancelled"; const deviceCodeExpired = "device_code_expired"; const deviceCodeUnknownError = "device_code_unknown_error"; const noAccountInSilentRequest = "no_account_in_silent_request"; const invalidCacheRecord = "invalid_cache_record"; const invalidCacheEnvironment = "invalid_cache_environment"; const noAccountFound = "no_account_found"; const noCryptoObject = "no_crypto_object"; const unexpectedCredentialType = "unexpected_credential_type"; const invalidAssertion = "invalid_assertion"; const invalidClientCredential = "invalid_client_credential"; const tokenRefreshRequired = "token_refresh_required"; const userTimeoutReached = "user_timeout_reached"; const tokenClaimsCnfRequiredForSignedJwt = "token_claims_cnf_required_for_signedjwt"; const authorizationCodeMissingFromServerResponse = "authorization_code_missing_from_server_response"; const bindingKeyNotRemoved = "binding_key_not_removed"; const endSessionEndpointNotSupported = "end_session_endpoint_not_supported"; const keyIdMissing = "key_id_missing"; const noNetworkConnectivity = "no_network_connectivity"; const userCanceled = "user_canceled"; const missingTenantIdError = "missing_tenant_id_error"; const methodNotImplemented = "method_not_implemented"; const nestedAppAuthBridgeDisabled = "nested_app_auth_bridge_disabled"; var ClientAuthErrorCodes = /*#__PURE__*/Object.freeze({ __proto__: null, authTimeNotFound: authTimeNotFound, authorizationCodeMissingFromServerResponse: authorizationCodeMissingFromServerResponse, bindingKeyNotRemoved: bindingKeyNotRemoved, cannotAppendScopeSet: cannotAppendScopeSet, cannotRemoveEmptyScope: cannotRemoveEmptyScope, clientInfoDecodingError: clientInfoDecodingError, clientInfoEmptyError: clientInfoEmptyError, deviceCodeExpired: deviceCodeExpired, deviceCodePollingCancelled: deviceCodePollingCancelled, deviceCodeUnknownError: deviceCodeUnknownError, emptyInputScopeSet: emptyInputScopeSet, endSessionEndpointNotSupported: endSessionEndpointNotSupported, endpointResolutionError: endpointResolutionError, hashNotDeserialized: hashNotDeserialized, invalidAssertion: invalidAssertion, invalidCacheEnvironment: invalidCacheEnvironment, invalidCacheRecord: invalidCacheRecord, invalidClientCredential: invalidClientCredential, invalidState: invalidState, keyIdMissing: keyIdMissing, maxAgeTranspired: maxAgeTranspired, methodNotImplemented: methodNotImplemented, missingTenantIdError: missingTenantIdError, multipleMatchingAccounts: multipleMatchingAccounts, multipleMatchingAppMetadata: multipleMatchingAppMetadata, multipleMatchingTokens: multipleMatchingTokens, nestedAppAuthBridgeDisabled: nestedAppAuthBridgeDisabled, networkError: networkError, noAccountFound: noAccountFound, noAccountInSilentRequest: noAccountInSilentRequest, noCryptoObject: noCryptoObject, noNetworkConnectivity: noNetworkConnectivity, nonceMismatch: nonceMismatch, nullOrEmptyToken: nullOrEmptyToken, openIdConfigError: openIdConfigError, requestCannotBeMade: requestCannotBeMade, stateMismatch: stateMismatch, stateNotFound: stateNotFound, tokenClaimsCnfRequiredForSignedJwt: tokenClaimsCnfRequiredForSignedJwt, tokenParsingError: tokenParsingError, tokenRefreshRequired: tokenRefreshRequired, unexpectedCredentialType: unexpectedCredentialType, userCanceled: userCanceled, userTimeoutReached: userTimeoutReached }); /* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ /** * ClientAuthErrorMessage class containing string constants used by error codes and messages. */ const ClientAuthErrorMessages = { [clientInfoDecodingError]: "The client info could not be parsed/decoded correctly", [clientInfoEmptyError]: "The client info was empty", [tokenParsingError]: "Token cannot be parsed", [nullOrEmptyToken]: "The token is null or empty", [endpointResolutionError]: "Endpoints cannot be resolved", [networkError]: "Network request failed", [openIdConfigError]: "Could not retrieve endpoints. Check your authority and verify the .well-known/openid-configuration endpoint returns the required endpoints.", [hashNotDeserialized]: "The hash parameters could not be deserialized", [invalidState]: "State was not the expected format", [stateMismatch]: "State mismatch error", [stateNotFound]: "State not found", [nonceMismatch]: "Nonce mismatch error", [authTimeNotFound]: "Max Age was requested and the ID token is missing the auth_time variable." + " auth_time is an optional claim and is not enabled by default - it must be enabled." + " See https://aka.ms/msaljs/optional-claims for more information.", [maxAgeTranspired]: "Max Age is set to 0, or too much time has elapsed since the last end-user authentication.", [multipleMatchingTokens]: "The cache contains multiple tokens satisfying the requirements. " + "Call AcquireToken again providing more requirements such as authority or account.", [multipleMatchingAccounts]: "The cache contains multiple accounts satisfying the given parameters. Please pass more info to obtain the correct account", [multipleMatchingAppMetadata]: "The cache contains multiple appMetadata satisfying the given parameters. Please pass more info to obtain the correct appMetadata", [requestCannotBeMade]: "Token request cannot be made without authorization code or refresh token.", [cannotRemoveEmptyScope]: "Cannot remove null or empty scope from ScopeSet", [cannotAppendScopeSet]: "Cannot append ScopeSet", [emptyInputScopeSet]: "Empty input ScopeSet cannot be processed", [deviceCodePollingCancelled]: "Caller has cancelled token endpoint polling during device code flow by setting DeviceCodeRequest.cancel = true.", [deviceCodeExpired]: "Device code is expired.", [deviceCodeUnknownError]: "Device code stopped polling for unknown reasons.", [noAccountInSilentRequest]: "Please pass an account object, silent flow is not supported without account information", [invalidCacheRecord]: "Cache record object was null or undefined.", [invalidCacheEnvironment]: "Invalid environment when attempting to create cache entry", [noAccountFound]: "No account found in cache for given key.", [noCryptoObject]: "No crypto object detected.", [unexpectedCredentialType]: "Unexpected credential type.", [invalidAssertion]: "Client assertion must meet requirements described in https://tools.ietf.org/html/rfc7515", [invalidClientCredential]: "Client credential (secret, certificate, or assertion) must not be empty when creating a confidential client. An application should at most have one credential", [tokenRefreshRequired]: "Cannot return token from cache because it must be refreshed. This may be due to one of the following reasons: forceRefresh parameter is set to true, claims have been requested, there is no cached access token or it is expired.", [userTimeoutReached]: "User defined timeout for device code polling reached", [tokenClaimsCnfRequiredForSignedJwt]: "Cannot generate a POP jwt if the token_claims are not populated", [authorizationCodeMissingFromServerResponse]: "Server response does not contain an authorization code to proceed", [bindingKeyNotRemoved]: "Could not remove the credential's binding key from storage.", [endSessionEndpointNotSupported]: "The provided authority does not support logout", [keyIdMissing]: "A keyId value is missing from the requested bound token's cache record and is required to match the token to it's stored binding key.", [noNetworkConnectivity]: "No network connectivity. Check your internet connection.", [userCanceled]: "User cancelled the flow.", [missingTenantIdError]: "A tenant id - not common, organizations, or consumers - must be specified when using the client_credentials flow.", [methodNotImplemented]: "This method has not been implemented", [nestedAppAuthBridgeDisabled]: "The nested app auth bridge is disabled", }; /** * String constants used by error codes and messages. * @deprecated Use ClientAuthErrorCodes instead */ const ClientAuthErrorMessage = { clientInfoDecodingError: { code: clientInfoDecodingError, desc: ClientAuthErrorMessages[clientInfoDecodingError], }, clientInfoEmptyError: { code: clientInfoEmptyError, desc: ClientAuthErrorMessages[clientInfoEmptyError], }, tokenParsingError: { code: tokenParsingError, desc: ClientAuthErrorMessages[tokenParsingError], }, nullOrEmptyToken: { code: nullOrEmptyToken, desc: ClientAuthErrorMessages[nullOrEmptyToken], }, endpointResolutionError: { code: endpointResolutionError, desc: ClientAuthErrorMessages[endpointResolutionError], }, networkError: { code: networkError, desc: ClientAuthErrorMessages[networkError], }, unableToGetOpenidConfigError: { code: openIdConfigError, desc: ClientAuthErrorMessages[openIdConfigError], }, hashNotDeserialized: { code: hashNotDeserialized, desc: ClientAuthErrorMessages[hashNotDeserialized], }, invalidStateError: { code: invalidState, desc: ClientAuthErrorMessages[invalidState], }, stateMismatchError: { code: stateMismatch, desc: ClientAuthErrorMessages[stateMismatch], }, stateNotFoundError: { code: stateNotFound, desc: ClientAuthErrorMessages[stateNotFound], }, nonceMismatchError: { code: nonceMismatch, desc: ClientAuthErrorMessages[nonceMismatch], }, authTimeNotFoundError: { code: authTimeNotFound, desc: ClientAuthErrorMessages[authTimeNotFound], }, maxAgeTranspired: { code: maxAgeTranspired, desc: ClientAuthErrorMessages[maxAgeTranspired], }, multipleMatchingTokens: { code: multipleMatchingTokens, desc: ClientAuthErrorMessages[multipleMatchingTokens], }, multipleMatchingAccounts: { code: multipleMatchingAccounts, desc: ClientAuthErrorMessages[multipleMatchingAccounts], }, multipleMatchingAppMetadata: { code: multipleMatchingAppMetadata, desc: ClientAuthErrorMessages[multipleMatchingAppMetadata], }, tokenRequestCannotBeMade: { code: requestCannotBeMade, desc: ClientAuthErrorMessages[requestCannotBeMade], }, removeEmptyScopeError: { code: cannotRemoveEmptyScope, desc: ClientAuthErrorMessages[cannotRemoveEmptyScope], }, appendScopeSetError: { code: cannotAppendScopeSet, desc: ClientAuthErrorMessages[cannotAppendScopeSet], }, emptyInputScopeSetError: { code: emptyInputScopeSet, desc: ClientAuthErrorMessages[emptyInputScopeSet], }, DeviceCodePollingCancelled: { code: deviceCodePollingCancelled, desc: ClientAuthErrorMessages[deviceCodePollingCancelled], }, DeviceCodeExpired: { code: deviceCodeExpired, desc: ClientAuthErrorMessages[deviceCodeExpired], }, DeviceCodeUnknownError: { code: deviceCodeUnknownError, desc: ClientAuthErrorMessages[deviceCodeUnknownError], }, NoAccountInSilentRequest: { code: noAccountInSilentRequest, desc: ClientAuthErrorMessages[noAccountInSilentRequest], }, invalidCacheRecord: { code: invalidCacheRecord, desc: ClientAuthErrorMessages[invalidCacheRecord], }, invalidCacheEnvironment: { code: invalidCacheEnvironment, desc: ClientAuthErrorMessages[invalidCacheEnvironment], }, noAccountFound: { code: noAccountFound, desc: ClientAuthErrorMessages[noAccountFound], }, noCryptoObj: { code: noCryptoObject, desc: ClientAuthErrorMessages[noCryptoObject], }, unexpectedCredentialType: { code: unexpectedCredentialType, desc: ClientAuthErrorMessages[unexpectedCredentialType], }, invalidAssertion: { code: invalidAssertion, desc: ClientAuthErrorMessages[invalidAssertion], }, invalidClientCredential: { code: invalidClientCredential, desc: ClientAuthErrorMessages[invalidClientCredential], }, tokenRefreshRequired: { code: tokenRefreshRequired, desc: ClientAuthErrorMessages[tokenRefreshRequired], }, userTimeoutReached: { code: userTimeoutReached, desc: ClientAuthErrorMessages[userTimeoutReached], }, tokenClaimsRequired: { code: tokenClaimsCnfRequiredForSignedJwt, desc: ClientAuthErrorMessages[tokenClaimsCnfRequiredForSignedJwt], }, noAuthorizationCodeFromServer: { code: authorizationCodeMissingFromServerResponse, desc: ClientAuthErrorMessages[authorizationCodeMissingFromServerResponse], }, bindingKeyNotRemovedError: { code: bindingKeyNotRemoved, desc: ClientAuthErrorMessages[bindingKeyNotRemoved], }, logoutNotSupported: { code: endSessionEndpointNotSupported, desc: ClientAuthErrorMessages[endSessionEndpointNotSupported], }, keyIdMissing: { code: keyIdMissing, desc: ClientAuthErrorMessages[keyIdMissing], }, noNetworkConnectivity: { code: noNetworkConnectivity, desc: ClientAuthErrorMessages[noNetworkConnectivity], }, userCanceledError: { code: userCanceled, desc: ClientAuthErrorMessages[userCanceled], }, missingTenantIdError: { code: missingTenantIdError, desc: ClientAuthErrorMessages[missingTenantIdError], }, nestedAppAuthBridgeDisabled: { code: nestedAppAuthBridgeDisabled, desc: ClientAuthErrorMessages[nestedAppAuthBridgeDisabled], }, }; /** * Error thrown when there is an error in the client code running on the browser. */ class ClientAuthError extends AuthError { constructor(errorCode, additionalMessage) { super(errorCode, additionalMessage ? `${ClientAuthErrorMessages[errorCode]}: ${additionalMessage}` : ClientAuthErrorMessages[errorCode]); this.name = "ClientAuthError"; Object.setPrototypeOf(this, ClientAuthError.prototype); } } function createClientAuthError(errorCode, additionalMessage) { return new ClientAuthError(errorCode, additionalMessage); } /* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ /** * Extract token by decoding the rawToken * * @param encodedToken */ function extractTokenClaims(encodedToken, base64Decode) { const jswPayload = getJWSPayload(encodedToken); // token will be decoded to get the username try { // base64Decode() should throw an error if there is an issue const base64Decoded = base64Decode(jswPayload); return JSON.parse(base64Decoded); } catch (err) { throw createClientAuthError(tokenParsingError); } } /** * decode a JWT * * @param authToken */ function getJWSPayload(authToken) { if (!authToken) { throw createClientAuthError(nullOrEmptyToken); } const tokenPartsRegex = /^([^\.\s]*)\.([^\.\s]+)\.([^\.\s]*)$/; const matches = tokenPartsRegex.exec(authToken); if (!matches || matches.length < 4) { throw createClientAuthError(tokenParsingError); } /** * const crackedToken = { * header: matches[1], * JWSPayload: matches[2], * JWSSig: matches[3], * }; */ return matches[2]; } /** * Determine if the token's max_age has transpired */ function checkMaxAge(authTime, maxAge) { /* * per https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest * To force an immediate re-authentication: If an app requires that a user re-authenticate prior to access, * provide a value of 0 for the max_age parameter and the AS will force a fresh login. */ const fiveMinuteSkew = 300000; // five minutes in milliseconds if (maxAge === 0 || Date.now() - fiveMinuteSkew > authTime + maxAge) { throw createClientAuthError(maxAgeTranspired); } } var AuthToken = /*#__PURE__*/Object.freeze({ __proto__: null, checkMaxAge: checkMaxAge, extractTokenClaims: extractTokenClaims, getJWSPayload: getJWSPayload }); /* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ /** * Authority types supported by MSAL. */ const AuthorityType = { Default: 0, Adfs: 1, Dsts: 2, Ciam: 3, }; /* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ function isOpenIdConfigResponse(response) { return (response.hasOwnProperty("authorization_endpoint") && response.hasOwnProperty("token_endpoint") && response.hasOwnProperty("issuer") && response.hasOwnProperty("jwks_uri")); } /* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ const redirectUriEmpty = "redirect_uri_empty"; const claimsRequestParsingError = "claims_request_parsing_error"; const authorityUriInsecure = "authority_uri_insecure"; const urlParseError = "url_parse_error"; const urlEmptyError = "empty_url_error"; const emptyInputScopesError = "empty_input_scopes_error"; const invalidClaims = "invalid_claims"; const tokenRequestEmpty = "token_request_empty"; const logoutRequestEmpty = "logout_request_empty"; const invalidCodeChallengeMethod = "invalid_code_challenge_method"; const pkceParamsMissing = "pkce_params_missing"; const invalidCloudDiscoveryMetadata = "invalid_cloud_discovery_metadata"; const invalidAuthorityMetadata = "invalid_authority_metadata"; const untrustedAuthority = "untrusted_authority"; const missingSshJwk = "missing_ssh_jwk"; const missingSshKid = "missing_ssh_kid"; const missingNonceAuthenticationHeader = "missing_nonce_authentication_header"; const invalidAuthenticationHeader = "invalid_authentication_header"; const cannotSetOIDCOptions = "cannot_set_OIDCOptions"; const cannotAllowPlatformBroker = "cannot_allow_platform_broker"; const authorityMismatch = "authority_mismatch"; const invalidRequestMethodForEAR = "invalid_request_method_for_EAR"; const invalidAuthorizePostBodyParameters = "invalid_authorize_post_body_parameters"; var ClientConfigurationErrorCodes = /*#__PURE__*/Object.freeze({ __proto__: null, authorityMismatch: authorityMismatch, authorityUriInsecure: authorityUriInsecure, cannotAllowPlatformBroker: cannotAllowPlatformBroker, cannotSetOIDCOptions: cannotSetOIDCOptions, claimsRequestParsingError: claimsRequestParsingError, emptyInputScopesError: emptyInputScopesError, invalidAuthenticationHeader: invalidAuthenticationHeader, invalidAuthorityMetadata: invalidAuthorityMetadata, invalidAuthorizePostBodyParameters: invalidAuthorizePostBodyParameters, invalidClaims: invalidClaims, invalidCloudDiscoveryMetadata: invalidCloudDiscoveryMetadata, invalidCodeChallengeMethod: invalidCodeChallengeMethod, invalidRequestMethodForEAR: invalidRequestMethodForEAR, logoutRequestEmpty: logoutRequestEmpty, missingNonceAuthenticationHeader: missingNonceAuthenticationHeader, missingSshJwk: missingSshJwk, missingSshKid: missingSshKid, pkceParamsMissing: pkceParamsMissing, redirectUriEmpty: redirectUriEmpty, tokenRequestEmpty: tokenRequestEmpty, untrustedAuthority: untrustedAuthority, urlEmptyError: urlEmptyError, urlParseError: urlParseError }); /* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ const ClientConfigurationErrorMessages = { [redirectUriEmpty]: "A redirect URI is required for all calls, and none has been set.", [claimsRequestParsingError]: "Could not parse the given claims request object.", [authorityUriInsecure]: "Authority URIs must use https. Please see here for valid authority configuration options: https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-js-initializing-client-applications#configuration-options", [urlParseError]: "URL could not be parsed into appropriate segments.", [urlEmptyError]: "URL was empty or null.", [emptyInputScopesError]: "Scopes cannot be passed as null, undefined or empty array because they are required to obtain an access token.", [invalidClaims]: "Given claims parameter must be a stringified JSON object.", [tokenRequestEmpty]: "Token request was empty and not found in cache.", [logoutRequestEmpty]: "The logout request was null or undefined.", [invalidCodeChallengeMethod]: 'code_challenge_method passed is invalid. Valid values are "plain" and "S256".', [pkceParamsMissing]: "Both params: code_challenge and code_challenge_method are to be passed if to be sent in the request", [invalidCloudDiscoveryMetadata]: "Invalid cloudDiscoveryMetadata provided. Must be a stringified JSON object containing tenant_discovery_endpoint and metadata fields", [invalidAuthorityMetadata]: "Invalid authorityMetadata provided. Must by a stringified JSON object containing authorization_endpoint, token_endpoint, issuer fields.", [untrustedAuthority]: "The provided authority is not a trusted authority. Please include this authority in the knownAuthorities config parameter.", [missingSshJwk]: "Missing sshJwk in SSH certificate request. A stringified JSON Web Key is required when using the SSH authentication scheme.", [missingSshKid]: "Missing sshKid in SSH certificate request. A string that uniquely identifies the public SSH key is required when using the SSH authentication scheme.", [missingNonceAuthenticationHeader]: "Unable to find an authentication header containing server nonce. Either the Authentication-Info or WWW-Authenticate headers must be present in order to obtain a server nonce.", [invalidAuthenticationHeader]: "Invalid authentication header provided", [cannotSetOIDCOptions]: "Cannot set OIDCOptions parameter. Please change the protocol mode to OIDC or use a non-Microsoft authority.", [cannotAllowPlatformBroker]: "Cannot set allowPlatformBroker parameter to true when not in AAD protocol mode.", [authorityMismatch]: "Authority mismatch error. Authority provided in login request or PublicClientApplication config does not match the environment of the provided account. Please use a matching account or make an interactive request to login to this authority.", [invalidAuthorizePostBodyParameters]: "Invalid authorize post body parameters provided. If you are using authorizePostBodyParameters, the request method must be POST. Please check the request method and parameters.", [invalidRequestMethodForEAR]: "Invalid request method for EAR protocol mode. The request method cannot be GET when using EAR protocol mode. Please change the request method to POST.", }; /** * ClientConfigurationErrorMessage class containing string constants used by error codes and messages. * @deprecated Use ClientConfigurationErrorCodes instead */ const ClientConfigurationErrorMessage = { redirectUriNotSet: { code: redirectUriEmpty, desc: ClientConfigurationErrorMessages[redirectUriEmpty], }, claimsRequestParsingError: { code: claimsRequestParsingError, desc: ClientConfigurationErrorMessages[claimsRequestParsingError], }, authorityUriInsecure: { code: authorityUriInsecure, desc: ClientConfigurationErrorMessages[authorityUriInsecure], }, urlParseError: { code: urlParseError, desc: ClientConfigurationErrorMessages[urlParseError], }, urlEmptyError: { code: urlEmptyError, desc: ClientConfigurationErrorMessages[urlEmptyError], }, emptyScopesError: { code: emptyInputScopesError, desc: ClientConfigurationErrorMessages[emptyInputScopesError], }, invalidClaimsRequest: { code: invalidClaims, desc: ClientConfigurationErrorMessages[invalidClaims], }, tokenRequestEmptyError: { code: tokenRequestEmpty, desc: ClientConfigurationErrorMessages[tokenRequestEmpty], }, logoutRequestEmptyError: { code: logoutRequestEmpty, desc: ClientConfigurationErrorMessages[logoutRequestEmpty], }, invalidCodeChallengeMethod: { code: invalidCodeChallengeMethod, desc: ClientConfigurationErrorMessages[invalidCodeChallengeMethod], }, invalidCodeChallengeParams: { code: pkceParamsMissing, desc: ClientConfigurationErrorMessages[pkceParamsMissing], }, invalidCloudDiscoveryMetadata: { code: invalidCloudDiscoveryMetadata, desc: ClientConfigurationErrorMessages[invalidCloudDiscoveryMetadata], }, invalidAuthorityMetadata: { code: invalidAuthorityMetadata, desc: ClientConfigurationErrorMessages[invalidAuthorityMetadata], }, untrustedAuthority: { code: untrustedAuthority, desc: ClientConfigurationErrorMessages[untrustedAuthority], }, missingSshJwk: { code: missingSshJwk, desc: ClientConfigurationErrorMessages[missingSshJwk], }, missingSshKid: { code: missingSshKid, desc: ClientConfigurationErrorMessages[missingSshKid], }, missingNonceAuthenticationHeader: { code: missingNonceAuthenticationHeader, desc: ClientConfigurationErrorMessages[missingNonceAuthenticationHeader], }, invalidAuthenticationHeader: { code: invalidAuthenticationHeader, desc: ClientConfigurationErrorMessages[invalidAuthenticationHeader], }, cannotSetOIDCOptions: { code: cannotSetOIDCOptions, desc: ClientConfigurationErrorMessages[cannotSetOIDCOptions], }, cannotAllowPlatformBroker: { code: cannotAllowPlatformBroker, desc: ClientConfigurationErrorMessages[cannotAllowPlatformBroker], }, authorityMismatch: { code: authorityMismatch, desc: ClientConfigurationErrorMessages[authorityMismatch], }, invalidAuthorizePostBodyParameters: { code: invalidAuthorizePostBodyParameters, desc: ClientConfigurationErrorMessages[invalidAuthorizePostBodyParameters], }, invalidRequestMethodForEAR: { code: invalidRequestMethodForEAR, desc: ClientConfigurationErrorMessages[invalidRequestMethodForEAR], }, }; /** * Error thrown when there is an error in configuration of the MSAL.js library. */ class ClientConfigurationError extends AuthError { constructor(errorCode) { super(errorCode, ClientConfigurationErrorMessages[errorCode]); this.name = "ClientConfigurationError"; Object.setPrototypeOf(this, ClientConfigurationError.prototype); } } function createClientConfigurationError(errorCode) { return new ClientConfigurationError(errorCode); } /* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ /** * @hidden */ class StringUtils { /** * Check if stringified object is empty * @param strObj */ static isEmptyObj(strObj) { if (strObj) { try { const obj = JSON.parse(strObj); return Object.keys(obj).length === 0; } catch (e) { } } return true; } static startsWith(str, search) { return str.indexOf(search) === 0; } static endsWith(str, search) { return (str.length >= search.length && str.lastIndexOf(search) === str.length - search.length); } /** * Parses string into an object. * * @param query */ static queryStringToObject(query) { const obj = {}; const params = query.split("&"); const decode = (s) => decodeURIComponent(s.replace(/\+/g, " ")); params.forEach((pair) => { if (pair.trim()) { const [key, value] = pair.split(/=(.+)/g, 2); // Split on the first occurence of the '=' character if (key && value) { obj[decode(key)] = decode(value); } } }); return obj; } /** * Trims entries in an array. * * @param arr */ static trimArrayEntries(arr) { return arr.map((entry) => entry.trim()); } /** * Removes empty strings from array * @param arr */ static removeEmptyStringsFromArray(arr) { return arr.filter((entry) => { return !!entry; }); } /** * Attempts to parse a string into JSON * @param str */ static jsonParseHelper(str) { try { return JSON.parse(str); } catch (e) { return null; } } /** * Tests if a given string matches a given pattern, with support for wildcards and queries. * @param pattern Wildcard pattern to string match. Supports "*" for wildcards and "?" for queries * @param input String to match against */ static matchPattern(pattern, input) { /** * Wildcard support: https://stackoverflow.com/a/3117248/4888559 * Queries: replaces "?" in string with escaped "\?" for regex test */ // eslint-disable-next-line security/detect-non-literal-regexp const regex = new RegExp(pattern .replace(/\\/g, "\\\\") .replace(/\*/g, "[^ ]*") .replace(/\?/g, "\\?")); return regex.test(input); } } /* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ /** * Canonicalizes a URL by making it lowercase and ensuring it ends with / * Inlined version of UrlString.canonicalizeUri to avoid circular dependency * @param url - URL to canonicalize * @returns Canonicalized URL */ function canonicalizeUrl(url) { if (!url) { return url; } let lowerCaseUrl = url.toLowerCase(); if (StringUtils.endsWith(lowerCaseUrl, "?")) { lowerCaseUrl = lowerCaseUrl.slice(0, -1); } else if (StringUtils.endsWith(lowerCaseUrl, "?/")) { lowerCaseUrl = lowerCaseUrl.slice(0, -2); } if (!StringUtils.endsWith(lowerCaseUrl, "/")) { lowerCaseUrl += "/"; } return lowerCaseUrl; } /** * Parses hash string from given string. Returns empty string if no hash symbol is found. * @param hashString */ function stripLeadingHashOrQuery(responseString) { if (responseString.startsWith("#/")) { return responseString.substring(2); } else if (responseString.startsWith("#") || responseString.startsWith("?")) { return responseString.substring(1); } return responseString; } /** * Returns URL hash as server auth code response object. */ function getDeserializedResponse(responseString) { // Check if given hash is empty if (!responseString || responseString.indexOf("=") < 0) { return null; } try { // Strip the # or ? symbol if present const normalizedResponse = stripLeadingHashOrQuery(responseString); // If # symbol was not present, above will return empty string, so give original hash value const deserializedHash = Object.fromEntries(new URLSearchParams(normalizedResponse)); // Check for known response properties if (deserializedHash.code || deserializedHash.ear_jwe || deserializedHash.error || deserializedHash.error_description || deserializedHash.state) { return deserializedHash; } } catch (e) { throw createClientAuthError(hashNotDeserialized); } return null; } /** * Utility to create a URL from the params map */ function mapToQueryString(parameters, encodeExtraParams = true, extraQueryParameters) { const queryParameterArray = new Array(); parameters.forEach((value, key) => { if (!encodeExtraParams && extraQueryParameters && key in extraQueryParameters) { queryParameterArray.push(`${key}=${value}`); } else { queryParameterArray.push(`${key}=${encodeURIComponent(value)}`); } }); return queryParameterArray.join("&"); } /** * Normalizes URLs for comparison by removing hash, canonicalizing, * and ensuring consistent URL encoding in query parameters. * This fixes redirect loops when URLs contain encoded characters like apostrophes (%27). * @param url - URL to normalize * @returns Normalized URL string for comparison */ function normalizeUrlForComparison(url) { if (!url) { return url; } // Remove hash first const urlWithoutHash = url.split("#")[0]; try { // Parse the URL to handle encoding consistently const urlObj = new URL(urlWithoutHash); /* * Reconstruct the URL with properly decoded query parameters * This ensures that %27 and ' are treated as equivalent */ const normalizedUrl = urlObj.origin + urlObj.pathname + urlObj.search; // Apply canonicalization logic inline to avoid circular dependency return canonicalizeUrl(normalizedUrl); } catch (e) { // Fallback to original logic if URL parsing fails return canonicalizeUrl(urlWithoutHash); } } var UrlUtils = /*#__PURE__*/Object.freeze({ __proto__: null, getDeserializedResponse: getDeserializedResponse, mapToQueryString: mapToQueryString, normalizeUrlForComparison: normalizeUrlForComparison, stripLeadingHashOrQuery: stripLeadingHashOrQuery }); /* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ /** * Url object class which can perform various transformations on url strings. */ class UrlString { get urlString() { return this._urlString; } constructor(url) { this._urlString = url; if (!this._urlString) { // Throws error if url is empty throw createClientConfigurationError(urlEmptyError); } if (!url.includes("#")) { this._urlString = UrlString.canonicalizeUri(url); } } /** * Ensure urls are lower case and end with a / character. * @param url */ static canonicalizeUri(url) { if (url) { let lowerCaseUrl = url.toLowerCase(); if (StringUtils.endsWith(lowerCaseUrl, "?")) { lowerCaseUrl = lowerCaseUrl.slice(0, -1); } else if (StringUtils.endsWith(lowerCaseUrl, "?/")) { lowerCaseUrl = lowerCaseUrl.slice(0, -2); } if (!StringUtils.endsWith(lowerCaseUrl, "/")) { lowerCaseUrl += "/"; } return lowerCaseUrl; } return url; } /** * Throws if urlString passed is not a valid authority URI string. */ validateAsUri() { // Attempts to parse url for uri components let components; try { components = this.getUrlComponents(); } catch (e) { throw createClientConfigurationError(urlParseError); } // Throw error if URI or path segments are not parseable. if (!components.HostNameAndPort || !components.PathSegments) { throw createClientConfigurationError(urlParseError); } // Throw error if uri is insecure. if (!components.Protocol || components.Protocol.toLowerCase() !== "https:") { throw createClientConfigurationError(authorityUriInsecure); } } /** * Given a url and a query string return the url with provided query string appended * @param url * @param queryString */ static appendQueryString(url, queryString) { if (!queryString) { return url; } return url.indexOf("?") < 0 ? `${url}?${queryString}` : `${url}&${queryString}`; } /** * Returns a url with the