Skip to content

Comments

Fix failure of calling authenticated APIs from secondary AsgardeoProvider Instances (Multi-Provider Support)#337

Merged
DonOmalVindula merged 6 commits intoasgardeo:mainfrom
kavindadimuthu:fix/multi-http-clients
Feb 24, 2026
Merged

Fix failure of calling authenticated APIs from secondary AsgardeoProvider Instances (Multi-Provider Support)#337
DonOmalVindula merged 6 commits intoasgardeo:mainfrom
kavindadimuthu:fix/multi-http-clients

Conversation

@kavindadimuthu
Copy link
Contributor

@kavindadimuthu kavindadimuthu commented Jan 26, 2026

Purpose

This pull request introduces multi-HTTP clients support when multiple provider instances are implemented. This ensures that all authenticated HTTP operations are isolated per instance.

The most important changes are:

Instance-specific HTTP Client Management

  • Refactored HttpClient to support multiple isolated HTTP client/axios instances, each keyed by instance ID, preventing state conflicts between auth contexts. All HTTP handler flags and callbacks are now instance-specific. [1] [2] [3] [4] [5] [6] [7] [8]
  • Updated all usages of HttpClient.getInstance() to provide the correct instance ID, ensuring HTTP requests are routed through the correct context. [1] [2] [3] [4]

Related Issues

Related PRs

Checklist

  • Followed the CONTRIBUTING guidelines.
  • Manual test round performed and verified.
  • Documentation provided. (Add links if there are any)
  • Unit tests provided. (Add links if there are any)

Security checks

@kavindadimuthu kavindadimuthu force-pushed the fix/multi-http-clients branch 3 times, most recently from a6c1841 to 12fd275 Compare February 18, 2026 17:13
Copy link
Contributor

@DonOmalVindula DonOmalVindula left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The multiton refactoring looks good overall and the approach is correct. However, there's a this-binding bug that needs to be fixed before merging — see inline comments.

Copy link
Contributor

@DonOmalVindula DonOmalVindula left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few more issues I noticed during review.


let _getSignOutURLFromSessionStorage: boolean = false;

const _httpClient: HttpClientInstance = HttpClient.getInstance();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: worker-core.ts has the same pattern at the same line — HttpClient.getInstance() without an instanceId — but was missed in this PR. The web worker path will always fall back to instanceId=0 regardless of which provider spawned it.

Suggestion: Thread the instanceID through to WebWorkerCore the same way it's done in MainThreadClient:

export const WebWorkerCore = async (
  instanceID: number,
  config: AuthClientConfig<WebWorkerClientConfig>,
  ...
): Promise<WebWorkerCoreInterface> => {
  ...
  const _httpClient: HttpClientInstance = HttpClient.getInstance(instanceID);
  ...
};

See packages/browser/src/__legacy__/worker/worker-core.ts:65.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved this

private static isHandlerEnabled: boolean;
private static instances: Map<number, HttpClientInstance> = new Map();
private static clientInstances: Map<number, HttpClient> = new Map();
private isHandlerEnabled: boolean = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Memory leak: Instances are added to these static Maps but never removed. If an AsgardeoProvider unmounts and remounts (e.g. React hot-reload, dynamic multi-tenant switching), stale axios instances with outdated interceptors and callbacks will accumulate.

Suggestion: Add a static cleanup method:

public static destroyInstance(instanceId: number): void {
  const axiosInstance = this.instances.get(instanceId);
  if (axiosInstance) {
    // Eject interceptors to prevent memory leaks
    axiosInstance.interceptors.request.clear();
    axiosInstance.interceptors.response.clear();
  }
  this.instances.delete(instanceId);
  this.clientInstances.delete(instanceId);
}

This should be called during provider teardown.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved this

private static clientInstance: HttpClient;
private static isHandlerEnabled: boolean;
private static instances: Map<number, HttpClientInstance> = new Map();
private static clientInstances: Map<number, HttpClient> = new Map();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead code: clientInstances is write-only — nothing ever calls clientInstances.get(). If you add a destroyInstance() method (see my other comment), this map becomes useful for cleanup. Otherwise, it should be removed to avoid confusion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved this

…e to support instance ID

- Implement `destroyInstance` method in `HttpClient` to clean up instances and prevent memory leaks.
- Update `WebWorkerCore` to accept an `instanceID` parameter for better instance management.
- Modified `workerReceiver` to handle instance ID during initialization and pass it to `WebWorkerCore`.
@asgardeo-github-bot
Copy link

🦋 Changeset detected

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Copy link
Contributor

@DonOmalVindula DonOmalVindula left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The core singleton → multiton refactoring looks correct and all previous review comments have been addressed. A few remaining items to clean up before merging.

if (axiosInstance) {
// Eject interceptors to prevent memory leaks
axiosInstance.interceptors.request.clear();
axiosInstance.interceptors.response.clear();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

destroyInstance() is defined but never called anywhere. It needs to be wired into the provider teardown/unmount lifecycle (e.g., in AsgardeoProvider's cleanup) to actually prevent the memory leak it was designed to address. Without a caller, this is dead code.

Please either:

  1. Wire it into the provider's useEffect cleanup, or
  2. Remove it and track the cleanup as a separate follow-up issue.


const message: Message<AuthClientConfig<WebWorkerClientConfig>> = {
data: config,
const message: Message<AuthClientConfig<WebWorkerClientConfig> & {instanceID: number}> = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mixing instanceID into the config data payload via intersection type (& {instanceID: number}) is fragile. If AuthClientConfig ever adds an instanceID field, it will silently conflict.

Nit: Consider passing instanceID as a separate field on the Message type rather than stuffing it into data.

return this.axiosInstance;
public static getInstance(instanceId: number = 0): HttpClientInstance {
if (this.instances.has(instanceId)) {
return this.instances.get(instanceId)!;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Naming inconsistency — this method uses instanceId (camelCase) while MainThreadClient, WebWorkerCore, and workerReceiver all use instanceID (all-caps ID). Pick one convention and use it consistently across the codebase.

@DonOmalVindula
Copy link
Contributor

You can address the added comments in a follow-up PR

@DonOmalVindula DonOmalVindula merged commit 3b6c874 into asgardeo:main Feb 24, 2026
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: Authenticated API Calls Fail for Secondary AsgardeoProvider Instances (Multi-Provider Support)

3 participants