Open newway-anshul opened 1 month ago
Hi,
I was looking into a similar issue today and I did some analysis. Also I posted the question on Stackoverflow: https://stackoverflow.com/questions/78977600/oidc-oauth-api-requests-using-different-public-clientid-in-an-angular-app
Some APIs are registered on our API Gateway with different OAUTH clientId from two different identity providers. Our need is then to be able to call APIs by specifying the IDP and the clientId.
The issue, in short, is that OAuthService is really meant to be used as a singleton in a page, meaning that only one IDP and one clientId can be used by the page.
Storage access First root cause, as you mentioned, is the way it uses Storage. Indeed, the keys are static. In the code of the lib you find stuff like this._storage.setItem('refresh_token', refreshToken) I wonder what happens when you jump from one front-end to another when the two are using different APIs registered with different client-id. All instances of OAuthService will overwrite the same keys from the Storage. To solve this quickly we have to implement a custom OAuthStorage that wrap a sessionStorage and use keys with a pattern like prefix:IDP:client-id (ex: angular-oauth2-oidc:https://myidp.com/auth/realms/abc/:api-public-client-id) Under such key we would store a Json object containing the requested keys ({refresh_token:"xyz",...}) Note that although having only one Storage key per instance may sound elegant it can lead to concurrency issues. One way to deal with it is to use Mutex or use "Web Locks API" (https://developer.mozilla.org/en-US/docs/Web/API/Web_Locks_API). This would involve to change the interface of OAuthStorage with async accessors (IMO, consumers should be aware of the async behavior). A first step could be to prefix all keys that are currently used. Then we may rationalize the use of the keys and reduce them if possible. iFrame identifier Then comes the issue of the iFrame identifier for the silent refresh. Like for the rest of the code it assumes there is a unique instance of the class running in the page. First it destroys (potentially) and create an iFrame with id = this.silentRefreshIFrameName (default is 'angular-oauth-oidc-silent-refresh-iframe'). A new refresh for another API will destroy the existing iFrame created from a concurrent refresh. Luckily this is a public property of the class so it’s possible to calculate a unique value per API definition. postMessage Another problem is how messages are treated when acquiring token (from iFrame or popup). Before creating an iFrame a message listener is added… ok, but what if two iFrames are doing the silent refresh in parallel? As you guess, when first iFrame posts a message it will be captured by all listeners and all will enter the tryLogin() method. One may succeed but all others will fail. The way to solve that is to use the OAUTH state parameter:
The state will be sent back as a query parameter. Great, the class has a state field. It’s then possible to set it to a value that would be recognized by the correct OAuthService instance. Only the emitter instance would treat the received message.
Am I wrong or missing something?
Hi there,
I'm working on an Angular application that requires two different OAuth flows:
Currently, I'm using the angular-oauth2-oidc library for both flows, but I'm encountering issues when trying to manage two different configurations. Here's a brief overview of my setup:
I've tried a few approaches:
Both approaches have led to conflicts and unexpected behavior, particularly with token storage and management.
Questions:
Any guidance or best practices for managing this scenario would be greatly appreciated. Thank you for your time and assistance!