Add extracted source directory and README navigation

This commit is contained in:
Shawn Bot
2026-03-31 14:56:06 +00:00
parent 6252bb6eb5
commit 91e01d755b
4757 changed files with 984951 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
/*! @azure/msal-common v15.13.1 2025-10-29 */
'use strict';
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
async function getClientAssertion(clientAssertion, clientId, tokenEndpoint) {
if (typeof clientAssertion === "string") {
return clientAssertion;
}
else {
const config = {
clientId: clientId,
tokenEndpoint: tokenEndpoint,
};
return clientAssertion(config);
}
}
export { getClientAssertion };
//# sourceMappingURL=ClientAssertionUtils.mjs.map

View File

@@ -0,0 +1,325 @@
/*! @azure/msal-common v15.13.1 2025-10-29 */
'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 = "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",
};
export { AADAuthorityConstants, APP_METADATA, AUTHORITY_METADATA_CONSTANTS, AuthenticationScheme, AuthorityMetadataSource, CLIENT_INFO, CacheAccountType, CacheOutcome, CacheType, ClaimsRequestKeys, CodeChallengeMethodValues, Constants, CredentialType, DEFAULT_TOKEN_RENEWAL_OFFSET_SEC, EncodingTypes, Errors, GrantType, HeaderNames, HttpMethod, HttpStatus, JsonWebTokenTypes, OAuthResponseType, OIDC_DEFAULT_SCOPES, OIDC_SCOPES, ONE_DAY_IN_MS, PasswordGrantConstants, PersistentCacheKeys, PromptValue, RegionDiscoveryOutcomes, RegionDiscoverySources, ResponseMode, SERVER_TELEM_CONSTANTS, Separators, ServerResponseType, THE_FAMILY_ID, ThrottlingConstants };
//# sourceMappingURL=Constants.mjs.map

View File

@@ -0,0 +1,99 @@
/*! @azure/msal-common v15.13.1 2025-10-29 */
'use strict';
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
/**
* Wraps a function with a performance measurement.
* Usage: invoke(functionToCall, performanceClient, "EventName", "correlationId")(...argsToPassToFunction)
* @param callback
* @param eventName
* @param logger
* @param telemetryClient
* @param correlationId
* @returns
* @internal
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const invoke = (callback, eventName, logger, telemetryClient, correlationId) => {
return (...args) => {
logger.trace(`Executing function ${eventName}`);
const inProgressEvent = telemetryClient?.startMeasurement(eventName, correlationId);
if (correlationId) {
// Track number of times this API is called in a single request
const eventCount = eventName + "CallCount";
telemetryClient?.incrementFields({ [eventCount]: 1 }, correlationId);
}
try {
const result = callback(...args);
inProgressEvent?.end({
success: true,
});
logger.trace(`Returning result from ${eventName}`);
return result;
}
catch (e) {
logger.trace(`Error occurred in ${eventName}`);
try {
logger.trace(JSON.stringify(e));
}
catch (e) {
logger.trace("Unable to print error message.");
}
inProgressEvent?.end({
success: false,
}, e);
throw e;
}
};
};
/**
* Wraps an async function with a performance measurement.
* Usage: invokeAsync(functionToCall, performanceClient, "EventName", "correlationId")(...argsToPassToFunction)
* @param callback
* @param eventName
* @param logger
* @param telemetryClient
* @param correlationId
* @returns
* @internal
*
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const invokeAsync = (callback, eventName, logger, telemetryClient, correlationId) => {
return (...args) => {
logger.trace(`Executing function ${eventName}`);
const inProgressEvent = telemetryClient?.startMeasurement(eventName, correlationId);
if (correlationId) {
// Track number of times this API is called in a single request
const eventCount = eventName + "CallCount";
telemetryClient?.incrementFields({ [eventCount]: 1 }, correlationId);
}
telemetryClient?.setPreQueueTime(eventName, correlationId);
return callback(...args)
.then((response) => {
logger.trace(`Returning result from ${eventName}`);
inProgressEvent?.end({
success: true,
});
return response;
})
.catch((e) => {
logger.trace(`Error occurred in ${eventName}`);
try {
logger.trace(JSON.stringify(e));
}
catch (e) {
logger.trace("Unable to print error message.");
}
inProgressEvent?.end({
success: false,
}, e);
throw e;
});
};
};
export { invoke, invokeAsync };
//# sourceMappingURL=FunctionWrappers.mjs.map

View File

@@ -0,0 +1,78 @@
/*! @azure/msal-common v15.13.1 2025-10-29 */
'use strict';
import { Constants } from './Constants.mjs';
import { createClientAuthError } from '../error/ClientAuthError.mjs';
import { noCryptoObject, invalidState } from '../error/ClientAuthErrorCodes.mjs';
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
/**
* Class which provides helpers for OAuth 2.0 protocol specific values
*/
class ProtocolUtils {
/**
* Appends user state with random guid, or returns random guid.
* @param userState
* @param randomGuid
*/
static setRequestState(cryptoObj, userState, meta) {
const libraryState = ProtocolUtils.generateLibraryState(cryptoObj, meta);
return userState
? `${libraryState}${Constants.RESOURCE_DELIM}${userState}`
: libraryState;
}
/**
* Generates the state value used by the common library.
* @param randomGuid
* @param cryptoObj
*/
static generateLibraryState(cryptoObj, meta) {
if (!cryptoObj) {
throw createClientAuthError(noCryptoObject);
}
// Create a state object containing a unique id and the timestamp of the request creation
const stateObj = {
id: cryptoObj.createNewGuid(),
};
if (meta) {
stateObj.meta = meta;
}
const stateString = JSON.stringify(stateObj);
return cryptoObj.base64Encode(stateString);
}
/**
* Parses the state into the RequestStateObject, which contains the LibraryState info and the state passed by the user.
* @param state
* @param cryptoObj
*/
static parseRequestState(cryptoObj, state) {
if (!cryptoObj) {
throw createClientAuthError(noCryptoObject);
}
if (!state) {
throw createClientAuthError(invalidState);
}
try {
// Split the state between library state and user passed state and decode them separately
const splitState = state.split(Constants.RESOURCE_DELIM);
const libraryState = splitState[0];
const userState = splitState.length > 1
? splitState.slice(1).join(Constants.RESOURCE_DELIM)
: Constants.EMPTY_STRING;
const libraryStateString = cryptoObj.base64Decode(libraryState);
const libraryStateObj = JSON.parse(libraryStateString);
return {
userRequestState: userState || Constants.EMPTY_STRING,
libraryState: libraryStateObj,
};
}
catch (e) {
throw createClientAuthError(invalidState);
}
}
}
export { ProtocolUtils };
//# sourceMappingURL=ProtocolUtils.mjs.map

