@asgardeo/javascript
Version:
Framework agnostic JavaScript SDK for Asgardeo.
1,334 lines (1,315 loc) • 150 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
// src/StorageManager.ts
var ASGARDEO_SESSION_ACTIVE = "asgardeo-session-active";
var StorageManager = class {
constructor(instanceID, store) {
__publicField(this, "_id");
__publicField(this, "_store");
this._id = instanceID;
this._store = store;
}
async setDataInBulk(key, data) {
const existingDataJSON = await this._store.getData(key) ?? null;
const existingData = existingDataJSON && JSON.parse(existingDataJSON);
const dataToBeSaved = { ...existingData, ...data };
const dataToBeSavedJSON = JSON.stringify(dataToBeSaved);
await this._store.setData(key, dataToBeSavedJSON);
}
async setValue(key, attribute, value) {
const existingDataJSON = await this._store.getData(key) ?? null;
const existingData = existingDataJSON && JSON.parse(existingDataJSON);
const dataToBeSaved = { ...existingData, [attribute]: value };
const dataToBeSavedJSON = JSON.stringify(dataToBeSaved);
await this._store.setData(key, dataToBeSavedJSON);
}
async removeValue(key, attribute) {
const existingDataJSON = await this._store.getData(key) ?? null;
const existingData = existingDataJSON && JSON.parse(existingDataJSON);
const dataToBeSaved = { ...existingData };
delete dataToBeSaved[attribute];
const dataToBeSavedJSON = JSON.stringify(dataToBeSaved);
await this._store.setData(key, dataToBeSavedJSON);
}
_resolveKey(store, userId) {
return userId ? `${store}-${this._id}-${userId}` : `${store}-${this._id}`;
}
isLocalStorageAvailable() {
try {
const testValue = "__ASGARDEO_AUTH_CORE_LOCAL_STORAGE_TEST__";
localStorage.setItem(testValue, testValue);
localStorage.removeItem(testValue);
return true;
} catch (error2) {
return false;
}
}
async setConfigData(config) {
await this.setDataInBulk(this._resolveKey("config_data" /* ConfigData */), config);
}
async setOIDCProviderMetaData(oidcProviderMetaData) {
this.setDataInBulk(this._resolveKey("oidc_provider_meta_data" /* OIDCProviderMetaData */), oidcProviderMetaData);
}
async setTemporaryData(temporaryData, userId) {
this.setDataInBulk(this._resolveKey("temporary_data" /* TemporaryData */, userId), temporaryData);
}
async setSessionData(sessionData, userId) {
this.setDataInBulk(this._resolveKey("session_data" /* SessionData */, userId), sessionData);
}
async setCustomData(key, customData, userId) {
this.setDataInBulk(this._resolveKey(key, userId), customData);
}
async getConfigData(userId) {
return JSON.parse(await this._store.getData(this._resolveKey("config_data" /* ConfigData */, userId)) ?? null);
}
async loadOpenIDProviderConfiguration() {
return JSON.parse(await this._store.getData(this._resolveKey("oidc_provider_meta_data" /* OIDCProviderMetaData */)) ?? null);
}
async getTemporaryData(userId) {
return JSON.parse(await this._store.getData(this._resolveKey("temporary_data" /* TemporaryData */, userId)) ?? null);
}
async getSessionData(userId) {
return JSON.parse(await this._store.getData(this._resolveKey("session_data" /* SessionData */, userId)) ?? null);
}
async getCustomData(key, userId) {
return JSON.parse(await this._store.getData(this._resolveKey(key, userId)) ?? null);
}
setSessionStatus(status) {
this.isLocalStorageAvailable() && localStorage.setItem(`${ASGARDEO_SESSION_ACTIVE}`, status);
}
getSessionStatus() {
return this.isLocalStorageAvailable() ? localStorage.getItem(`${ASGARDEO_SESSION_ACTIVE}`) ?? "" : "";
}
removeSessionStatus() {
this.isLocalStorageAvailable() && localStorage.removeItem(`${ASGARDEO_SESSION_ACTIVE}`);
}
async removeConfigData() {
await this._store.removeData(this._resolveKey("config_data" /* ConfigData */));
}
async removeOIDCProviderMetaData() {
await this._store.removeData(this._resolveKey("oidc_provider_meta_data" /* OIDCProviderMetaData */));
}
async removeTemporaryData(userId) {
await this._store.removeData(this._resolveKey("temporary_data" /* TemporaryData */, userId));
}
async removeSessionData(userId) {
await this._store.removeData(this._resolveKey("session_data" /* SessionData */, userId));
}
async getConfigDataParameter(key) {
const data = await this._store.getData(this._resolveKey("config_data" /* ConfigData */));
return data && JSON.parse(data)[key];
}
async getOIDCProviderMetaDataParameter(key) {
const data = await this._store.getData(this._resolveKey("oidc_provider_meta_data" /* OIDCProviderMetaData */));
return data && JSON.parse(data)[key];
}
async getTemporaryDataParameter(key, userId) {
const data = await this._store.getData(this._resolveKey("temporary_data" /* TemporaryData */, userId));
return data && JSON.parse(data)[key];
}
async getSessionDataParameter(key, userId) {
const data = await this._store.getData(this._resolveKey("session_data" /* SessionData */, userId));
return data && JSON.parse(data)[key];
}
async setConfigDataParameter(key, value) {
await this.setValue(this._resolveKey("config_data" /* ConfigData */), key, value);
}
async setOIDCProviderMetaDataParameter(key, value) {
await this.setValue(this._resolveKey("oidc_provider_meta_data" /* OIDCProviderMetaData */), key, value);
}
async setTemporaryDataParameter(key, value, userId) {
await this.setValue(this._resolveKey("temporary_data" /* TemporaryData */, userId), key, value);
}
async setSessionDataParameter(key, value, userId) {
await this.setValue(this._resolveKey("session_data" /* SessionData */, userId), key, value);
}
async removeConfigDataParameter(key) {
await this.removeValue(this._resolveKey("config_data" /* ConfigData */), key);
}
async removeOIDCProviderMetaDataParameter(key) {
await this.removeValue(this._resolveKey("oidc_provider_meta_data" /* OIDCProviderMetaData */), key);
}
async removeTemporaryDataParameter(key, userId) {
await this.removeValue(this._resolveKey("temporary_data" /* TemporaryData */, userId), key);
}
async removeSessionDataParameter(key, userId) {
await this.removeValue(this._resolveKey("session_data" /* SessionData */, userId), key);
}
};
var StorageManager_default = StorageManager;
// src/constants/OIDCDiscoveryConstants.ts
var OIDCDiscoveryConstants = {
/**
* Collection of standard OIDC endpoint paths used for authentication flows.
* These endpoints are relative paths that should be appended to the base URL
* of your identity provider.
*/
Endpoints: {
/**
* Authorization endpoint for initiating the OAuth2/OIDC flow.
* This endpoint is used to request authorization and receive an authorization code.
*/
AUTHORIZATION: "/oauth2/authorize",
/**
* Session check iframe endpoint for session management.
* Used to monitor the user's session state through a hidden iframe.
*/
SESSION_IFRAME: "/oidc/checksession",
/**
* End session endpoint for logout functionality.
* Used to terminate the user's session and perform logout operations.
*/
END_SESSION: "/oidc/logout",
/**
* Token issuer endpoint.
* The endpoint that issues OAuth2/OIDC tokens.
*/
ISSUER: "/oauth2/token",
/**
* JSON Web Key Set endpoint for key validation.
* Provides the public keys used to verify token signatures.
*/
JWKS: "/oauth2/jwks",
/**
* Token revocation endpoint.
* Used to invalidate access or refresh tokens before they expire.
*/
REVOCATION: "/oauth2/revoke",
/**
* Token endpoint for obtaining access tokens.
* Used to exchange authorization codes for access tokens and refresh tokens.
*/
TOKEN: "/oauth2/token",
/**
* UserInfo endpoint for obtaining user claims.
* Provides authenticated user information when called with a valid access token.
*/
USERINFO: "/oauth2/userinfo"
},
/**
* Storage related constants used for maintaining OIDC state.
* These constants define the keys used to store OIDC-related data
* in the browser's storage mechanisms.
*/
Storage: {
/**
* Storage keys for various OIDC endpoints and configurations.
* These keys are used to store endpoint URLs and configuration
* states in the browser's storage.
*/
StorageKeys: {
/**
* Collection of storage keys for OIDC endpoints.
* These keys are used to store the discovered endpoint URLs
* from the OpenID Provider's configuration.
*/
Endpoints: {
/**
* Storage key for the authorization endpoint URL.
* Used to store the URL where authorization requests should be sent.
*/
AUTHORIZATION: "authorization_endpoint",
/**
* Storage key for the token endpoint URL.
* Used to store the URL where token requests should be sent.
*/
TOKEN: "token_endpoint",
/**
* Storage key for the revocation endpoint URL.
* Used to store the URL where token revocation requests should be sent.
*/
REVOCATION: "revocation_endpoint",
/**
* Storage key for the end session endpoint URL.
* Used to store the URL where logout requests should be sent.
*/
END_SESSION: "end_session_endpoint",
/**
* Storage key for the JWKS URI endpoint URL.
* Used to store the URL where JSON Web Key Sets can be retrieved.
*/
JWKS: "jwks_uri",
/**
* Storage key for the session check iframe URL.
* Used to store the URL of the iframe used for session state monitoring.
*/
SESSION_IFRAME: "check_session_iframe",
/**
* Storage key for the issuer identifier URL.
* Used to store the URL that identifies the OpenID Provider.
*/
ISSUER: "issuer",
/**
* Storage key for the userinfo endpoint URL.
* Used to store the URL where user information can be retrieved.
*/
USERINFO: "userinfo_endpoint"
},
/**
* Flag to track if OpenID Provider configuration is initiated.
* Used to determine if the OIDC discovery process has been started.
* This helps prevent duplicate initialization attempts.
*/
OPENID_PROVIDER_CONFIG_INITIATED: "op_config_initiated"
}
}
};
var OIDCDiscoveryConstants_default = OIDCDiscoveryConstants;
// src/constants/ScopeConstants.ts
var ScopeConstants = {
/**
* The scope for accessing the user's profile information from SCIM.
* This scope allows the client to retrieve basic user information such as
* name, email, profile picture, etc.
*/
INTERNAL_LOGIN: "internal_login",
/**
* The base OpenID Connect scope.
* Required for all OpenID Connect flows. Indicates that the client
* is initiating an OpenID Connect authentication request.
*/
OPENID: "openid",
/**
* The OpenID Connect profile scope.
* This scope allows the client to access the user's profile information.
* It includes details such as the user's name, email, and other profile attributes.
*/
PROFILE: "profile"
};
var ScopeConstants_default = ScopeConstants;
// src/constants/OIDCRequestConstants.ts
var OIDCRequestConstants = {
Params: {
/**
* The authorization code returned from the authorization endpoint.
* Used in the authorization code flow.
*/
AUTHORIZATION_CODE: "code",
/**
* Session state parameter used for session management between the client and the OP.
*/
SESSION_STATE: "session_state",
/**
* State parameter used to maintain state between the request and the callback.
* Helps in preventing CSRF attacks.
*/
STATE: "state",
/**
* Indicates whether sign-out was successful during the end-session flow.
* May be returned by the OP after a logout request.
*/
SIGN_OUT_SUCCESS: "sign_out_success"
},
/**
* Constants related to the OpenID Connect (OIDC) sign-in flow.
*/
SignIn: {
/**
* Constants related to the payload of the OIDC sign-in request.
*/
Payload: {
/**
* The default scopes used in OIDC sign-in requests.
*/
DEFAULT_SCOPES: [ScopeConstants_default.OPENID, ScopeConstants_default.PROFILE, ScopeConstants_default.INTERNAL_LOGIN]
}
},
/**
* Sign-out related constants for managing the end-session flow in OIDC.
*/
SignOut: {
/**
* Storage-related constants for managing sign-out state.
*/
Storage: {
/**
* Collection of storage keys used in sign-out implementation
*/
StorageKeys: {
/**
* Storage key for the sign-out URL.
* Used to store the complete URL where the user should be redirected after
* completing the OIDC logout process.
*/
SIGN_OUT_URL: "sign_out_url"
}
}
}
};
var OIDCRequestConstants_default = OIDCRequestConstants;
// src/errors/exception.ts
var AsgardeoAuthException = class {
constructor(code, name, message) {
__publicField(this, "name");
__publicField(this, "code");
__publicField(this, "message");
this.message = message;
this.name = name;
this.code = code;
Object.setPrototypeOf(this, new.target.prototype);
}
};
// src/constants/TokenConstants.ts
var TokenConstants = {
/**
* Token signature validation constants.
* Contains configurations related to token signature verification.
*/
SignatureValidation: {
/**
* Fallback array of supported signature algorithms for OIDC token validation.
* These values are used when the supported algorithms cannot be retrieved from
* the .well-known/openid-configuration endpoint.
*
* Supported algorithms:
* - `RS256` - RSASSA-PKCS1-v1_5 using SHA-256
* - `RS512` - RSASSA-PKCS1-v1_5 using SHA-512
* - `RS384` - RSASSA-PKCS1-v1_5 using SHA-384
* - `PS256` - RSASSA-PSS using SHA-256 and MGF1 with SHA-256
*/
SUPPORTED_ALGORITHMS: ["RS256", "RS512", "RS384", "PS256"]
},
/**
* Storage-related constants for OIDC tokens.
* Contains keys used to store token-related data in browser storage.
*/
Storage: {
/**
* Collection of storage keys used in token management.
* These keys are used to store and retrieve token-related
* information from browser storage.
*/
StorageKeys: {
/**
* Key used to store the refresh token timer identifier.
* This timer is used to schedule token refresh operations
* before the current token expires.
*/
REFRESH_TOKEN_TIMER: "refresh_token_timer"
}
}
};
var TokenConstants_default = TokenConstants;
// src/IsomorphicCrypto.ts
var IsomorphicCrypto = class {
constructor(cryptoUtils) {
__publicField(this, "_cryptoUtils");
this._cryptoUtils = cryptoUtils;
}
/**
* Generate code verifier.
*
* @returns code verifier.
*/
getCodeVerifier() {
return this._cryptoUtils.base64URLEncode(this._cryptoUtils.generateRandomBytes(32));
}
/**
* Derive code challenge from the code verifier.
*
* @param verifier - Code verifier.
*
* @returns - code challenge.
*/
getCodeChallenge(verifier) {
return this._cryptoUtils.base64URLEncode(this._cryptoUtils.hashSha256(verifier));
}
/**
* Get JWK used for the id_token
*
* @param jwtHeader - header of the id_token.
* @param keys - jwks response.
*
* @returns public key.
*
* @throws
*/
/* eslint-disable @typescript-eslint/no-explicit-any */
getJWKForTheIdToken(jwtHeader, keys) {
const headerJSON = JSON.parse(this._cryptoUtils.base64URLDecode(jwtHeader));
for (const key of keys) {
if (headerJSON["kid"] === key.kid) {
return key;
}
}
throw new AsgardeoAuthException(
"JS-CRYPTO_UTIL-GJFTIT-IV01",
"kid not found.",
"Failed to find the 'kid' specified in the id_token. 'kid' found in the header : " + headerJSON["kid"] + ", Expected values: " + keys.map((key) => key.kid).join(", ")
);
}
/**
* Verify id token.
*
* @param idToken - id_token received from the IdP.
* @param jwk - public key used for signing.
* @param clientId - app identification.
* @param issuer - id_token issuer.
* @param username - Username.
* @param clockTolerance - Allowed leeway for id_tokens (in seconds).
*
* @returns whether the id_token is valid.
*
* @throws
*/
isValidIdToken(idToken, jwk, clientId, issuer, username, clockTolerance, validateJwtIssuer) {
return this._cryptoUtils.verifyJwt(
idToken,
jwk,
TokenConstants_default.SignatureValidation.SUPPORTED_ALGORITHMS,
clientId,
issuer,
username,
clockTolerance,
validateJwtIssuer
).then((response) => {
if (response) {
return Promise.resolve(true);
}
return Promise.reject(
new AsgardeoAuthException(
"JS-CRYPTO_HELPER-IVIT-IV01",
"Invalid ID token.",
"ID token validation returned false"
)
);
});
}
/**
* This function decodes the payload of an id token and returns it.
*
* @param idToken - The id token to be decoded.
*
* @returns - The decoded payload of the id token.
*
* @throws
*/
decodeIdToken(idToken) {
try {
const utf8String = this._cryptoUtils.base64URLDecode(idToken?.split(".")[1]);
const payload = JSON.parse(utf8String);
return payload;
} catch (error2) {
throw new AsgardeoAuthException("JS-CRYPTO_UTIL-DIT-IV01", "Decoding ID token failed.", error2);
}
}
};
// src/constants/PKCEConstants.ts
var PKCEConstants = {
DEFAULT_CODE_CHALLENGE_METHOD: "S256",
/**
* Storage-related constants for managing PKCE state
*/
Storage: {
/**
* Collection of storage keys used in PKCE implementation
*/
StorageKeys: {
/**
* Key used to store the PKCE code verifier in temporary storage.
* The code verifier is a cryptographically random string that is
* used to generate the code challenge.
*/
CODE_VERIFIER: "pkce_code_verifier",
/**
* Separator used in storage keys to create unique identifiers
* by combining different parts of the key.
*/
SEPARATOR: "#"
}
}
};
var PKCEConstants_default = PKCEConstants;
// src/utils/extractPkceStorageKeyFromState.ts
var extractPkceStorageKeyFromState = (state) => {
const index = parseInt(state.split("request_")[1]);
return `${PKCEConstants_default.Storage.StorageKeys.CODE_VERIFIER}${PKCEConstants_default.Storage.StorageKeys.SEPARATOR}${index}`;
};
var extractPkceStorageKeyFromState_default = extractPkceStorageKeyFromState;
// src/constants/TokenExchangeConstants.ts
var TokenExchangeConstants = {
/**
* Collection of placeholder strings used in token exchange operations.
* These placeholders are replaced with actual values when processing
* token exchange requests.
*/
Placeholders: {
/**
* Placeholder for the token value in exchange requests.
* Usually replaced with an access token or refresh token.
*/
ACCESS_TOKEN: "{{accessToken}}",
/**
* Placeholder for the username in token exchange operations.
* Used when user identity needs to be included in the exchange.
*/
USERNAME: "{{username}}",
/**
* Placeholder for OAuth scopes in token exchange requests.
* Replaced with space-separated scope strings.
*/
SCOPES: "{{scopes}}",
/**
* Placeholder for client ID in token exchange operations.
* Required for client authentication.
*/
CLIENT_ID: "{{clientId}}",
/**
* Placeholder for client secret in token exchange operations.
* Used for client authentication in confidential client flows.
*/
CLIENT_SECRET: "{{clientSecret}}"
}
};
var TokenExchangeConstants_default = TokenExchangeConstants;
// src/utils/extractUserClaimsFromIdToken.ts
var extractUserClaimsFromIdToken = (payload) => {
const filteredPayload = { ...payload };
const protocolClaims = [
"iss",
"aud",
"exp",
"iat",
"acr",
"amr",
"azp",
"auth_time",
"nonce",
"c_hash",
"at_hash",
"nbf",
"isk",
"sid",
"jti",
"sub"
];
protocolClaims.forEach((claim) => {
delete filteredPayload[claim];
});
const userClaims = {};
Object.entries(filteredPayload).forEach(([key, value]) => {
const camelCasedKey = key.split("_").map((part, i) => i === 0 ? part : part[0].toUpperCase() + part.slice(1)).join("");
userClaims[camelCasedKey] = value;
});
return userClaims;
};
var extractUserClaimsFromIdToken_default = extractUserClaimsFromIdToken;
// src/errors/AsgardeoError.ts
var AsgardeoError = class _AsgardeoError extends Error {
constructor(message, code, origin) {
const _origin = _AsgardeoError.resolveOrigin(origin);
super(message);
__publicField(this, "code");
__publicField(this, "origin");
this.name = new.target.name;
this.code = code;
this.origin = _origin;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, new.target);
}
}
static resolveOrigin(origin) {
if (!origin) {
return "@asgardeo/javascript";
}
return `@asgardeo/${origin}`;
}
toString() {
const prefix = `\u{1F6E1}\uFE0F Asgardeo - ${this.origin}:`;
return `[${this.name}]
${prefix} ${this.message}
(code="${this.code}")`;
}
};
// src/errors/AsgardeoRuntimeError.ts
var AsgardeoRuntimeError = class extends AsgardeoError {
/**
* Creates an instance of AsgardeoRuntimeError.
*
* @param message - Human-readable description of the error
* @param code - A unique error code that identifies the error type
* @param details - Additional details about the error that might be helpful for debugging
* @param origin - Optional. The SDK origin (e.g. 'react', 'vue'). Defaults to generic 'Asgardeo'
* @constructor
*/
constructor(message, code, origin, details) {
super(message, code, origin);
this.details = details;
Object.defineProperty(this, "name", {
value: "AsgardeoRuntimeError",
configurable: true,
writable: true
});
}
/**
* Returns a string representation of the runtime error
* @returns Formatted error string with name, code, details, and message
*/
toString() {
const details = this.details ? `
Details: ${JSON.stringify(this.details, null, 2)}` : "";
return `[${this.name}] (code="${this.code}")${details}
Message: ${this.message}`;
}
};
// src/utils/processOpenIDScopes.ts
var processOpenIDScopes = (scopes) => {
let processedScopes = [];
if (scopes) {
if (Array.isArray(scopes)) {
processedScopes = scopes;
} else if (typeof scopes === "string") {
processedScopes = scopes.split(" ");
} else {
throw new AsgardeoRuntimeError(
"Scopes must be a string or an array of strings.",
"processOpenIDScopes-Invalid-001",
"javascript",
"The provided scopes are not in the expected format. Please provide a string or an array of strings."
);
}
}
OIDCRequestConstants_default.SignIn.Payload.DEFAULT_SCOPES.forEach((defaultScope) => {
if (!processedScopes.includes(defaultScope)) {
processedScopes.push(defaultScope);
}
});
return processedScopes.join(" ");
};
var processOpenIDScopes_default = processOpenIDScopes;
// src/__legacy__/helpers/authentication-helper.ts
var AuthenticationHelper = class {
constructor(storageManager, cryptoHelper) {
__publicField(this, "_storageManager");
__publicField(this, "_config");
__publicField(this, "_oidcProviderMetaData");
__publicField(this, "_cryptoHelper");
this._storageManager = storageManager;
this._config = async () => this._storageManager.getConfigData();
this._oidcProviderMetaData = async () => this._storageManager.loadOpenIDProviderConfiguration();
this._cryptoHelper = cryptoHelper;
}
async resolveEndpoints(response) {
const oidcProviderMetaData = {};
const configData = await this._config();
configData.endpoints && Object.keys(configData.endpoints).forEach((endpointName) => {
const snakeCasedName = endpointName.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
oidcProviderMetaData[snakeCasedName] = configData?.endpoints ? configData.endpoints[endpointName] : "";
});
return { ...response, ...oidcProviderMetaData };
}
async resolveEndpointsExplicitly() {
const oidcProviderMetaData = {};
const configData = await this._config();
const requiredEndpoints = [
OIDCDiscoveryConstants_default.Storage.StorageKeys.Endpoints.AUTHORIZATION,
OIDCDiscoveryConstants_default.Storage.StorageKeys.Endpoints.END_SESSION,
OIDCDiscoveryConstants_default.Storage.StorageKeys.Endpoints.JWKS,
OIDCDiscoveryConstants_default.Storage.StorageKeys.Endpoints.SESSION_IFRAME,
OIDCDiscoveryConstants_default.Storage.StorageKeys.Endpoints.REVOCATION,
OIDCDiscoveryConstants_default.Storage.StorageKeys.Endpoints.TOKEN,
OIDCDiscoveryConstants_default.Storage.StorageKeys.Endpoints.ISSUER,
OIDCDiscoveryConstants_default.Storage.StorageKeys.Endpoints.USERINFO
];
const isRequiredEndpointsContains = configData.endpoints ? requiredEndpoints.every(
(reqEndpointName) => configData.endpoints ? Object.keys(configData.endpoints).some((endpointName) => {
const snakeCasedName = endpointName.replace(
/[A-Z]/g,
(letter) => `_${letter.toLowerCase()}`
);
return snakeCasedName === reqEndpointName;
}) : false
) : false;
if (!isRequiredEndpointsContains) {
throw new AsgardeoAuthException(
"JS-AUTH_HELPER-REE-NF01",
"Required endpoints missing",
"Some or all of the required endpoints are missing in the object passed to the `endpoints` attribute of the`AuthConfig` object."
);
}
configData.endpoints && Object.keys(configData.endpoints).forEach((endpointName) => {
const snakeCasedName = endpointName.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
oidcProviderMetaData[snakeCasedName] = configData?.endpoints ? configData.endpoints[endpointName] : "";
});
return { ...oidcProviderMetaData };
}
async resolveEndpointsByBaseURL() {
const oidcProviderMetaData = {};
const configData = await this._config();
const { baseUrl } = configData;
if (!baseUrl) {
throw new AsgardeoAuthException(
"JS-AUTH_HELPER_REBO-NF01",
"Base URL not defined.",
"Base URL is not defined in AuthClient config."
);
}
configData.endpoints && Object.keys(configData.endpoints).forEach((endpointName) => {
const snakeCasedName = endpointName.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
oidcProviderMetaData[snakeCasedName] = configData?.endpoints ? configData.endpoints[endpointName] : "";
});
const defaultEndpoints = {
[OIDCDiscoveryConstants_default.Storage.StorageKeys.Endpoints.AUTHORIZATION]: `${baseUrl}${OIDCDiscoveryConstants_default.Endpoints.AUTHORIZATION}`,
[OIDCDiscoveryConstants_default.Storage.StorageKeys.Endpoints.END_SESSION]: `${baseUrl}${OIDCDiscoveryConstants_default.Endpoints.END_SESSION}`,
[OIDCDiscoveryConstants_default.Storage.StorageKeys.Endpoints.ISSUER]: `${baseUrl}${OIDCDiscoveryConstants_default.Endpoints.ISSUER}`,
[OIDCDiscoveryConstants_default.Storage.StorageKeys.Endpoints.JWKS]: `${baseUrl}${OIDCDiscoveryConstants_default.Endpoints.JWKS}`,
[OIDCDiscoveryConstants_default.Storage.StorageKeys.Endpoints.SESSION_IFRAME]: `${baseUrl}${OIDCDiscoveryConstants_default.Endpoints.SESSION_IFRAME}`,
[OIDCDiscoveryConstants_default.Storage.StorageKeys.Endpoints.REVOCATION]: `${baseUrl}${OIDCDiscoveryConstants_default.Endpoints.REVOCATION}`,
[OIDCDiscoveryConstants_default.Storage.StorageKeys.Endpoints.TOKEN]: `${baseUrl}${OIDCDiscoveryConstants_default.Endpoints.TOKEN}`,
[OIDCDiscoveryConstants_default.Storage.StorageKeys.Endpoints.USERINFO]: `${baseUrl}${OIDCDiscoveryConstants_default.Endpoints.USERINFO}`
};
return { ...defaultEndpoints, ...oidcProviderMetaData };
}
async validateIdToken(idToken) {
const jwksEndpoint = (await this._storageManager.loadOpenIDProviderConfiguration()).jwks_uri;
const configData = await this._config();
if (!jwksEndpoint || jwksEndpoint.trim().length === 0) {
throw new AsgardeoAuthException(
"JS_AUTH_HELPER-VIT-NF01",
"JWKS endpoint not found.",
"No JWKS endpoint was found in the OIDC provider meta data returned by the well-known endpoint or the JWKS endpoint passed to the SDK is empty."
);
}
let response;
try {
response = await fetch(jwksEndpoint, {
credentials: configData.sendCookiesInRequests ? "include" : "same-origin"
});
} catch (error2) {
throw new AsgardeoAuthException(
"JS-AUTH_HELPER-VIT-NE02",
"Request to jwks endpoint failed.",
error2 ?? "The request sent to get the jwks from the server failed."
);
}
if (response.status !== 200 || !response.ok) {
throw new AsgardeoAuthException(
"JS-AUTH_HELPER-VIT-HE03",
`Invalid response status received for jwks request (${response.statusText}).`,
await response.json()
);
}
const { issuer } = await this._oidcProviderMetaData();
const { keys } = await response.json();
const jwk = await this._cryptoHelper.getJWKForTheIdToken(idToken.split(".")[0], keys);
return this._cryptoHelper.isValidIdToken(
idToken,
jwk,
(await this._config()).clientId,
issuer ?? "",
this._cryptoHelper.decodeIdToken(idToken).sub,
(await this._config()).tokenValidation?.idToken?.clockTolerance,
(await this._config()).tokenValidation?.idToken?.validateIssuer ?? true
);
}
getAuthenticatedUserInfo(idToken) {
const payload = this._cryptoHelper.decodeIdToken(idToken);
const username = payload?.["username"] ?? "";
const givenName = payload?.["given_name"] ?? "";
const familyName = payload?.["family_name"] ?? "";
const fullName = givenName && familyName ? `${givenName} ${familyName}` : givenName || familyName || "";
const displayName = payload.preferred_username ?? fullName;
return {
displayName,
username,
...extractUserClaimsFromIdToken_default(payload)
};
}
async replaceCustomGrantTemplateTags(text, userId) {
const configData = await this._config();
const sessionData = await this._storageManager.getSessionData(userId);
const scope = processOpenIDScopes_default(configData.scopes);
if (typeof text !== "string") {
return text;
}
return text.replace(TokenExchangeConstants_default.Placeholders.ACCESS_TOKEN, sessionData.access_token).replace(
TokenExchangeConstants_default.Placeholders.USERNAME,
this.getAuthenticatedUserInfo(sessionData.id_token).username
).replace(TokenExchangeConstants_default.Placeholders.SCOPES, scope).replace(TokenExchangeConstants_default.Placeholders.CLIENT_ID, configData.clientId).replace(TokenExchangeConstants_default.Placeholders.CLIENT_SECRET, configData.clientSecret ?? "");
}
async clearSession(userId) {
await this._storageManager.removeTemporaryData(userId);
await this._storageManager.removeSessionData(userId);
}
async handleTokenResponse(response, userId) {
if (response.status !== 200 || !response.ok) {
throw new AsgardeoAuthException(
"JS-AUTH_HELPER-HTR-NE01",
`Invalid response status received for token request (${response.statusText}).`,
await response.json()
);
}
const parsedResponse = await response.json();
parsedResponse.created_at = (/* @__PURE__ */ new Date()).getTime();
const shouldValidateIdToken = (await this._config()).tokenValidation?.idToken?.validate;
if (shouldValidateIdToken) {
return this.validateIdToken(parsedResponse.id_token).then(async () => {
await this._storageManager.setSessionData(parsedResponse, userId);
const tokenResponse2 = {
accessToken: parsedResponse.access_token,
createdAt: parsedResponse.created_at,
expiresIn: parsedResponse.expires_in,
idToken: parsedResponse.id_token,
refreshToken: parsedResponse.refresh_token,
scope: parsedResponse.scope,
tokenType: parsedResponse.token_type
};
return Promise.resolve(tokenResponse2);
});
}
const tokenResponse = {
accessToken: parsedResponse.access_token,
createdAt: parsedResponse.created_at,
expiresIn: parsedResponse.expires_in,
idToken: parsedResponse.id_token,
refreshToken: parsedResponse.refresh_token,
scope: parsedResponse.scope,
tokenType: parsedResponse.token_type
};
await this._storageManager.setSessionData(parsedResponse, userId);
return Promise.resolve(tokenResponse);
}
};
// src/utils/generatePkceStorageKey.ts
var generatePkceStorageKey = (tempStore) => {
const keys = [];
Object.keys(tempStore).forEach((key) => {
if (key.startsWith(PKCEConstants_default.Storage.StorageKeys.CODE_VERIFIER)) {
keys.push(key);
}
});
const lastKey = keys.sort().pop();
const index = parseInt(lastKey?.split(PKCEConstants_default.Storage.StorageKeys.SEPARATOR)[1] ?? "-1");
return `${PKCEConstants_default.Storage.StorageKeys.CODE_VERIFIER}${PKCEConstants_default.Storage.StorageKeys.SEPARATOR}${index + 1}`;
};
var generatePkceStorageKey_default = generatePkceStorageKey;
// src/utils/generateStateParamForRequestCorrelation.ts
var generateStateParamForRequestCorrelation = (pkceKey, state) => {
const index = parseInt(pkceKey.split(PKCEConstants_default.Storage.StorageKeys.SEPARATOR)[1]);
return state ? `${state}_request_${index}` : `request_${index}`;
};
var generateStateParamForRequestCorrelation_default = generateStateParamForRequestCorrelation;
// src/utils/getAuthorizeRequestUrlParams.ts
var getAuthorizeRequestUrlParams = (options, pkceOptions, customParams) => {
const { redirectUri, clientId, clientSecret, scopes, responseMode, codeChallenge, codeChallengeMethod, prompt } = options;
const authorizeRequestParams = /* @__PURE__ */ new Map();
authorizeRequestParams.set("response_type", "code");
authorizeRequestParams.set("client_id", clientId);
authorizeRequestParams.set("scope", scopes);
authorizeRequestParams.set("redirect_uri", redirectUri);
if (responseMode) {
authorizeRequestParams.set("response_mode", responseMode);
}
const pkceKey = pkceOptions?.key;
if (codeChallenge) {
authorizeRequestParams.set("code_challenge", codeChallenge);
if (codeChallengeMethod) {
authorizeRequestParams.set("code_challenge_method", codeChallengeMethod);
} else {
throw new AsgardeoRuntimeError(
"Code challenge method is required when code challenge is provided.",
"getAuthorizeRequestUrlParams-ValidationError-001",
"javascript",
"When PKCE is enabled, the code challenge method must be provided along with the code challenge."
);
}
}
if (prompt) {
authorizeRequestParams.set("prompt", prompt);
}
if (customParams) {
for (const [key, value] of Object.entries(customParams)) {
if (key !== "" && value !== "" && key !== OIDCRequestConstants_default.Params.STATE) {
authorizeRequestParams.set(key, value.toString());
}
}
}
authorizeRequestParams.set(
OIDCRequestConstants_default.Params.STATE,
generateStateParamForRequestCorrelation_default(
pkceKey,
customParams ? customParams[OIDCRequestConstants_default.Params.STATE]?.toString() : ""
)
);
return authorizeRequestParams;
};
var getAuthorizeRequestUrlParams_default = getAuthorizeRequestUrlParams;
// src/__legacy__/client.ts
var DefaultConfig = {
tokenValidation: {
idToken: {
validate: true,
validateIssuer: true,
clockTolerance: 300
}
},
enablePKCE: true,
responseMode: "query",
sendCookiesInRequests: true
};
var _AsgardeoAuthClient = class _AsgardeoAuthClient {
/**
* This is the constructor method that returns an instance of the .
*
* @param store - The store object.
*
* @example
* ```
* const _store: Store = new DataStore();
* const auth = new AsgardeoAuthClient<CustomClientConfig>(_store);
* ```
*
* {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#constructor}
*
* @preserve
*/
constructor() {
__publicField(this, "_storageManager");
__publicField(this, "_config");
__publicField(this, "_oidcProviderMetaData");
__publicField(this, "_authenticationHelper");
__publicField(this, "_cryptoUtils");
__publicField(this, "_cryptoHelper");
}
/**
*
* This method initializes the SDK with the config data.
*
* @param config - The config object to initialize with.
*
* @example
* const config = \{
* afterSignInUrl: "http://localhost:3000/sign-in",
* clientId: "client ID",
* baseUrl: "https://localhost:9443"
* \}
*
* await auth.initialize(config);
*
* {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#initialize}
*
* @preserve
*/
async initialize(config, store, cryptoUtils, instanceID) {
const clientId = config.clientId;
if (!_AsgardeoAuthClient._instanceID) {
_AsgardeoAuthClient._instanceID = 0;
} else {
_AsgardeoAuthClient._instanceID += 1;
}
if (instanceID) {
_AsgardeoAuthClient._instanceID = instanceID;
}
if (!clientId) {
this._storageManager = new StorageManager_default(`instance_${_AsgardeoAuthClient._instanceID}`, store);
} else {
this._storageManager = new StorageManager_default(`instance_${_AsgardeoAuthClient._instanceID}-${clientId}`, store);
}
this._cryptoUtils = cryptoUtils;
this._cryptoHelper = new IsomorphicCrypto(cryptoUtils);
this._authenticationHelper = new AuthenticationHelper(this._storageManager, this._cryptoHelper);
this._config = async () => await this._storageManager.getConfigData();
this._oidcProviderMetaData = async () => await this._storageManager.loadOpenIDProviderConfiguration();
_AsgardeoAuthClient._authenticationHelper = this._authenticationHelper;
await this._storageManager.setConfigData({
...DefaultConfig,
...config,
scope: processOpenIDScopes_default(config.scopes)
});
}
/**
* This method returns the `StorageManager` object that allows you to access authentication data.
*
* @returns - The `StorageManager` object.
*
* @example
* ```
* const data = auth.getStorageManager();
* ```
*
* {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#getStorageManager}
*
* @preserve
*/
getStorageManager() {
return this._storageManager;
}
/**
* This method returns the `instanceID` variable of the given instance.
*
* @returns - The `instanceID` number.
*
* @example
* ```
* const instanceId = auth.getInstanceId();
* ```
*
* @preserve
*/
getInstanceId() {
return _AsgardeoAuthClient._instanceID;
}
/**
* This is an async method that returns a Promise that resolves with the authorization URL.
*
* @param config - (Optional) A config object to force initialization and pass
* custom path parameters such as the fidp parameter.
* @param userId - (Optional) A unique ID of the user to be authenticated. This is useful in multi-user
* scenarios where each user should be uniquely identified.
*
* @returns - A promise that resolves with the authorization URL.
*
* @example
* ```
* auth.getSignInUrl().then((url)=>{
* // console.log(url);
* }).catch((error)=>{
* // console.error(error);
* });
* ```
*
* {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#getSignInUrl}
*
* @preserve
*/
async getSignInUrl(requestConfig, userId) {
const authRequestConfig = { ...requestConfig };
delete authRequestConfig?.forceInit;
const __TODO__ = async () => {
const authorizeEndpoint = await this._storageManager.getOIDCProviderMetaDataParameter(
OIDCDiscoveryConstants_default.Storage.StorageKeys.Endpoints.AUTHORIZATION
);
if (!authorizeEndpoint || authorizeEndpoint.trim().length === 0) {
throw new AsgardeoAuthException(
"JS-AUTH_CORE-GAU-NF01",
"No authorization endpoint found.",
"No authorization endpoint was found in the OIDC provider meta data from the well-known endpoint or the authorization endpoint passed to the SDK is empty."
);
}
const authorizeRequest = new URL(authorizeEndpoint);
const configData = await this._config();
const tempStore = await this._storageManager.getTemporaryData(userId);
const pkceKey = await generatePkceStorageKey_default(tempStore);
let codeVerifier;
let codeChallenge;
if (configData.enablePKCE) {
codeVerifier = this._cryptoHelper?.getCodeVerifier();
codeChallenge = this._cryptoHelper?.getCodeChallenge(codeVerifier);
await this._storageManager.setTemporaryDataParameter(pkceKey, codeVerifier, userId);
}
if (authRequestConfig["client_secret"]) {
authRequestConfig["client_secret"] = configData.clientSecret;
}
const authorizeRequestParams = getAuthorizeRequestUrlParams_default(
{
redirectUri: configData.afterSignInUrl,
clientId: configData.clientId,
scopes: processOpenIDScopes_default(configData.scopes),
responseMode: configData.responseMode,
codeChallengeMethod: PKCEConstants_default.DEFAULT_CODE_CHALLENGE_METHOD,
codeChallenge,
prompt: configData.prompt
},
{ key: pkceKey },
authRequestConfig
);
for (const [key, value] of authorizeRequestParams.entries()) {
authorizeRequest.searchParams.append(key, value);
}
return authorizeRequest.toString();
};
if (await this._storageManager.getTemporaryDataParameter(
OIDCDiscoveryConstants_default.Storage.StorageKeys.OPENID_PROVIDER_CONFIG_INITIATED
)) {
return __TODO__();
}
return this.loadOpenIDProviderConfiguration(requestConfig?.forceInit).then(() => {
return __TODO__();
});
}
/**
* This is an async method that sends a request to obtain the access token and returns a Promise
* that resolves with the token and other relevant data.
*
* @param authorizationCode - The authorization code.
* @param sessionState - The session state.
* @param userId - (Optional) A unique ID of the user to be authenticated. This is useful in multi-user
* scenarios where each user should be uniquely identified.
*
* @returns - A Promise that resolves with the token response.
*
* @example
* ```
* auth.requestAccessToken(authCode, sessionState).then((token)=>{
* // console.log(token);
* }).catch((error)=>{
* // console.error(error);
* });
* ```
*
* {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#requestAccessToken}
*
*
* @preserve
*/
async requestAccessToken(authorizationCode, sessionState, state, userId, tokenRequestConfig) {
const __TODO__ = async () => {
const tokenEndpoint = (await this._oidcProviderMetaData()).token_endpoint;
const configData = await this._config();
if (!tokenEndpoint || tokenEndpoint.trim().length === 0) {
throw new AsgardeoAuthException(
"JS-AUTH_CORE-RAT1-NF01",
"Token endpoint not found.",
"No token endpoint was found in the OIDC provider meta data returned by the well-known endpoint or the token endpoint passed to the SDK is empty."
);
}
sessionState && await this._storageManager.setSessionDataParameter(
OIDCRequestConstants_default.Params.SESSION_STATE,
sessionState,
userId
);
const body = new URLSearchParams();
body.set("client_id", configData.clientId);
if (configData.clientSecret && configData.clientSecret.trim().length > 0) {
body.set("client_secret", configData.clientSecret);
}
const code = authorizationCode;
body.set("code", code);
body.set("grant_type", "authorization_code");
body.set("redirect_uri", configData.afterSignInUrl);
if (tokenRequestConfig?.params) {
Object.entries(tokenRequestConfig.params).forEach(([key, value]) => {
body.append(key, value);
});
}
if (configData.enablePKCE) {
body.set(
"code_verifier",
`${await this._storageManager.getTemporaryDataParameter(extractPkceStorageKeyFromState_default(state), userId)}`
);
await this._storageManager.removeTemporaryDataParameter(extractPkceStorageKeyFromState_default(state), userId);
}
let tokenResponse;
try {
tokenResponse = await fetch(tokenEndpoint, {
body,
credentials: configData.sendCookiesInRequests ? "include" : "same-origin",
headers: {
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded"
},
method: "POST"
});
} catch (error2) {
throw new AsgardeoAuthException(
"JS-AUTH_CORE-RAT1-NE02",
"Requesting access token failed",
error2 ?? "The request to get the access token from the server failed."
);
}
if (!tokenResponse.ok) {
throw new AsgardeoAuthException(
"JS-AUTH_CORE-RAT1-HE03",
`Requesting access token failed with ${tokenResponse.statusText}`,
await tokenResponse.json()
);
}
return await this._authenticationHelper.handleTokenResponse(tokenResponse, userId);
};
if (await this._storageManager.getTemporaryDataParameter(
OIDCDiscoveryConstants_default.Storage.StorageKeys.OPENID_PROVIDER_CONFIG_INITIATED
)) {
return __TODO__();
}
return this.loadOpenIDProviderConfiguration(false).then(() => {
return __TODO__();
});
}
async loadOpenIDProviderConfiguration(forceInit) {
const configData = await this._config();
if (!forceInit && await this._storageManager.getTemporaryDataParameter(
OIDCDiscoveryConstants_default.Storage.StorageKeys.OPENID_PROVIDER_CONFIG_INITIATED
)) {
return Promise.resolve();
}
const wellKnownEndpoint = configData.wellKnownEndpoint;
if (wellKnownEndpoint) {
let response;
try {
response = await fetch(wellKnownEndpoint);
if (response.status !== 200 || !response.ok) {
throw new Error();
}
} catch {
throw new AsgardeoAuthException(
"JS-AUTH_CORE-GOPMD-HE01",
"Invalid well-known response",
"The well known endpoint response has been failed with an error."
);
}
await this._storageManager.setOIDCProviderMetaData(
await this._authenticationHelper.resolveEndpoints(await response.json())
);
await this._storageManager.setTemporaryDataParameter(
OIDCDiscoveryConstants_default.Storage.StorageKeys.OPENID_PROVIDER_CONFIG_INITIATED,
true
);
return Promise.resolve();
} else if (configData.baseUrl) {
try {
await this._storageManager.setOIDCProviderMetaData(
await this._authenticationHelper.resolveEndpointsByBaseURL()
);
} catch (error2) {
throw new AsgardeoAuthException(
"JS-AUTH_CORE-GOPMD-IV02",
"Resolving endpoints failed.",
error2 ?? "Resolving endpoints by base url failed."
);
}
await this._storageManager.setTemporaryDataParameter(
OIDCDiscoveryConstants_default.Storage.StorageKeys.OPENID_PROVIDER_CONFIG_INITIATED,
true
);
return Promise.resolve();
} else {
await this._storageManager.setOIDCProviderMetaData(await this._authenticationHelper.resolveEndpointsExplicitly());
await this._storageManager.setTemporaryDataParameter(
OIDCDiscoveryConstants_default.Storage.StorageKeys.OPENID_PROVIDER_CONFIG_INITIATED,
true
);
return Promise.resolve();
}
}
/**
* This method returns the sign-out URL.
*
* @param userId - (Optional) A unique ID of the user to be authenticated. This is useful in multi-user
* scenarios where each user should be uniquely identified.
*
* **This doesn't clear the authentication data.**
*
* @returns - A Promise that resolves with the sign-out URL.
*
* @example
* ```
* const signOutUrl = await auth.getSignOutUrl();
* ```
*
* {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#getSignOutUrl}
*
* @preserve
*/
async getSignOutUrl(userId) {
const logoutEndpoint = (await this._oidcProviderMetaData())?.end_session_endpoint;
const configData = await this._config();
if (!logoutEndpoint || logoutEndpoint.trim().length === 0) {
throw new AsgardeoAuthException(
"JS-AUTH_CORE-GSOU-NF01",
"Sign-out endpoint not found.",
"No sign-out endpoint was found in the