From f3357bba0d8b70e9014739b1cb479140d06ecfe2 Mon Sep 17 00:00:00 2001 From: Brion Date: Tue, 2 Dec 2025 11:21:22 +0530 Subject: [PATCH 1/6] fix: update resource server validation to use allowedExternalUrls --- .../helpers/authentication-helper.ts | 29 ++++++++++--------- .../src/__legacy__/models/client-config.ts | 2 +- packages/javascript/src/models/config.ts | 18 ++++++++++++ 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/packages/browser/src/__legacy__/helpers/authentication-helper.ts b/packages/browser/src/__legacy__/helpers/authentication-helper.ts index d7b7dcc8..89583051 100644 --- a/packages/browser/src/__legacy__/helpers/authentication-helper.ts +++ b/packages/browser/src/__legacy__/helpers/authentication-helper.ts @@ -29,6 +29,7 @@ import { OIDCEndpoints, TokenResponse, extractPkceStorageKeyFromState, + Config, } from '@asgardeo/javascript'; import {SPAHelper} from './spa-helper'; import { @@ -103,6 +104,7 @@ export class AuthenticationHelper void, ): Promise { + const _config: Config = (await this._storageManager.getConfigData()) as Config; let useDefaultEndpoint = true; let matches = false; @@ -110,19 +112,18 @@ export class AuthenticationHelper void, ): Promise { let matches = false; - const config = await this._storageManager.getConfigData(); + const config: Config = (await this._storageManager.getConfigData()) as Config; - for (const baseUrl of [...((await config?.resourceServerURLs) ?? []), (config as any).baseUrl]) { + for (const baseUrl of [...(config?.allowedExternalUrls ?? []), (config as any).baseUrl]) { if (baseUrl && requestConfig?.url?.startsWith(baseUrl)) { matches = true; @@ -319,9 +320,9 @@ export class AuthenticationHelper void, ): Promise { let matches = true; - const config = await this._storageManager.getConfigData(); + const config: Config = (await this._storageManager.getConfigData()) as Config; for (const requestConfig of requestConfigs) { let urlMatches = false; - for (const baseUrl of [...((await config)?.resourceServerURLs ?? []), (config as any).baseUrl]) { + for (const baseUrl of [...(config?.allowedExternalUrls ?? []), (config as any).baseUrl]) { if (baseUrl && requestConfig.url?.startsWith(baseUrl)) { urlMatches = true; @@ -436,9 +437,9 @@ export class AuthenticationHelper; periodicTokenRefresh?: boolean; autoLogoutOnTokenRefreshError?: boolean; diff --git a/packages/javascript/src/models/config.ts b/packages/javascript/src/models/config.ts index 659dab1b..b2f88891 100644 --- a/packages/javascript/src/models/config.ts +++ b/packages/javascript/src/models/config.ts @@ -78,6 +78,24 @@ export interface BaseConfig extends WithPreferences { */ afterSignOutUrl?: string | undefined; + /** + * A list of external API base URLs that the SDK is allowed to attach access tokens to when making HTTP requests. + * + * When making authenticated HTTP requests using the SDK's HTTP client, the access token will only be attached + * to requests whose URLs start with one of these specified base URLs. This provides a security layer by + * preventing tokens from being sent to unauthorized servers. + * + * @remarks + * - This is only applicable when the storage type is `webWorker`. + * - Each URL should be a base URL without trailing slashes (e.g., "https://api.example.com"). + * - The SDK will check if the request URL starts with any of these base URLs before attaching the token. + * - If a request is made to a URL that doesn't match any of these base URLs, an error will be thrown. + * + * @example + * allowedExternalUrls: ["https://api.example.com", "https://api.another-service.com"] + */ + allowedExternalUrls?: string[]; + /** * Optional organization handle for the Organization in Asgardeo. * This is used to identify the organization in the Asgardeo identity server in cases like Branding, etc. From 99cb8db8a7ffb4b473ddfee725b83ad2effc71f1 Mon Sep 17 00:00:00 2001 From: Brion Date: Tue, 2 Dec 2025 13:02:54 +0530 Subject: [PATCH 2/6] fix: restrict URL validation to WebWorker storage in AuthenticationHelper --- .../helpers/authentication-helper.ts | 49 ++++++++++++------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/packages/browser/src/__legacy__/helpers/authentication-helper.ts b/packages/browser/src/__legacy__/helpers/authentication-helper.ts index 89583051..4309075d 100644 --- a/packages/browser/src/__legacy__/helpers/authentication-helper.ts +++ b/packages/browser/src/__legacy__/helpers/authentication-helper.ts @@ -112,11 +112,16 @@ export class AuthenticationHelper Date: Tue, 2 Dec 2025 14:31:18 +0530 Subject: [PATCH 3/6] =?UTF-8?q?chore:=20add=20changeset=20=F0=9F=A6=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/afraid-buckets-jog.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/afraid-buckets-jog.md diff --git a/.changeset/afraid-buckets-jog.md b/.changeset/afraid-buckets-jog.md new file mode 100644 index 00000000..be19c532 --- /dev/null +++ b/.changeset/afraid-buckets-jog.md @@ -0,0 +1,6 @@ +--- +'@asgardeo/javascript': patch +'@asgardeo/browser': patch +--- + +Add ability to call external endpoints without explicitly allowing them in non `webWorker` storage modes From 6e3e3d76cdaddd87d0d53739580f5caf455aea6d Mon Sep 17 00:00:00 2001 From: Brion Date: Tue, 2 Dec 2025 14:49:34 +0530 Subject: [PATCH 4/6] fix: update AsgardeoProvider and AsgardeoContext for improved functionality --- packages/react/src/contexts/Asgardeo/AsgardeoContext.ts | 3 ++- packages/react/src/contexts/Asgardeo/AsgardeoProvider.tsx | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/react/src/contexts/Asgardeo/AsgardeoContext.ts b/packages/react/src/contexts/Asgardeo/AsgardeoContext.ts index f705f3cc..03a40f7a 100644 --- a/packages/react/src/contexts/Asgardeo/AsgardeoContext.ts +++ b/packages/react/src/contexts/Asgardeo/AsgardeoContext.ts @@ -139,7 +139,7 @@ export type AsgardeoContextProps = { */ reInitialize: (config: Partial) => Promise; } & Pick & - Pick; + Pick; /** * Context object for managing the Authentication flow builder core context. @@ -170,6 +170,7 @@ const AsgardeoContext: Context = createContext> = ({ exchangeToken: asgardeo.exchangeToken.bind(asgardeo), syncSession, platform: config?.platform, + switchOrganization }), [ applicationId, @@ -537,6 +538,7 @@ const AsgardeoProvider: FC> = ({ asgardeo, signInOptions, syncSession, + switchOrganization ], ); From 0f7e10277dc4c0e05ddd95e7900bd5a5b9b0569f Mon Sep 17 00:00:00 2001 From: Brion Date: Tue, 2 Dec 2025 15:09:20 +0530 Subject: [PATCH 5/6] fix: update switchOrganization and onOrganizationSwitch to return TokenResponse --- .../react/src/contexts/Asgardeo/AsgardeoProvider.tsx | 11 +++++++---- .../contexts/Organization/OrganizationProvider.tsx | 3 ++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/react/src/contexts/Asgardeo/AsgardeoProvider.tsx b/packages/react/src/contexts/Asgardeo/AsgardeoProvider.tsx index 57dd9017..570f4fa8 100644 --- a/packages/react/src/contexts/Asgardeo/AsgardeoProvider.tsx +++ b/packages/react/src/contexts/Asgardeo/AsgardeoProvider.tsx @@ -31,6 +31,7 @@ import { Platform, extractUserClaimsFromIdToken, EmbeddedSignInFlowResponseV2, + TokenResponse, } from '@asgardeo/browser'; import {FC, RefObject, PropsWithChildren, ReactElement, useEffect, useMemo, useRef, useState, useCallback} from 'react'; import AsgardeoContext from './AsgardeoContext'; @@ -459,15 +460,17 @@ const AsgardeoProvider: FC> = ({ } }; - const switchOrganization = async (organization: Organization): Promise => { + const switchOrganization = async (organization: Organization): Promise => { try { setIsUpdatingSession(true); setIsLoadingSync(true); - await asgardeo.switchOrganization(organization); + const response: TokenResponse | Response = await asgardeo.switchOrganization(organization); if (await asgardeo.isSignedIn()) { await updateSession(); } + + return response; } catch (error) { throw new AsgardeoRuntimeError( `Failed to switch organization: ${error instanceof Error ? error.message : String(JSON.stringify(error))}`, @@ -519,7 +522,7 @@ const AsgardeoProvider: FC> = ({ exchangeToken: asgardeo.exchangeToken.bind(asgardeo), syncSession, platform: config?.platform, - switchOrganization + switchOrganization, }), [ applicationId, @@ -538,7 +541,7 @@ const AsgardeoProvider: FC> = ({ asgardeo, signInOptions, syncSession, - switchOrganization + switchOrganization, ], ); diff --git a/packages/react/src/contexts/Organization/OrganizationProvider.tsx b/packages/react/src/contexts/Organization/OrganizationProvider.tsx index 960bf4f6..91af4661 100644 --- a/packages/react/src/contexts/Organization/OrganizationProvider.tsx +++ b/packages/react/src/contexts/Organization/OrganizationProvider.tsx @@ -21,6 +21,7 @@ import { Organization, AllOrganizationsApiResponse, CreateOrganizationPayload, + TokenResponse, } from '@asgardeo/browser'; import {FC, PropsWithChildren, ReactElement, useCallback, useMemo, useState} from 'react'; import OrganizationContext, {OrganizationContextProps} from './OrganizationContext'; @@ -56,7 +57,7 @@ export interface OrganizationProviderProps { /** * Callback function called when switching organizations */ - onOrganizationSwitch?: (organization: Organization) => Promise; + onOrganizationSwitch?: (organization: Organization) => Promise; /** * Refetch the my organizations list. * @returns From d632b69cb4d7441b06c0b3aeb625e720b7152732 Mon Sep 17 00:00:00 2001 From: Brion Date: Tue, 2 Dec 2025 15:10:04 +0530 Subject: [PATCH 6/6] =?UTF-8?q?chore:=20update=20changeset=20=F0=9F=A6=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/afraid-buckets-jog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.changeset/afraid-buckets-jog.md b/.changeset/afraid-buckets-jog.md index be19c532..7db36f5b 100644 --- a/.changeset/afraid-buckets-jog.md +++ b/.changeset/afraid-buckets-jog.md @@ -1,6 +1,7 @@ --- '@asgardeo/javascript': patch '@asgardeo/browser': patch +'@asgardeo/react': patch --- Add ability to call external endpoints without explicitly allowing them in non `webWorker` storage modes