View File

@@ -0,0 +1,100 @@
/*! @azure/msal-common v15.13.1 2025-10-29 */
'use strict';
/*
* 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);
}
}
export { StringUtils };
//# sourceMappingURL=StringUtils.mjs.map

View File

@@ -0,0 +1,76 @@
/*! @azure/msal-common v15.13.1 2025-10-29 */
'use strict';
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
/**
* Utility functions for managing date and time operations.
*/
/**
* return the current time in Unix time (seconds).
*/
function nowSeconds() {
// Date.getTime() returns in milliseconds.
return Math.round(new Date().getTime() / 1000.0);
}
/**
* Converts JS Date object to seconds
* @param date Date
*/
function toSecondsFromDate(date) {
// Convert date to seconds
return date.getTime() / 1000;
}
/**
* Convert seconds to JS Date object. Seconds can be in a number or string format or undefined (will still return a date).
* @param seconds
*/
function toDateFromSeconds(seconds) {
if (seconds) {
return new Date(Number(seconds) * 1000);
}
return new Date();
}
/**
* check if a token is expired based on given UTC time in seconds.
* @param expiresOn
*/
function isTokenExpired(expiresOn, offset) {
// check for access token expiry
const expirationSec = Number(expiresOn) || 0;
const offsetCurrentTimeSec = nowSeconds() + offset;
// If current time + offset is greater than token expiration time, then token is expired.
return offsetCurrentTimeSec > expirationSec;
}
/**
* Checks if a cache entry is expired based on the last updated time and cache retention days.
* @param lastUpdatedAt
* @param cacheRetentionDays
* @returns
*/
function isCacheExpired(lastUpdatedAt, cacheRetentionDays) {
const cacheExpirationTimestamp = Number(lastUpdatedAt) + cacheRetentionDays * 24 * 60 * 60 * 1000;
return Date.now() > cacheExpirationTimestamp;
}
/**
* If the current time is earlier than the time that a token was cached at, we must discard the token
* i.e. The system clock was turned back after acquiring the cached token
* @param cachedAt
* @param offset
*/
function wasClockTurnedBack(cachedAt) {
const cachedAtSec = Number(cachedAt);
return cachedAtSec > nowSeconds();
}
/**
* Waits for t number of milliseconds
* @param t number
* @param value T
*/
function delay(t, value) {
return new Promise((resolve) => setTimeout(() => resolve(value), t));
}
export { delay, isCacheExpired, isTokenExpired, nowSeconds, toDateFromSeconds, toSecondsFromDate, wasClockTurnedBack };
//# sourceMappingURL=TimeUtils.mjs.map

View File

@@ -0,0 +1,122 @@
/*! @azure/msal-common v15.13.1 2025-10-29 */
'use strict';
import { createClientAuthError } from '../error/ClientAuthError.mjs';
import { StringUtils } from './StringUtils.mjs';
import { hashNotDeserialized } from '../error/ClientAuthErrorCodes.mjs';
/*
* 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);
}
}
export { getDeserializedResponse, mapToQueryString, normalizeUrlForComparison, stripLeadingHashOrQuery };
//# sourceMappingURL=UrlUtils.mjs.map