Skip to content

Implement multi organization context management support#374

Open
kavindadimuthu wants to merge 8 commits intoasgardeo:mainfrom
kavindadimuthu:feature/organization-context
Open

Implement multi organization context management support#374
kavindadimuthu wants to merge 8 commits intoasgardeo:mainfrom
kavindadimuthu:feature/organization-context

Conversation

@kavindadimuthu
Copy link
Contributor

Purpose

This pull request introduces multi-organization authentication context support, enabling users to authenticate and exchange tokens across different organization contexts. The main changes include improvements in session and storage management keyed by instance, and new configuration options and React components for organization chaining.

Multi-organization context and token exchange support:

  • Added organizationChain configuration to both BaseConfig and DefaultAuthClientConfig, allowing specification of sourceInstanceId and targetOrganizationId for chained authentication and token exchange between organizations. [1] [2]
  • Updated the exchangeToken and replaceCustomGrantTemplateTags logic to fetch session data from the appropriate organization context, using the organizationChain configuration to determine the correct instance for access tokens. [1] [2] [3] [4]

Session and storage management improvements:

  • Enhanced StorageManager to support resolving keys and retrieving session data based on both userId and instanceId, ensuring correct data isolation between organization contexts. [1] [2]

React SDK enhancements:

  • Added a new OrganizationContext React component to encapsulate organization context configuration and propagate it through the component tree, supporting nested/multi-organization scenarios.
  • Updated AsgardeoReactClient.switchOrganization to utilize the new organizationChain configuration and determine if sign-in is required based on the presence of a sourceInstanceId. [1] [2]

These changes collectively enable seamless authentication flows across multiple organizations, improve isolation of authentication state, and provide a more robust foundation for multi-tenant applications.

Related Issues

  • N/A

Related PRs

  • N/A

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 feature/organization-context branch 2 times, most recently from 492ab15 to 99dda63 Compare February 20, 2026 05:55
@kavindadimuthu kavindadimuthu marked this pull request as ready for review February 20, 2026 08:40
await this._validateMethod();
} else {
await this._validateMethod();
// await this._validateMethod();
Copy link
Member

Choose a reason for hiding this comment

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

Is this expected?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah. Here it checks the signedIn status in both paths unless config.signInRequired is explicitly true or false. So I intentionally removed that check from the else path.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed that else block

@kavindadimuthu kavindadimuthu force-pushed the feature/organization-context branch from b0346fe to 13ab7c6 Compare February 23, 2026 05:11
@kavindadimuthu kavindadimuthu force-pushed the feature/organization-context branch 2 times, most recently from 392669a to 6091a45 Compare February 24, 2026 09:09
…, and worker files

- Changed all occurrences of instanceID to instanceId in message.ts, spa-utils.ts, worker-core.ts, and worker-receiver.ts for uniformity.
- Added instanceId property to the Message interface in message.ts.
/**
* Instance ID of the source organization context to retrieve access token from for organization token exchange.
* Used in linked organization scenarios to automatically fetch the source organization's access token.
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

sourceInstanceId is typed as string | number here but as number in BaseConfig (packages/javascript/src/models/config.ts:140). This type inconsistency could lead to subtle storage key mismatches. Consider unifying to number in both places since instanceId is number everywhere else in the codebase.

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

if (clientId) {
instanceKey = `instance_${sourceInstanceId}-${clientId}`;
} else {
instanceKey = `instance_${sourceInstanceId}`;
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: The storage key format instance_${sourceInstanceId}-${clientId} is manually reconstructed here, duplicating the logic from client.ts:135-137 where StorageManager is initialized. Consider extracting a shared utility for constructing instance storage keys to avoid divergence if the format ever changes. This can be addressed in a follow-up PR.

*/
useEffect(() => {
const performOrganizationSwitch = async (): Promise<void> => {
// Prevent multiple authentication attempts
Copy link
Contributor

Choose a reason for hiding this comment

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

If targetOrganizationId changes after a successful authentication, hasAuthenticatedRef remains true and the effect won't trigger re-authentication for the new org. Consider storing the last successfully authenticated targetOrganizationId in the ref instead of a boolean, and resetting when the org ID changes. This can be added later as an improvement.

sessionData = await this.storageManager.getSessionData(userId, instanceKey);

if (!sessionData.access_token) {
throw new AsgardeoAuthException(
Copy link
Contributor

Choose a reason for hiding this comment

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

getSessionData can return null if no session exists for the given instance key. sessionData.access_token will throw a TypeError in that case, bypassing the helpful AsgardeoAuthException below. Consider adding an explicit null check:

if (\!sessionData || \!sessionData.access_token) {

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

let response: Response;

let response: Response;
try {
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider simplifying by moving the OIDC config check to the top of the method instead of wrapping the entire body in a closure:

if (!await this.storageManager.getTemporaryDataParameter(
    OIDCDiscoveryConstants.Storage.StorageKeys.OPENID_PROVIDER_CONFIG_INITIATED,
)) {
  await this.loadOpenIDProviderConfiguration(false);
}
// ... rest of method as-is, no wrapping needed

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

@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.

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.

4 participants