Skip to content

Commit 3b6c874

Browse files
Merge pull request #337 from kavindadimuthu/fix/multi-http-clients
Fix failure of calling authenticated APIs from secondary AsgardeoProvider Instances (Multi-Provider Support)
2 parents b96e741 + 8571623 commit 3b6c874

7 files changed

Lines changed: 74 additions & 44 deletions

File tree

.changeset/light-queens-rest.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@asgardeo/browser': minor
3+
---
4+
5+
Fix failure of calling authenticated APIs from secondary AsgardeoProvider Instances in Multi Provider scenarios

packages/browser/src/__legacy__/clients/main-thread-client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export const MainThreadClient = async (
8585

8686
let _getSignOutURLFromSessionStorage: boolean = false;
8787

88-
const _httpClient: HttpClientInstance = HttpClient.getInstance();
88+
const _httpClient: HttpClientInstance = HttpClient.getInstance(instanceID);
8989
let _isHttpHandlerEnabled: boolean = true;
9090
let _httpErrorCallback: (error: HttpError) => void | Promise<void>;
9191
let _httpFinishCallback: () => void;

packages/browser/src/__legacy__/clients/web-worker-client.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,8 +365,8 @@ export const WebWorkerClient = async (
365365
}
366366
};
367367

368-
const message: Message<AuthClientConfig<WebWorkerClientConfig>> = {
369-
data: config,
368+
const message: Message<AuthClientConfig<WebWorkerClientConfig> & {instanceID: number}> = {
369+
data: {...config, instanceID},
370370
type: INIT,
371371
};
372372

packages/browser/src/__legacy__/http-client/clients/axios-http-client.ts

Lines changed: 59 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ import {HttpClientInstance, HttpClientInterface, HttpClientStatic} from '../mode
4141
*/
4242
@staticDecorator<HttpClientStatic<HttpClientInstance>>()
4343
export class HttpClient implements HttpClientInterface<HttpRequestConfig, HttpResponse, HttpError> {
44-
private static axiosInstance: HttpClientInstance;
45-
private static clientInstance: HttpClient;
46-
private static isHandlerEnabled: boolean;
44+
private static instances: Map<number, HttpClientInstance> = new Map();
45+
private static clientInstances: Map<number, HttpClient> = new Map();
46+
private isHandlerEnabled: boolean = true;
4747
private attachToken: (request: HttpRequestConfig) => Promise<void> = () => Promise.resolve();
4848
private requestStartCallback: (request: HttpRequestConfig) => void = () => null;
4949
private requestSuccessCallback: (response: HttpResponse) => void = () => null;
@@ -59,55 +59,78 @@ export class HttpClient implements HttpClientInterface<HttpRequestConfig, HttpRe
5959
*/
6060
private constructor() {
6161
this.init = this.init.bind(this);
62+
this.enableHandler = this.enableHandler.bind(this);
63+
this.disableHandler = this.disableHandler.bind(this);
64+
this.disableHandlerWithTimeout = this.disableHandlerWithTimeout.bind(this);
6265
this.setHttpRequestErrorCallback = this.setHttpRequestErrorCallback.bind(this);
6366
this.setHttpRequestFinishCallback = this.setHttpRequestFinishCallback.bind(this);
6467
this.setHttpRequestStartCallback = this.setHttpRequestStartCallback.bind(this);
6568
this.setHttpRequestSuccessCallback = this.setHttpRequestSuccessCallback.bind(this);
6669
}
6770

6871
/**
69-
* Returns an aggregated instance of type `HttpInstance` of `HttpClient`.
72+
* Returns an instance-specific HttpClient instance.
73+
* Each instance ID gets its own axios instance and HttpClient to avoid state conflicts.
7074
*
71-
* @return {any}
75+
* @param instanceId - The instance ID for multi-auth context support. Defaults to 0.
76+
* @return {HttpClientInstance}
7277
*/
73-
public static getInstance(): HttpClientInstance {
74-
if (this.axiosInstance) {
75-
return this.axiosInstance;
78+
public static getInstance(instanceId: number = 0): HttpClientInstance {
79+
if (this.instances.has(instanceId)) {
80+
return this.instances.get(instanceId)!;
7681
}
7782

78-
this.axiosInstance = axios.create({
83+
const axiosInstance = axios.create({
7984
withCredentials: true,
80-
});
85+
}) as HttpClientInstance;
8186

82-
if (!this.clientInstance) {
83-
this.clientInstance = new HttpClient();
84-
}
87+
const clientInstance = new HttpClient();
88+
this.clientInstances.set(instanceId, clientInstance);
8589

8690
// Register request interceptor
87-
this.axiosInstance.interceptors.request.use(async (request: InternalAxiosRequestConfig) => await this.clientInstance.requestHandler(request as HttpRequestConfig) as InternalAxiosRequestConfig);
91+
axiosInstance.interceptors.request.use(async (request: InternalAxiosRequestConfig) => await clientInstance.requestHandler(request as HttpRequestConfig) as InternalAxiosRequestConfig);
8892

8993
// Register response interceptor
90-
this.axiosInstance.interceptors.response.use(
91-
response => this.clientInstance.successHandler(response),
92-
error => this.clientInstance.errorHandler(error),
94+
axiosInstance.interceptors.response.use(
95+
response => clientInstance.successHandler(response),
96+
error => clientInstance.errorHandler(error),
9397
);
9498

9599
// Add the missing helper methods from axios
96-
this.axiosInstance.all = axios.all;
97-
this.axiosInstance.spread = axios.spread;
100+
axiosInstance.all = axios.all;
101+
axiosInstance.spread = axios.spread;
98102

99103
// Add the init method from the `HttpClient` instance.
100-
this.axiosInstance.init = this.clientInstance.init;
104+
axiosInstance.init = clientInstance.init;
101105

102106
// Add the handler enabling & disabling methods to the instance.
103-
this.axiosInstance.enableHandler = this.clientInstance.enableHandler;
104-
this.axiosInstance.disableHandler = this.clientInstance.disableHandler;
105-
this.axiosInstance.disableHandlerWithTimeout = this.clientInstance.disableHandlerWithTimeout;
106-
this.axiosInstance.setHttpRequestStartCallback = this.clientInstance.setHttpRequestStartCallback;
107-
this.axiosInstance.setHttpRequestSuccessCallback = this.clientInstance.setHttpRequestSuccessCallback;
108-
this.axiosInstance.setHttpRequestErrorCallback = this.clientInstance.setHttpRequestErrorCallback;
109-
this.axiosInstance.setHttpRequestFinishCallback = this.clientInstance.setHttpRequestFinishCallback;
110-
return this.axiosInstance;
107+
axiosInstance.enableHandler = clientInstance.enableHandler;
108+
axiosInstance.disableHandler = clientInstance.disableHandler;
109+
axiosInstance.disableHandlerWithTimeout = clientInstance.disableHandlerWithTimeout;
110+
axiosInstance.setHttpRequestStartCallback = clientInstance.setHttpRequestStartCallback;
111+
axiosInstance.setHttpRequestSuccessCallback = clientInstance.setHttpRequestSuccessCallback;
112+
axiosInstance.setHttpRequestErrorCallback = clientInstance.setHttpRequestErrorCallback;
113+
axiosInstance.setHttpRequestFinishCallback = clientInstance.setHttpRequestFinishCallback;
114+
115+
this.instances.set(instanceId, axiosInstance);
116+
return axiosInstance;
117+
}
118+
119+
/**
120+
* Destroys and cleans up an HttpClient instance.
121+
* This should be called during provider teardown to prevent memory leaks.
122+
*
123+
* @param instanceId - The instance ID to destroy. Defaults to 0.
124+
*/
125+
public static destroyInstance(instanceId: number = 0): void {
126+
const axiosInstance = this.instances.get(instanceId);
127+
if (axiosInstance) {
128+
// Eject interceptors to prevent memory leaks
129+
axiosInstance.interceptors.request.clear();
130+
axiosInstance.interceptors.response.clear();
131+
}
132+
this.instances.delete(instanceId);
133+
this.clientInstances.delete(instanceId);
111134
}
112135

113136
/**
@@ -134,7 +157,7 @@ export class HttpClient implements HttpClientInterface<HttpRequestConfig, HttpRe
134157

135158
request.startTimeInMs = new Date().getTime();
136159

137-
if (HttpClient.isHandlerEnabled) {
160+
if (this.isHandlerEnabled) {
138161
if (this.requestStartCallback && typeof this.requestStartCallback === 'function') {
139162
this.requestStartCallback(request);
140163
}
@@ -151,7 +174,7 @@ export class HttpClient implements HttpClientInterface<HttpRequestConfig, HttpRe
151174
* @return {HttpError}
152175
*/
153176
public errorHandler(error: HttpError): HttpError {
154-
if (HttpClient.isHandlerEnabled) {
177+
if (this.isHandlerEnabled) {
155178
if (this.requestErrorCallback && typeof this.requestErrorCallback === 'function') {
156179
this.requestErrorCallback(error);
157180
}
@@ -171,7 +194,7 @@ export class HttpClient implements HttpClientInterface<HttpRequestConfig, HttpRe
171194
* @return {HttpResponse}
172195
*/
173196
public successHandler(response: HttpResponse): HttpResponse {
174-
if (HttpClient.isHandlerEnabled) {
197+
if (this.isHandlerEnabled) {
175198
if (this.requestSuccessCallback && typeof this.requestSuccessCallback === 'function') {
176199
this.requestSuccessCallback(response);
177200
}
@@ -195,22 +218,22 @@ export class HttpClient implements HttpClientInterface<HttpRequestConfig, HttpRe
195218
isHandlerEnabled = true,
196219
attachToken: (request: HttpRequestConfig) => Promise<void>,
197220
): Promise<void> {
198-
HttpClient.isHandlerEnabled = isHandlerEnabled;
221+
this.isHandlerEnabled = isHandlerEnabled;
199222
this.attachToken = attachToken;
200223
}
201224

202225
/**
203226
* Enables the handler.
204227
*/
205228
public enableHandler(): void {
206-
HttpClient.isHandlerEnabled = true;
229+
this.isHandlerEnabled = true;
207230
}
208231

209232
/**
210233
* Disables the handler.
211234
*/
212235
public disableHandler(): void {
213-
HttpClient.isHandlerEnabled = false;
236+
this.isHandlerEnabled = false;
214237
}
215238

216239
/**
@@ -219,10 +242,10 @@ export class HttpClient implements HttpClientInterface<HttpRequestConfig, HttpRe
219242
* @param {number} timeout - Timeout in milliseconds.
220243
*/
221244
public disableHandlerWithTimeout(timeout: number = HttpClient.DEFAULT_HANDLER_DISABLE_TIMEOUT): void {
222-
HttpClient.isHandlerEnabled = false;
245+
this.isHandlerEnabled = false;
223246

224247
setTimeout(() => {
225-
HttpClient.isHandlerEnabled = true;
248+
this.isHandlerEnabled = true;
226249
}, timeout);
227250
}
228251

packages/browser/src/__legacy__/http-client/models/http-client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { HttpError, HttpResponse } from "../../models";
2323
* Http client interface with static functions.
2424
*/
2525
export interface HttpClientStatic<S> {
26-
getInstance(): S;
26+
getInstance(instanceId?: number): S;
2727
}
2828

2929
/**

packages/browser/src/__legacy__/worker/worker-core.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import {MemoryStore} from '../stores';
4242
import {SPACryptoUtils} from '../utils/crypto-utils';
4343

4444
export const WebWorkerCore = async (
45+
instanceID: number,
4546
config: AuthClientConfig<WebWorkerClientConfig>,
4647
getAuthHelper: (
4748
authClient: AsgardeoAuthClient<WebWorkerClientConfig>,
@@ -51,7 +52,7 @@ export const WebWorkerCore = async (
5152
const _store: Storage = new MemoryStore();
5253
const _cryptoUtils: SPACryptoUtils = new SPACryptoUtils();
5354
const _authenticationClient = new AsgardeoAuthClient<WebWorkerClientConfig>();
54-
await _authenticationClient.initialize(config, _store, _cryptoUtils);
55+
await _authenticationClient.initialize(config, _store, _cryptoUtils, instanceID);
5556

5657
const _spaHelper = new SPAHelper<WebWorkerClientConfig>(_authenticationClient);
5758

@@ -62,7 +63,7 @@ export const WebWorkerCore = async (
6263

6364
const _dataLayer = _authenticationClient.getStorageManager();
6465

65-
const _httpClient: HttpClientInstance = HttpClient.getInstance();
66+
const _httpClient: HttpClientInstance = HttpClient.getInstance(instanceID);
6667

6768
const attachToken = async (request: HttpRequestConfig): Promise<void> => {
6869
await _authenticationHelper.attachTokenToRequestConfig(request);

packages/browser/src/__legacy__/worker/worker-receiver.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,9 @@ export const workerReceiver = (
8484
switch (data.type) {
8585
case INIT:
8686
try {
87-
const config: AuthClientConfig<WebWorkerClientConfig> = {...data.data};
88-
webWorker = await WebWorkerCore(config, getAuthHelper);
87+
const {instanceID = 0, ...configData} = data.data;
88+
const config: AuthClientConfig<WebWorkerClientConfig> = {...configData};
89+
webWorker = await WebWorkerCore(instanceID, config, getAuthHelper);
8990
webWorker.setHttpRequestFinishCallback(onRequestFinishCallback);
9091
webWorker.setHttpRequestStartCallback(onRequestStartCallback);
9192
webWorker.setHttpRequestSuccessCallback(onRequestSuccessCallback);

0 commit comments

Comments
 (0)