RocketChat / RocketChat/EmbeddedChat
[Bug]: Cross-Instance Authentication Corruption via Hardcoded `ec_token` Key
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 165
- Forks
- 381
- Avg merge
- 1d 2h
- Merged PRs (30d)
- 1
Description
The EmbeddedChat authentication logic hardcodes the localStorage key to ec_token in packages/react/src/lib/auth.js. This prevents multiple instances of EmbeddedChat from co-existing on the same domain with independent sessions.
If two EmbeddedChat instances (for example, a Sales Bot and a Support Bot) are embedded on the same page or domain, logging into one instance overwrites the authentication token of the other.
Reproduction Steps
- Embed two instances of EmbeddedChat on the same page.
- Log in to Instance A.
- Log in to Instance B.
- Refresh the page.
Result: Instance A is logged in as Instance B’s user (or ends up with an invalid token), because the shared ec_token value was overwritten.
Jest Test
const localStorageMock = (function () {
let store = {};
return {
getItem: (key) => store[key] || null,
setItem: (key, value) => {
store[key] = value.toString();
},
removeItem: (key) => {
delete store[key];
},
clear: () => {
store = {};
},
};
})();
Object.defineProperty(global, 'localStorage', {
value: localStorageMock,
});
import { getTokenStorage } from './auth';
describe('Cross-Instance Authentication Corruption', () => {
beforeEach(() => {
localStorage.clear();
jest.clearAllMocks();
});
const getLocalStorageKey = () => 'ec_token';
test('Two seemingly independent instances overwrite each other\'s tokens', async () => {
const auth = getTokenStorage(false);
const { saveToken, getToken } = auth;
// Simulate Instance A login
const instanceAToken = 'token_for_instance_A';
await saveToken(instanceAToken);
expect(localStorage.getItem(getLocalStorageKey())).toBe(instanceAToken);
expect(await getToken()).toBe(instanceAToken);
// Simulate Instance B login
const instanceBToken = 'token_for_instance_B';
await saveToken(instanceBToken);
// Instance A token is overwritten
expect(localStorage.getItem(getLocalStorageKey())).toBe(instanceBToken);
const currentToken = await getToken();
expect(currentToken).not.toBe(instanceAToken);
expect(currentToken).toBe(instanceBToken);
});
});
Expected Behavior
The token storage key should be configurable or automatically namespaced to allow multiple isolated EmbeddedChat instances on the same domain.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in packages/react/src/lib/auth.js, especially getTokenStorage(false), and reproduce the two-instance scenario with the Jest test described in the issue. Trace how saveToken and getToken derive their localStorage key. Done means separate EmbeddedChat instances retain independent tokens, with coverage for saving and retrieving both tokens.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, react
- Domain
- authentication, frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100