Skip to content

fix: namespace auth token storage key to prevent cross-instance sessi… - #1405

Open
swarnendusahu10-dotcom wants to merge 2 commits into
RocketChat:developfrom
swarnendusahu10-dotcom:fix/issue-1105-cross-instance-auth-isolation
Open

swarnendusahu10-dotcom wants to merge 2 commits into
RocketChat:developfrom
swarnendusahu10-dotcom:fix/issue-1105-cross-instance-auth-isolation

Conversation

@swarnendusahu10-dotcom

Copy link
Copy Markdown
Contributor

Summary

Closes #1105

When multiple EmbeddedChat instances (e.g. Sales Bot and Support Bot, or multi-tenant widgets) co-exist on the same domain, logging into one instance previously overwrote the authentication session of the other because the localStorage key was hardcoded to 'ec_token' in packages/react/src/lib/auth.js.

This pull request introduces host-scoped namespaced token storage keys with an opt-in tokenStorageKey prop override and automatic backward-compatible session migration.


Key Changes

  1. Dynamic Namespaced Storage Keys (packages/react/src/lib/auth.js):

    • Refactored getTokenStorage(secure, key) and local storage helpers to accept a configurable storage key.
    • Preserves asynchronous function signatures.
    • Seamless backward compatibility: if a namespaced key is empty, getTokenLocalStorage falls back to and migrates any existing legacy 'ec_token' session so existing users are never logged out upon upgrading.
  2. Host-Scoped Resolution & Memoization (packages/react/src/views/EmbeddedChat.js):

    • Automatically scopes the default storage key to ec_token_${normalizedHost}, ensuring different servers maintain completely independent sessions.
    • Crucially avoids room-based scoping (roomId), ensuring that switching channels within the same chat instance does not log the user out.
    • Adds an optional tokenStorageKey prop with PropTypes coverage for integrators needing custom instance isolation on the same host.
    • Wraps getTokenStorage(secure, storageKey) in useMemo to eliminate unnecessary function recreations and prevent redundant RCInstance re-renders.

Verification

  • Verified cross-instance session isolation: logging into Instance A (https://sales.example.com) does not overwrite Instance B (https://support.example.com).
  • Verified room navigation: switching rooms within the same host preserves authentication.
  • Verified backward compatibility: existing sessions saved under legacy 'ec_token' migrate seamlessly without user intervention.
  • Formatted with Prettier (npx prettier --check).
  • Clean monorepo build with npm run build (dist/cjs and dist/esm generated without errors).

@swarnendusahu10-dotcom

Copy link
Copy Markdown
Contributor Author

Hi @Spiral-Memory , gentle bump on this one. All CI checks are green with 0 merge conflicts against latest develop. Please let me know if this looks good to merge or if there's anything you'd like me to update. Appreciate your guidance! ✨

@Spiral-Memory Spiral-Memory left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Rest LGTM

Comment thread packages/react/src/lib/auth.js Outdated
if (token) {
return token;
}
// Backward compatibility: fallback and migrate legacy 'ec_token' if namespaced key is empty

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We can remove the fallback

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removed the legacy fallback completely. getTokenLocalStorage and deleteTokenLocalStorage now strictly operate on the targeted key.

return tokenStorageKey;
}
if (host) {
const normalizedHost = host.trim().replace(/\/+$/, '');

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can we have a cleaner way of doing this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@Spiral-Memory - Replaced the manual regex string trimming with standard new URL(...).host parsing. It cleanly extracts the hostname/port (e.g., ec_token_localhost:3000, ec_token_open.rocket.chat), strips trailing slashes/paths automatically, and gracefully falls back to 'ec_token'.

@Spiral-Memory

Copy link
Copy Markdown
Collaborator

@Aryan-Verma-999 You can review as well.

@swarnendusahu10-dotcom

Copy link
Copy Markdown
Contributor Author

Hi @Spiral-Memory @Aryan-Verma-999! 👋
Thank you for the review! I've updated the branch with commit 4ff5325 addressing both points:

Removed the legacy ec_token migration fallback in auth.js.
Cleaned up storageKey resolution in EmbeddedChat.js using standard URL host parsing.

All tests and Prettier checks are passing cleanly. Ready for review whenever you have a moment! 😊

This branch has not been deployed

No deployments
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]: Cross-Instance Authentication Corruption via Hardcoded ec_token Key

2 participants